ReMe/github-pages/scripts/generate-content.mjs

249 lines
7.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
const siteDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const repoDir = path.resolve(siteDir, "..");
const outputDir = path.join(siteDir, ".generated", "content");
const navigationGroupOrder = [
"overview",
"start",
"integration",
"fundamentals",
"automation",
"concepts",
"workspace",
"plugins",
"benchmarks",
"development",
];
const topicOrder = [
"quick_start",
"plugin_management",
"memory_as_file",
"memory_search",
"auto_memory",
"auto_resource",
"auto_link",
"auto_dream",
"proactive",
"reme_scene",
"framework",
"reme-blog",
"contributing",
];
const groups = {
quick_start: "start",
plugin_management: "start",
memory_as_file: "fundamentals",
memory_search: "fundamentals",
auto_memory: "automation",
auto_resource: "automation",
auto_link: "automation",
auto_dream: "automation",
proactive: "automation",
reme_scene: "concepts",
framework: "concepts",
"reme-blog": "concepts",
contributing: "development",
};
const localizedTitles = {
quick_start: { zh: "快速开始", en: "Quick Start" },
plugin_management: { zh: "插件管理", en: "Plugin Management" },
memory_as_file: { zh: "文件即记忆", en: "Memory as File" },
memory_search: { zh: "记忆检索", en: "Memory Search" },
auto_memory: { zh: "自动记忆", en: "Auto Memory" },
auto_resource: { zh: "自动资料整理", en: "Auto Resource" },
auto_link: { zh: "自动关联", en: "Auto Link" },
auto_dream: { zh: "自动沉淀", en: "Auto Dream" },
proactive: { zh: "主动发现", en: "Proactive" },
reme_scene: { zh: "ReMe 应用场景", en: "ReMe Application Scenarios" },
framework: { zh: "ReMe 代码框架", en: "ReMe Framework" },
"reme-blog": { zh: "ReMe 博客", en: "ReMe Blog" },
contributing: { zh: "开源与贡献", en: "Open Source and Contributing" },
};
const productDocuments = [
{
slug: "typescript",
source: "typescript",
titles: { zh: "TypeScript Agent 集成", en: "TypeScript Agent Integrations" },
descriptions: {
zh: "配置统一 HTTP client以及 DeepSeek Harness 和 OpenClaw 原生适配器。",
en: "Configure the shared HTTP client and native DeepSeek Harness and OpenClaw adapters.",
},
group: "integration",
},
{
slug: "studio",
source: "reme_studio",
titles: { zh: "ReMe 工作台", en: "ReMe Studio" },
descriptions: {
zh: "浏览、编辑和搜索本地记忆,并探索记忆图谱。",
en: "Browse, edit, search, and explore local memory from the web workspace.",
},
group: "workspace",
},
{
slug: "daily-paper",
source: "plugins/daily_paper",
titles: { zh: "每日论文插件", en: "Daily Paper Plugin" },
descriptions: {
zh: "发现论文、解析 PDF并生成阅读笔记与每日简报。",
en: "Discover papers, analyze PDFs, and produce reading notes and a daily brief.",
},
group: "plugins",
},
{
slug: "auto-fin",
source: "plugins/auto-fin",
titles: { zh: "Auto Fin 插件", en: "Auto Fin Plugin" },
descriptions: {
zh: "结合最新财联社新闻与本地历史记忆生成研究报告。",
en: "Research recent CLS news with historical context from local memory.",
},
group: "plugins",
},
{
slug: "beam",
source: "benchmark/beam",
titles: { zh: "BEAM", en: "BEAM" },
descriptions: {
zh: "评测大规模记忆检索能力。",
en: "Evaluate memory retrieval at scale.",
},
group: "benchmarks",
},
{
slug: "longmemeval",
source: "benchmark/longmemeval",
titles: { zh: "LongMemEval", en: "LongMemEval" },
descriptions: {
zh: "评测跨会话长期记忆问答能力。",
en: "Evaluate long-term, cross-session memory question answering.",
},
group: "benchmarks",
},
{
slug: "pibench",
source: "benchmark/pibench",
titles: { zh: "π-Bench", en: "π-Bench" },
descriptions: {
zh: "评测带持久记忆的个人智能体。",
en: "Evaluate personal agents with persistent memory.",
},
group: "benchmarks",
},
{
slug: "toolmemory",
source: "benchmark/toolmemory",
titles: { zh: "Tool Memory / ExpG", en: "Tool Memory / ExpG" },
descriptions: {
zh: "通过经验驱动的自适应指导增强 Agent 工具使用。",
en: "Improve agent tool use through experience-driven adaptive guidance.",
},
group: "benchmarks",
},
];
const sharedDocuments = [
{
id: "agents-guide",
path: "AGENTS.md",
sourcePath: "AGENTS.md",
titles: {
zh: "Agent 开发指南",
en: "Agent Development Guide",
},
description: "Repository contracts, lifecycle rules, safety boundaries, and validation.",
group: "development",
language: "shared",
},
];
async function markdownTitle(filePath) {
const source = await readFile(filePath, "utf8");
return source.match(/^#\s+(.+)$/m)?.[1]?.replace(/[`*_]/g, "") || path.basename(filePath, ".md");
}
async function buildManifest() {
const documents = [
{
id: "readme-zh",
path: "README_ZH.md",
sourcePath: "README_ZH.md",
title: "ReMe 项目介绍",
description: "核心理念、快速开始、使用场景与社区入口。",
group: "overview",
language: "zh",
},
{
id: "readme-en",
path: "README.md",
sourcePath: "README.md",
title: "Introducing ReMe",
description: "Core ideas, quick start, use cases, and community resources.",
group: "overview",
language: "en",
},
];
for (const language of ["zh", "en"]) {
for (const topic of topicOrder) {
const sourcePath = `docs/${language}/${topic}.md`;
documents.push({
id: `${language}-${topic}`,
path: sourcePath,
sourcePath,
title: localizedTitles[topic]?.[language] || (await markdownTitle(path.join(repoDir, sourcePath))),
description: "",
group: groups[topic],
language,
});
}
for (const product of productDocuments) {
const filename = language === "zh" ? "README_ZH.md" : "README.md";
documents.push({
id: `${product.slug}-${language}`,
path: `${product.source}/${filename}`,
sourcePath: `${product.source}/${filename}`,
title: product.titles[language],
description: product.descriptions[language],
group: product.group,
language,
});
}
}
return [...documents, ...sharedDocuments].sort(
(left, right) => navigationGroupOrder.indexOf(left.group) - navigationGroupOrder.indexOf(right.group),
);
}
await rm(path.join(siteDir, ".generated"), { recursive: true, force: true });
await mkdir(outputDir, { recursive: true });
await cp(path.join(siteDir, "public", "favicon.svg"), path.join(siteDir, ".generated", "favicon.svg"));
await cp(path.join(siteDir, "public", "CNAME"), path.join(siteDir, ".generated", "CNAME"));
for (const file of ["README.md", "README_ZH.md", "AGENTS.md"]) {
await cp(path.join(repoDir, file), path.join(outputDir, file));
}
await cp(path.join(repoDir, "docs"), path.join(outputDir, "docs"), {
recursive: true,
filter: (source) => path.basename(source) !== ".DS_Store",
});
for (const product of productDocuments) {
await mkdir(path.join(outputDir, product.source), { recursive: true });
for (const filename of ["README.md", "README_ZH.md"]) {
await cp(path.join(repoDir, product.source, filename), path.join(outputDir, product.source, filename));
}
}
await writeFile(
path.join(outputDir, "manifest.json"),
`${JSON.stringify({ documents: await buildManifest() }, null, 2)}\n`,
);