- 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
94 lines
2.3 KiB
TypeScript
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;
|
|
}
|