Files
cortex/src/core/import/markdown.ts
omigamedev 45998c73d0 Add import/export and backup system (Milestone 8)
- Obsidian vault importer with wikilink → edge conversion
- Markdown folder importer with frontmatter parsing
- Markdown exporter with wikilinks and frontmatter
- JSON-LD linked data exporter
- Database backup/restore functionality
- CLI: import, backup, restore-backup, list-backups
- MCP tools: memory_import, memory_backup, memory_export_markdown, memory_export_jsonld
2026-02-03 11:21:42 +01:00

94 lines
2.3 KiB
TypeScript

import * as fs from 'fs';
import * as path from 'path';
import { addNode } from '../store';
import { NodeKind } from '../../types';
export interface MarkdownImportOptions {
kind?: NodeKind;
tags?: string[];
dryRun?: boolean;
}
export interface MarkdownImportResult {
imported: number;
files: string[];
}
export async function importMarkdown(folderPath: string, options: MarkdownImportOptions = {}): Promise<MarkdownImportResult> {
const absPath = path.resolve(folderPath);
if (!fs.existsSync(absPath)) {
throw new Error(`Folder does not exist: ${absPath}`);
}
const files = findMarkdownFiles(absPath);
const defaultKind = options.kind || 'memory';
const defaultTags = options.tags || [];
if (options.dryRun) {
return {
imported: files.length,
files: files.map(f => path.relative(absPath, f)),
};
}
let imported = 0;
const importedFiles: string[] = [];
for (const file of files) {
const content = fs.readFileSync(file, 'utf-8');
const relativePath = path.relative(absPath, file);
const title = path.basename(file, '.md');
// Extract title from first H1 if present
const h1Match = content.match(/^#\s+(.+)$/m);
const nodeTitle = h1Match ? h1Match[1] : title;
// Remove the H1 from content if it was used as title
const nodeContent = h1Match ? content.replace(/^#\s+.+\n*/, '') : content;
await addNode({
kind: defaultKind,
title: nodeTitle,
content: nodeContent.trim(),
tags: ['imported', 'markdown', ...defaultTags],
metadata: {
importedFrom: 'markdown',
originalPath: relativePath,
importedAt: Date.now(),
},
});
imported++;
importedFiles.push(relativePath);
}
return {
imported,
files: importedFiles,
};
}
function findMarkdownFiles(dir: string): string[] {
const files: string[] = [];
function walk(currentDir: string) {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
if (entry.name.startsWith('.')) continue;
if (entry.isDirectory()) {
walk(fullPath);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
files.push(fullPath);
}
}
}
walk(dir);
return files;
}