[taskboard] migrate fleet console to nextjs
This commit is contained in:
130
lib/wiki.ts
Normal file
130
lib/wiki.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import type { WikiPage, WikiPageSummary } from "@/lib/types";
|
||||
|
||||
const WIKI_DIR = process.env.WIKI_DIR || path.join(process.cwd(), "wiki");
|
||||
|
||||
fs.mkdirSync(WIKI_DIR, { recursive: true });
|
||||
|
||||
function assertSafeFilename(filename: string) {
|
||||
if (filename.includes("..") || filename.includes("/") || filename.includes("\\")) {
|
||||
throw new Error("invalid_filename");
|
||||
}
|
||||
}
|
||||
|
||||
function extractMetadata(content: string) {
|
||||
const metadata = {
|
||||
title: "",
|
||||
created: "",
|
||||
modified: "",
|
||||
tags: [] as string[],
|
||||
};
|
||||
|
||||
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
||||
if (frontmatterMatch) {
|
||||
const frontmatter = frontmatterMatch[1];
|
||||
const titleMatch = frontmatter.match(/title:\s*(.+)/i);
|
||||
const tagsMatch = frontmatter.match(/tags:\s*\[(.+)\]/i);
|
||||
if (titleMatch) {
|
||||
metadata.title = titleMatch[1].trim();
|
||||
}
|
||||
if (tagsMatch) {
|
||||
metadata.tags = tagsMatch[1].split(",").map((tag) => tag.trim()).filter(Boolean);
|
||||
}
|
||||
}
|
||||
|
||||
if (!metadata.title) {
|
||||
const headingMatch = content.match(/^#\s+(.+)$/m);
|
||||
if (headingMatch) {
|
||||
metadata.title = headingMatch[1].trim();
|
||||
}
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
export function listWikiPages(): WikiPageSummary[] {
|
||||
if (!fs.existsSync(WIKI_DIR)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return fs
|
||||
.readdirSync(WIKI_DIR)
|
||||
.filter((fileName) => fileName.endsWith(".md"))
|
||||
.map((filename) => {
|
||||
const filePath = path.join(WIKI_DIR, filename);
|
||||
const stats = fs.statSync(filePath);
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
const metadata = extractMetadata(content);
|
||||
return {
|
||||
filename,
|
||||
title: metadata.title || filename.replace(".md", "").replace(/-/g, " "),
|
||||
created: stats.birthtime.toISOString(),
|
||||
modified: stats.mtime.toISOString(),
|
||||
tags: metadata.tags,
|
||||
};
|
||||
})
|
||||
.sort((left, right) => new Date(right.modified).getTime() - new Date(left.modified).getTime());
|
||||
}
|
||||
|
||||
export function readWikiPage(filename: string): WikiPage | null {
|
||||
assertSafeFilename(filename);
|
||||
const filePath = path.join(WIKI_DIR, filename);
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
const stats = fs.statSync(filePath);
|
||||
const metadata = extractMetadata(content);
|
||||
|
||||
return {
|
||||
filename,
|
||||
content,
|
||||
metadata: {
|
||||
title: metadata.title || filename.replace(".md", ""),
|
||||
created: stats.birthtime.toISOString(),
|
||||
modified: stats.mtime.toISOString(),
|
||||
tags: metadata.tags,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createWikiPage(title: string) {
|
||||
const safeTitle = title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.slice(0, 80);
|
||||
|
||||
const timestamp = new Date().toISOString().slice(0, 10);
|
||||
let filename = `${timestamp}-${safeTitle}.md`;
|
||||
let counter = 1;
|
||||
|
||||
while (fs.existsSync(path.join(WIKI_DIR, filename))) {
|
||||
filename = `${timestamp}-${safeTitle}-${counter}.md`;
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
const content = `# ${title}
|
||||
|
||||
## Summary
|
||||
|
||||
Document the architecture, deployment notes, or runbook here.
|
||||
`;
|
||||
|
||||
fs.writeFileSync(path.join(WIKI_DIR, filename), content, "utf8");
|
||||
return filename;
|
||||
}
|
||||
|
||||
export function updateWikiPage(filename: string, content: string) {
|
||||
assertSafeFilename(filename);
|
||||
fs.writeFileSync(path.join(WIKI_DIR, filename), content, "utf8");
|
||||
}
|
||||
|
||||
export function deleteWikiPage(filename: string) {
|
||||
assertSafeFilename(filename);
|
||||
fs.unlinkSync(path.join(WIKI_DIR, filename));
|
||||
}
|
||||
Reference in New Issue
Block a user