@shirokuma-library/mcp-knowledge-base
Version:
Shirokuma MCP Server for comprehensive knowledge management including issues, plans, documents, and work sessions. All stored data is structured for AI processing, not human readability.
144 lines (143 loc) • 6.72 kB
JavaScript
export class SessionMarkdownFormatter {
generateSessionMarkdown(session) {
let content = '---\n';
content += `id: ${session.id}\n`;
content += `title: "${session.title}"\n`;
if (session.description) {
content += `description: "${session.description}"\n`;
}
if (session.tags && session.tags.length > 0) {
content += `tags: [${session.tags.map(tag => `"${tag}"`).join(', ')}]\n`;
}
if (session.related_tasks && session.related_tasks.length > 0) {
content += `related_tasks: [${session.related_tasks.map(t => `"${t}"`).join(', ')}]\n`;
}
if (session.related_documents && session.related_documents.length > 0) {
content += `related_documents: [${session.related_documents.map(d => `"${d}"`).join(', ')}]\n`;
}
content += `date: ${session.date}\n`;
content += `createdAt: ${session.createdAt}\n`;
if (session.updatedAt) {
content += `updatedAt: ${session.updatedAt}\n`;
}
content += '---\n\n';
if (session.content) {
content += session.content;
}
return content;
}
generateLegacySessionMarkdown(session) {
let markdown = `# ${session.title}\n\n`;
markdown += `**Created**: ${session.createdAt}\n`;
if (session.updatedAt) {
markdown += `**Updated**: ${session.updatedAt}\n`;
}
markdown += '\n';
if (session.content) {
markdown += `\n${session.content}\n`;
}
return markdown;
}
parseSessionFromMarkdown(content, sessionId, date) {
const frontMatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (frontMatterMatch) {
return this.parseFrontMatterSession(frontMatterMatch, sessionId, date);
}
else {
return this.parseLegacySession(content, sessionId, date);
}
}
parseFrontMatterSession(match, sessionId, date) {
const frontMatter = match[1];
const bodyContent = match[2];
const titleMatch = frontMatter.match(/title: "(.+)"/);
const descriptionMatch = frontMatter.match(/description: "(.+)"/);
const tagsMatch = frontMatter.match(/tags: \[(.*)\]/);
const relatedTasksMatch = frontMatter.match(/related_tasks: \[(.*)\]/);
const relatedDocsMatch = frontMatter.match(/related_documents: \[(.*)\]/);
const createdAtMatch = frontMatter.match(/createdAt: (.+)/);
const updatedAtMatch = frontMatter.match(/updatedAt: (.+)/);
const content = bodyContent.trim() || undefined;
return {
id: sessionId,
title: titleMatch?.[1] || 'Unknown Session',
description: descriptionMatch?.[1],
content,
tags: tagsMatch?.[1] ? tagsMatch[1].split(', ').map(tag => tag.replace(/"/g, '')) : undefined,
related_tasks: relatedTasksMatch?.[1] ? relatedTasksMatch[1].split(', ').map(t => t.replace(/"/g, '')) : undefined,
related_documents: relatedDocsMatch?.[1] ? relatedDocsMatch[1].split(', ').map(d => d.replace(/"/g, '')) : undefined,
date,
createdAt: createdAtMatch?.[1] || '',
updatedAt: updatedAtMatch?.[1]
};
}
parseLegacySession(content, sessionId, date) {
const lines = content.split('\n');
const titleMatch = lines[0].match(/^# (.+)$/);
const title = titleMatch ? titleMatch[1] : 'Unknown Session';
const createdAtMatch = content.match(/\*\*Created\*\*: (.+)/);
const updatedAtMatch = content.match(/\*\*Updated\*\*: (.+)/);
const contentStart = content.indexOf('\n\n', content.indexOf('\n\n') + 2);
const bodyContent = contentStart !== -1 ? content.substring(contentStart).trim() : '';
return {
id: sessionId,
title,
date,
createdAt: createdAtMatch?.[1] || '',
updatedAt: updatedAtMatch?.[1],
content: bodyContent || undefined
};
}
generateDailyMarkdown(summary) {
let content = '---\n';
content += `date: ${summary.date}\n`;
content += `title: "${summary.title}"\n`;
if (summary.description) {
content += `description: "${summary.description}"\n`;
}
if (summary.tags.length > 0) {
content += `tags: [${summary.tags.map(tag => `"${tag}"`).join(', ')}]\n`;
}
if (summary.related_tasks && summary.related_tasks.length > 0) {
content += `related_tasks: [${summary.related_tasks.map(t => `"${t}"`).join(', ')}]\n`;
}
if (summary.related_documents && summary.related_documents.length > 0) {
content += `related_documents: [${summary.related_documents.map(d => `"${d}"`).join(', ')}]\n`;
}
content += `createdAt: ${summary.createdAt}\n`;
if (summary.updatedAt) {
content += `updatedAt: ${summary.updatedAt}\n`;
}
content += '---\n\n';
content += `# ${summary.title}\n\n`;
content += summary.content;
return content;
}
parseDailyFromMarkdown(content, date) {
const frontMatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (!frontMatterMatch) {
return null;
}
const frontMatter = frontMatterMatch[1];
const bodyContent = frontMatterMatch[2];
const dateMatch = frontMatter.match(/date: (.+)/);
const titleMatch = frontMatter.match(/title: "(.+)"/);
const descriptionMatch = frontMatter.match(/description: "(.+)"/);
const tagsMatch = frontMatter.match(/tags: \[(.*)\]/);
const relatedTasksMatch = frontMatter.match(/related_tasks: \[(.*)\]/);
const relatedDocsMatch = frontMatter.match(/related_documents: \[(.*)\]/);
const createdAtMatch = frontMatter.match(/createdAt: (.+)/);
const updatedAtMatch = frontMatter.match(/updatedAt: (.+)/);
return {
date: dateMatch?.[1] || date,
title: titleMatch?.[1] || 'Untitled',
description: descriptionMatch?.[1],
content: bodyContent.replace(/^# .+\n\n/, '').trim(),
tags: tagsMatch?.[1] ? tagsMatch[1].split(', ').map(tag => tag.replace(/"/g, '')) : [],
related_tasks: relatedTasksMatch?.[1] ? relatedTasksMatch[1].split(', ').map(t => t.replace(/"/g, '')) : [],
related_documents: relatedDocsMatch?.[1] ? relatedDocsMatch[1].split(', ').map(d => d.replace(/"/g, '')) : [],
createdAt: createdAtMatch?.[1] || '',
updatedAt: updatedAtMatch?.[1]
};
}
}