Skip to content

Commit 529ed2f

Browse files
authored
Enhance Markdown export functionality in MarkdownSerializer (#50)
* Enhance Markdown export functionality in MarkdownSerializer - Introduced MarkdownExportOptions interface to allow custom export names and descriptions. - Updated toMarkdown method to accept options for name and description, defaulting to 'MindCache Export'. - Modified exported Markdown structure to conditionally display entry attributes (type, system tags, z-index) based on their values. - Updated tests to validate new export format and ensure default values are omitted when not applicable. - Adjusted import functionality to recognize new Markdown format with 'Keys & Values' section. This change improves the flexibility and clarity of Markdown exports, aligning with user needs for customized documentation. * Update package version to 3.8.0 in package.json and MindCache.ts - Incremented the package version in package.json to 3.8.0 to reflect the latest changes. - Updated the version property in MindCache.ts to match the new package version, ensuring consistency across the codebase.
1 parent a1adaef commit 529ed2f

4 files changed

Lines changed: 104 additions & 18 deletions

File tree

packages/mindcache/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mindcache",
3-
"version": "3.7.0",
3+
"version": "3.8.0",
44
"description": "A TypeScript library for managing short-term memory in AI agents through an LLM-friendly key-value repository",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",

packages/mindcache/src/core/MarkdownSerializer.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,24 @@ export interface IMarkdownSerializable {
1414
clear(): void;
1515
}
1616

17+
/**
18+
* Options for markdown export
19+
*/
20+
export interface MarkdownExportOptions {
21+
/** Name/title for the export (defaults to 'MindCache Export') */
22+
name?: string;
23+
/** Description to include below the title */
24+
description?: string;
25+
}
26+
1727
/**
1828
* Serializes and deserializes MindCache data to/from Markdown format.
1929
*/
2030
export class MarkdownSerializer {
2131
/**
2232
* Export MindCache data to Markdown format.
2333
*/
24-
static toMarkdown(mc: IMarkdownSerializable): string {
34+
static toMarkdown(mc: IMarkdownSerializable, options?: MarkdownExportOptions): string {
2535
const now = new Date();
2636
const lines: string[] = [];
2737
const appendixEntries: Array<{
@@ -33,13 +43,18 @@ export class MarkdownSerializer {
3343
}> = [];
3444
let appendixCounter = 0;
3545

36-
lines.push('# MindCache STM Export');
46+
const name = options?.name || 'MindCache Export';
47+
lines.push(`# ${name}`);
3748
lines.push('');
49+
if (options?.description) {
50+
lines.push(options.description);
51+
lines.push('');
52+
}
3853
lines.push(`Export Date: ${now.toISOString().split('T')[0]}`);
3954
lines.push('');
4055
lines.push('---');
4156
lines.push('');
42-
lines.push('## STM Entries');
57+
lines.push('## Keys & Values');
4358
lines.push('');
4459

4560
const sortedKeys = mc.getSortedKeys();
@@ -49,9 +64,20 @@ export class MarkdownSerializer {
4964

5065
lines.push(`### ${key}`);
5166
const entryType = attributes?.type || 'text';
52-
lines.push(`- **Type**: \`${entryType}\``);
53-
lines.push(`- **System Tags**: \`${attributes?.systemTags?.join(', ') || 'none'}\``);
54-
lines.push(`- **Z-Index**: \`${attributes?.zIndex ?? 0}\``);
67+
// Only show type if not 'text' (the default)
68+
if (entryType !== 'text') {
69+
lines.push(`- **Type**: \`${entryType}\``);
70+
}
71+
// Only show system tags if there are any
72+
const systemTags = attributes?.systemTags;
73+
if (systemTags && systemTags.length > 0) {
74+
lines.push(`- **System Tags**: \`${systemTags.join(', ')}\``);
75+
}
76+
// Only show z-index if non-zero
77+
const zIndex = attributes?.zIndex ?? 0;
78+
if (zIndex !== 0) {
79+
lines.push(`- **Z-Index**: \`${zIndex}\``);
80+
}
5581

5682
if (attributes?.contentTags && attributes.contentTags.length > 0) {
5783
lines.push(`- **Tags**: \`${attributes.contentTags.join('`, `')}\``);
@@ -278,7 +304,10 @@ export class MarkdownSerializer {
278304

279305
// Check if we parsed any keys
280306
const hasParsedKeys = lines.some(line => line.startsWith('### ') && !line.startsWith('### Appendix'));
281-
const isSTMExport = markdown.includes('# MindCache STM Export') || markdown.includes('## STM Entries');
307+
const isSTMExport = markdown.includes('# MindCache STM Export') ||
308+
markdown.includes('## STM Entries') ||
309+
markdown.includes('## Keys & Values') ||
310+
markdown.includes('# MindCache Export');
282311

283312
if (!hasParsedKeys && !isSTMExport && markdown.trim().length > 0) {
284313
mc.set_value('imported_content', markdown.trim(), {
@@ -416,7 +445,10 @@ export class MarkdownSerializer {
416445

417446
// Handle unstructured content
418447
const hasParsedKeys = lines.some(line => line.startsWith('### ') && !line.startsWith('### Appendix'));
419-
const isSTMExport = markdown.includes('# MindCache STM Export') || markdown.includes('## STM Entries');
448+
const isSTMExport = markdown.includes('# MindCache STM Export') ||
449+
markdown.includes('## STM Entries') ||
450+
markdown.includes('## Keys & Values') ||
451+
markdown.includes('# MindCache Export');
420452

421453
if (!hasParsedKeys && !isSTMExport && markdown.trim().length > 0) {
422454
result['imported_content'] = {

packages/mindcache/src/core/MindCache.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export class MindCache {
112112
private globalListeners: GlobalListener[] = [];
113113

114114
// Metadata
115-
public readonly version = '3.6.0';
115+
public readonly version = '3.8.0';
116116

117117
// Internal flag to prevent sync loops when receiving remote updates
118118
// (Less critical with Yjs but kept for API compat)
@@ -1495,9 +1495,10 @@ export class MindCache {
14951495

14961496
/**
14971497
* Export to Markdown format.
1498+
* @param options Optional name and description for the export
14981499
*/
1499-
toMarkdown(): string {
1500-
return MarkdownSerializer.toMarkdown(this);
1500+
toMarkdown(options?: { name?: string; description?: string }): string {
1501+
return MarkdownSerializer.toMarkdown(this, options);
15011502
}
15021503

15031504
/**

packages/mindcache/src/core/mindcache.markdown.test.ts

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,49 @@ describe('MindCache Markdown Serialization', () => {
1212
test('should export empty STM to markdown', () => {
1313
const markdown = cache.toMarkdown();
1414

15-
expect(markdown).toContain('# MindCache STM Export');
16-
expect(markdown).toContain('## STM Entries');
15+
expect(markdown).toContain('# MindCache Export');
16+
expect(markdown).toContain('## Keys & Values');
1717
// No entries when empty
1818
});
1919

20-
test('should export text values to markdown', () => {
20+
test('should export with custom name and description', () => {
21+
cache.set_value('test', 'value');
22+
const markdown = cache.toMarkdown({
23+
name: 'My Project',
24+
description: 'This is my project description.'
25+
});
26+
27+
expect(markdown).toContain('# My Project');
28+
expect(markdown).toContain('This is my project description.');
29+
expect(markdown).toContain('## Keys & Values');
30+
});
31+
32+
test('should export text values to markdown without type line (default)', () => {
2133
cache.set_value('username', 'john_doe');
2234
cache.set_value('email', 'john@example.com');
2335

2436
const markdown = cache.toMarkdown();
2537

2638
expect(markdown).toContain('### username');
27-
expect(markdown).toContain('- **Type**: `text`');
39+
// Type 'text' should NOT be shown (it's the default)
40+
expect(markdown).not.toContain('- **Type**: `text`');
2841
expect(markdown).toContain('```\njohn_doe\n```');
2942
expect(markdown).toContain('### email');
3043
expect(markdown).toContain('```\njohn@example.com\n```');
3144
});
3245

46+
test('should skip default values (z-index 0, no system tags)', () => {
47+
cache.set_value('simple', 'value');
48+
49+
const markdown = cache.toMarkdown();
50+
51+
expect(markdown).toContain('### simple');
52+
// These defaults should NOT appear
53+
expect(markdown).not.toContain('- **Type**: `text`');
54+
expect(markdown).not.toContain('- **System Tags**: `none`');
55+
expect(markdown).not.toContain('- **Z-Index**: `0`');
56+
});
57+
3358
test('should export multiline text with code blocks', () => {
3459
cache.set_value('description', 'Line 1\nLine 2\nLine 3');
3560

@@ -53,16 +78,18 @@ describe('MindCache Markdown Serialization', () => {
5378
expect(markdown).toContain('"dark"');
5479
});
5580

56-
test('should export all attributes', () => {
81+
test('should export non-default attributes', () => {
5782
cache.set_value('test_key', 'value', {
5883
systemTags: ['ApplyTemplate'],
59-
contentTags: ['tag1', 'tag2', 'tag3']
84+
contentTags: ['tag1', 'tag2', 'tag3'],
85+
zIndex: 5
6086
});
6187

6288
const markdown = cache.toMarkdown();
6389

6490
expect(markdown).toContain('- **System Tags**: `ApplyTemplate`');
6591
expect(markdown).toContain('- **Tags**: `tag1`, `tag2`, `tag3`');
92+
expect(markdown).toContain('- **Z-Index**: `5`');
6693
});
6794

6895
test('should export image to appendix', () => {
@@ -150,6 +177,32 @@ Export Date: 2025-10-01
150177
expect(cache.size()).toBe(0);
151178
});
152179

180+
test('should import new format (Keys & Values)', () => {
181+
const markdown = `# My Project
182+
183+
This is my project.
184+
185+
Export Date: 2025-10-01
186+
187+
---
188+
189+
## Keys & Values
190+
191+
### username
192+
- **Value**:
193+
\`\`\`
194+
john_doe
195+
\`\`\`
196+
197+
`;
198+
199+
cache.fromMarkdown(markdown);
200+
201+
expect(cache.get_value('username')).toBe('john_doe');
202+
// Should default to type 'text'
203+
expect(cache.get_attributes('username')?.type).toBe('text');
204+
});
205+
153206
test('should import text values', () => {
154207
const markdown = `# MindCache STM Export
155208

0 commit comments

Comments
 (0)