diff --git a/.github/workflows/_build-docs.yml b/.github/workflows/_build-docs.yml index 8bc9691d..338c0ec6 100644 --- a/.github/workflows/_build-docs.yml +++ b/.github/workflows/_build-docs.yml @@ -28,6 +28,7 @@ jobs: steps: - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: + fetch-depth: 0 persist-credentials: false - name: Set up Node diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index d506b005..88f7eb59 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -11,11 +11,15 @@ on: - 'README_ZH.md' - 'docs/**' - 'github-pages/**' + - 'reme/config/default.yaml' + - 'integrations/claude_code/README.md' + - 'integrations/hermes_agent/README.md' - 'reme_studio/README*.md' - 'reme_studio/public/og.jpg' - 'typescript/README*.md' - 'plugins/*/README*.md' - 'benchmark/*/README*.md' + - 'benchmark/toolmemory/gitcha.png' pull_request: branches: [main, master, dev, develop] paths: @@ -26,11 +30,15 @@ on: - 'README_ZH.md' - 'docs/**' - 'github-pages/**' + - 'reme/config/default.yaml' + - 'integrations/claude_code/README.md' + - 'integrations/hermes_agent/README.md' - 'reme_studio/README*.md' - 'reme_studio/public/og.jpg' - 'typescript/README*.md' - 'plugins/*/README*.md' - 'benchmark/*/README*.md' + - 'benchmark/toolmemory/gitcha.png' workflow_dispatch: concurrency: diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index fe81de3d..488f086d 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -6,6 +6,9 @@ on: paths: - "github-pages/**" - "docs/**" + - "reme/config/default.yaml" + - "integrations/claude_code/README.md" + - "integrations/hermes_agent/README.md" - "README.md" - "README_ZH.md" - "reme_studio/README*.md" @@ -13,6 +16,7 @@ on: - "typescript/README*.md" - "plugins/*/README*.md" - "benchmark/*/README*.md" + - "benchmark/toolmemory/gitcha.png" - "AGENTS.md" - ".github/workflows/deploy-docs.yml" - ".github/workflows/_build-docs.yml" diff --git a/AGENTS.md b/AGENTS.md index 7718891a..ba8ae6ac 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,6 +62,8 @@ and concise documentation together. conventions. - `benchmark/` and `cookbook/`: runnable evaluations and example workflows. - `docs/`: README-linked supporting pages and figures. +- `github-pages/`: VitePress build shell, generated-content assembly, documentation checks, and GitHub Pages output. The + canonical theme and guides remain under `docs/`; `.generated/` and `dist/` are disposable. ## Development Setup @@ -195,6 +197,9 @@ Integration tests may contact real model providers, services, or agent subproces run credentialed or externally mutating tests automatically; run them only when the task requires them and the necessary environment has been supplied or authorized. Mock network, model, and subprocess boundaries in unit tests. +If documentation or the documentation theme changes, run `npm test` and `npm run build` from `github-pages/`. The Job +reference is generated from `reme/config/default.yaml`; do not edit generated pages directly. + ## Change Guardrails - Preserve unrelated user changes in a dirty working tree. diff --git a/README.md b/README.md index dc0c18ce..bf855dae 100644 --- a/README.md +++ b/README.md @@ -51,12 +51,12 @@ users retain control of the durable files. - [2026.08] - Published [`@agentscope-ai/reme`](https://www.npmjs.com/package/@agentscope-ai/reme), providing native ReMe memory integrations for DeepSeek Harness and OpenClaw plus a shared TypeScript HTTP client. -- [2026.08] - Published the [ReMe blog](https://agentscope-ai.github.io/ReMe/?doc=en-reme-blog), an end-to-end introduction to its local-first memory +- [2026.08] - Published the [ReMe blog](https://reme.agentscope.io/en/reme-blog), an end-to-end introduction to its local-first memory architecture, self-evolving workflows, hybrid search, proactive discovery, and benchmark results. -- [2026.08] - [Experience-driven enhancement method](https://reme.agentscope.io/?doc=toolmemory-en) of agent tool-use execution built +- [2026.08] - [Experience-driven enhancement method](https://reme.agentscope.io/en/benchmarks/toolmemory) of agent tool-use execution built on ReMe is available on [arXiv:2608.03403](https://arxiv.org/abs/2608.03403). -- [2026.07] - Introduced optional plugins: [Daily Paper](https://reme.agentscope.io/?doc=daily-paper-en) for paper discovery and - analysis, and [Auto Fin](https://reme.agentscope.io/?doc=auto-fin-en) for researching the latest 24 hours of topic-related CLS news +- [2026.07] - Introduced optional plugins: [Daily Paper](https://reme.agentscope.io/en/plugins/daily-paper) for paper discovery and + analysis, and [Auto Fin](https://reme.agentscope.io/en/plugins/auto-fin) for researching the latest 24 hours of topic-related CLS news with local-memory search and validated historical wikilinks. - [2026.07] - Our paper [Remember Me, Refine Me: A Dynamic Procedural Memory Framework for Experience-Driven Agent Evolution](https://aclanthology.org/2026.findings-acl.829/) @@ -171,7 +171,7 @@ Related: [[digest/wiki/memory-as-file.md]] The `core` installation includes Studio. After starting ReMe, open to browse, edit, and search the workspace. To add Studio to a base installation, use `pip install "reme-ai[web]"`. See the -[ReMe Studio guide](https://reme.agentscope.io/?doc=studio-en) for source builds, configuration, and development. +[ReMe Studio guide](https://reme.agentscope.io/en/workspace/studio) for source builds, configuration, and development. ## 🤝 Use ReMe with Your Agent @@ -308,12 +308,12 @@ benchmark. | Benchmark | Setting | Sample size | Agentic score | Focus | | --------------------------------------------------------------------------- | ------------ | -----------------------: | ------------: | ------------------------------------------------------------------ | -| **[LongMemEval cleaned-s](https://reme.agentscope.io/?doc=longmemeval-en)** | **Overall** | **500 questions** | **89.4%** | Cross-session retrieval, knowledge updates, and temporal reasoning | -| [BEAM](https://reme.agentscope.io/?doc=beam-en) | 100K context | 20 cases / 400 questions | 66.1% | Ten types of long-context memory tasks | -| [BEAM](https://reme.agentscope.io/?doc=beam-en) | 1M context | 35 cases / 700 questions | 65.0% | Ultra-long conversation settings | +| **[LongMemEval cleaned-s](https://reme.agentscope.io/en/benchmarks/longmemeval)** | **Overall** | **500 questions** | **89.4%** | Cross-session retrieval, knowledge updates, and temporal reasoning | +| [BEAM](https://reme.agentscope.io/en/benchmarks/beam) | 100K context | 20 cases / 400 questions | 66.1% | Ten types of long-context memory tasks | +| [BEAM](https://reme.agentscope.io/en/benchmarks/beam) | 1M context | 35 cases / 700 questions | 65.0% | Ultra-long conversation settings | ReMe also achieved a **0.580 PROC score across five user personas** in the repository's -[π-Bench evaluation](https://reme.agentscope.io/?doc=pibench-en), 2.4% above NanoBot under the same test-model configuration. PROC +[π-Bench evaluation](https://reme.agentscope.io/en/benchmarks/pibench), 2.4% above NanoBot under the same test-model configuration. PROC measures proactive handling of hidden intent, clarification, cross-session preferences and conventions, task dependencies, and underspecified requests. @@ -326,8 +326,8 @@ plugins; see the source distributions and their documentation for [Daily Paper]( | Plugin | Capability | | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| [Daily Paper](https://reme.agentscope.io/?doc=daily-paper-en) | Discover and rank papers, analyze PDFs with an agent, and generate file-native notes and a five-minute brief. | -| [Auto Fin](https://reme.agentscope.io/?doc=auto-fin-en) | Fetch topic-related CLS news, search ReMe history, and generate wikilink-backed Markdown reports. | +| [Daily Paper](https://reme.agentscope.io/en/plugins/daily-paper) | Discover and rank papers, analyze PDFs with an agent, and generate file-native notes and a five-minute brief. | +| [Auto Fin](https://reme.agentscope.io/en/plugins/auto-fin) | Fetch topic-related CLS news, search ReMe history, and generate wikilink-backed Markdown reports. | See [Plugin Management](docs/en/plugin_management.md) to install, inspect, validate, enable, and uninstall ReMe plugins. @@ -338,6 +338,8 @@ These guides cover the main user workflows and the runtime contracts implemented | Guide | What you will learn | | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [Quick Start](docs/en/quick_start.md) | Install ReMe, start the service, and run the first file and memory operations. | +| [Configuration](docs/en/configuration.md) | Configure the workspace, models, Service, Jobs, Components, plugins, and CLI overrides. | +| [Services and Deployment](docs/en/services.md) | Use HTTP, SSE, MCP, and Studio while respecting the default security boundary. | | [Memory as File](docs/en/memory_as_file.md) | Understand workspace layers, frontmatter, wikilinks, chunks, and the file-as-source-of-truth model. | | [Auto Memory](docs/en/auto_memory.md) | Preserve source conversations and distill reusable daily memory cards. | | [Auto Resource](docs/en/auto_resource.md) | Import supported text resources and turn them into source-linked daily cards. | @@ -347,7 +349,9 @@ These guides cover the main user workflows and the runtime contracts implemented | [Application Scenarios](docs/en/reme_scene.md) | Follow concrete financial research, coding-memory, and personal knowledge-base examples. | | [Framework](docs/en/framework.md) | Understand Application, Job, Step, Component, service, configuration, and lifecycle boundaries. | | [TypeScript integrations](typescript/README.md) | Configure the shared client and native DeepSeek Harness and OpenClaw adapters. | -| [ReMe Blog](https://agentscope-ai.github.io/ReMe/?doc=en-reme-blog) | Read the product story, design rationale, examples, and benchmark summary. | +| [CLI and Job API](docs/en/reference/cli.md) | Learn command syntax and use the generated default Job parameter reference. | +| [Operations and Recovery](docs/en/operations.md) | Diagnose services, maintain indexes, and back up, migrate, or recover a workspace. | +| [ReMe Blog](https://reme.agentscope.io/en/reme-blog) | Read the product story, design rationale, examples, and benchmark summary. | ## 🛠️ Common Commands diff --git a/README_ZH.md b/README_ZH.md index 7583e4f7..059d6ff6 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -49,13 +49,13 @@ - [2026.08] - 发布 [`@agentscope-ai/reme`](https://www.npmjs.com/package/@agentscope-ai/reme),提供统一 TypeScript HTTP client,以及 DeepSeek Harness 和 OpenClaw 的原生 ReMe 记忆集成。 -- [2026.08] - 发布 [ReMe 博客](https://agentscope-ai.github.io/ReMe/?doc=zh-reme-blog),系统介绍本地优先的记忆架构、自进化工作流、混合检索、 +- [2026.08] - 发布 [ReMe 博客](https://reme.agentscope.io/zh/reme-blog),系统介绍本地优先的记忆架构、自进化工作流、混合检索、 主动发现与评测结果。 - [2026.08] - 基于 ReMe 的智能体工具使用 - [经验驱动增强方法](https://reme.agentscope.io/?doc=toolmemory-zh)已发布,见 + [经验驱动增强方法](https://reme.agentscope.io/zh/benchmarks/toolmemory)已发布,见 [arXiv:2608.03403](https://arxiv.org/abs/2608.03403)。 -- [2026.07] - 新增可选插件:[每日论文](https://reme.agentscope.io/?doc=daily-paper-zh)用于论文发现与解析, - [Auto Fin](https://reme.agentscope.io/?doc=auto-fin-zh)用于研究最近 24 小时的主题相关财联社新闻,通过本地记忆搜索回顾历史材料并构建 +- [2026.07] - 新增可选插件:[每日论文](https://reme.agentscope.io/zh/plugins/daily-paper)用于论文发现与解析, + [Auto Fin](https://reme.agentscope.io/zh/plugins/auto-fin)用于研究最近 24 小时的主题相关财联社新闻,通过本地记忆搜索回顾历史材料并构建 wikilink。 - [2026.07] - 我们的论文 [Remember Me, Refine Me: A Dynamic Procedural Memory Framework for Experience-Driven Agent Evolution](https://aclanthology.org/2026.findings-acl.829/) @@ -170,7 +170,7 @@ ReMe 会把 Agent 记忆保存为可读的 Markdown。 上面的 `core` 安装已包含 Studio。启动 ReMe 后,打开 即可浏览、编辑和搜索 workspace。 如需为基础安装单独添加 Studio,可使用 `pip install "reme-ai[web]"`。源码构建、配置和开发说明见 -[ReMe Studio 指南](https://reme.agentscope.io/?doc=studio-zh)。 +[ReMe Studio 指南](https://reme.agentscope.io/zh/workspace/studio)。 ## 🤝 将 ReMe 接入你的 Agent @@ -301,11 +301,11 @@ ReMe 通过 Agent 多轮搜索与读取的方式,评测多会话和超长上 | 基准 | 设置 | 样本量 | Agentic 得分 | 主要检验内容 | | --------------------------------------------------------------------------- | ----------- | ----------------: | -----------: | ------------------------------ | -| **[LongMemEval cleaned-s](https://reme.agentscope.io/?doc=longmemeval-zh)** | **整体** | **500 题** | **89.4%** | 跨会话检索、知识更新与时间推理 | -| [BEAM](https://reme.agentscope.io/?doc=beam-zh) | 100K 上下文 | 20 cases / 400 题 | 66.1% | 十类长上下文记忆任务 | -| [BEAM](https://reme.agentscope.io/?doc=beam-zh) | 1M 上下文 | 35 cases / 700 题 | 65.0% | 超长对话设置 | +| **[LongMemEval cleaned-s](https://reme.agentscope.io/zh/benchmarks/longmemeval)** | **整体** | **500 题** | **89.4%** | 跨会话检索、知识更新与时间推理 | +| [BEAM](https://reme.agentscope.io/zh/benchmarks/beam) | 100K 上下文 | 20 cases / 400 题 | 66.1% | 十类长上下文记忆任务 | +| [BEAM](https://reme.agentscope.io/zh/benchmarks/beam) | 1M 上下文 | 35 cases / 700 题 | 65.0% | 超长对话设置 | -在仓库的 [π-Bench 评测](https://reme.agentscope.io/?doc=pibench-zh)中,ReMe Agent 在 5 种用户角色上的平均 **PROC 得分为 0.580** +在仓库的 [π-Bench 评测](https://reme.agentscope.io/zh/benchmarks/pibench)中,ReMe Agent 在 5 种用户角色上的平均 **PROC 得分为 0.580** ,比相同测试模型配置的 NanoBot 高 2.4%。PROC 用于评估隐藏意图完成、针对性澄清、跨会话偏好和规范复用、跨任务依赖推断以及欠规格请求推进等主动性能力。 ## 🧩 扩展与插件 @@ -316,8 +316,8 @@ ReMe 通过 Agent 多轮搜索与读取的方式,评测多会话和超长上 | 插件 | 能力 | | ---------------------------------------------------------- | ------------------------------------------------------------------------------ | -| [每日论文](https://reme.agentscope.io/?doc=daily-paper-zh) | 发现并排序论文,使用 Agent 解读 PDF,生成文件化论文笔记和五分钟简报。 | -| [Auto Fin](https://reme.agentscope.io/?doc=auto-fin-zh) | 拉取主题相关财联社新闻,搜索 ReMe 历史材料并生成带 wikilink 的 Markdown 报告。 | +| [每日论文](https://reme.agentscope.io/zh/plugins/daily-paper) | 发现并排序论文,使用 Agent 解读 PDF,生成文件化论文笔记和五分钟简报。 | +| [Auto Fin](https://reme.agentscope.io/zh/plugins/auto-fin) | 拉取主题相关财联社新闻,搜索 ReMe 历史材料并生成带 wikilink 的 Markdown 报告。 | 安装、查看、校验、启用和卸载 ReMe 插件的方法见[插件管理](docs/zh/plugin_management.md)。 @@ -328,6 +328,8 @@ ReMe 通过 Agent 多轮搜索与读取的方式,评测多会话和超长上 | 文档 | 主要内容 | | ------------------------------------------------------------------------ | ---------------------------------------------------------------------- | | [快速开始](docs/zh/quick_start.md) | 安装 ReMe、启动服务,并执行首次文件和记忆操作。 | +| [基础配置](docs/zh/configuration.md) | 配置 workspace、模型、Service、Job、Component、插件和命令行覆盖。 | +| [服务与部署](docs/zh/services.md) | 使用 HTTP、SSE、MCP 和 Studio,并理解默认安全边界。 | | [Memory as File](docs/zh/memory_as_file.md) | 理解 workspace 分层、frontmatter、wikilink、chunk 和文件事实来源模型。 | | [Auto Memory](docs/zh/auto_memory.md) | 保留过滤后的对话来源记录,并提炼可复用的 daily 记忆卡片。 | | [Auto Resource](docs/zh/auto_resource.md) | 导入支持的文本资料,转换为可追溯来源的 daily 卡片。 | @@ -337,7 +339,9 @@ ReMe 通过 Agent 多轮搜索与读取的方式,评测多会话和超长上 | [应用场景](docs/zh/reme_scene.md) | 查看金融研究、研发记忆和个人知识库的完整使用示例。 | | [框架说明](docs/zh/framework.md) | 理解 Application、Job、Step、Component、service、配置和生命周期边界。 | | [TypeScript 集成](typescript/README_ZH.md) | 配置统一 client,以及 DeepSeek Harness 和 OpenClaw 原生适配器。 | -| [ReMe 博客](https://agentscope-ai.github.io/ReMe/?doc=zh-reme-blog) | 了解完整产品故事、设计动机、使用示例和评测摘要。 | +| [CLI 与 Job API](docs/zh/reference/cli.md) | 查询命令语法,以及由默认配置自动生成的 Job 参数参考。 | +| [运维与恢复](docs/zh/operations.md) | 诊断服务、维护索引,并备份、迁移和恢复 workspace。 | +| [ReMe 博客](https://reme.agentscope.io/zh/reme-blog) | 了解完整产品故事、设计动机、使用示例和评测摘要。 | ## 🛠️ 常用命令 diff --git a/benchmark/toolmemory/README.md b/benchmark/toolmemory/README.md index 7f358018..40ac47fe 100644 --- a/benchmark/toolmemory/README.md +++ b/benchmark/toolmemory/README.md @@ -6,7 +6,7 @@ > Code: [https://github.com/WangCan1178/ExpG](https://github.com/WangCan1178/ExpG)

- ExpG challenges and overview + ExpG challenges and overview

### Overview diff --git a/benchmark/toolmemory/README_ZH.md b/benchmark/toolmemory/README_ZH.md index b0c5b89b..0d247385 100644 --- a/benchmark/toolmemory/README_ZH.md +++ b/benchmark/toolmemory/README_ZH.md @@ -6,7 +6,7 @@ > 代码:[https://github.com/WangCan1178/ExpG](https://github.com/WangCan1178/ExpG)

- ExpG 挑战与概览 + ExpG 挑战与概览

### 简介 diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts new file mode 100644 index 00000000..17411bae --- /dev/null +++ b/docs/.vitepress/config.mts @@ -0,0 +1,342 @@ +import fs from "node:fs"; +import path from "node:path"; +import { execFileSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import { defineConfig, type DefaultTheme } from "vitepress"; +import { legacyRoutes } from "./legacy-routes.mjs"; + +const sourceRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const repositoryRoot = path.resolve(sourceRoot, "../../.."); +const repository = "https://github.com/agentscope-ai/ReMe"; +const base = process.env.DOCS_BASE || "/"; + +function readSourceMap(): Record { + try { + return JSON.parse(fs.readFileSync(path.join(sourceRoot, ".source-map.json"), "utf8")); + } catch { + return {}; + } +} + +const sourceMap = readSourceMap(); + +function collectMarkdown(directory: string, root = directory): string[] { + const files: string[] = []; + for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { + if (entry.name.startsWith(".") || entry.name === "public" || entry.name === "figure") continue; + const absolute = path.join(directory, entry.name); + if (entry.isDirectory()) files.push(...collectMarkdown(absolute, root)); + else if (entry.name.endsWith(".md")) files.push(path.relative(root, absolute).replaceAll(path.sep, "/")); + } + return files.sort(); +} + +function buildLlmsFiles(outDir: string) { + const pages = collectMarkdown(sourceRoot); + const index = [ + "# ReMe Documentation", + "", + "> Local-first, file-native memory for agents.", + "", + ...pages.map((relativePath) => { + const source = fs.readFileSync(path.join(sourceRoot, relativePath), "utf8"); + const title = source.match(/^#\s+(.+)$/m)?.[1] + || source.match(/^title:\s*(.+)$/m)?.[1] + || path.basename(relativePath, ".md"); + const route = relativePath.replace(/(?:^|\/)index\.md$/, "").replace(/\.md$/, ""); + return `- [${title}](https://reme.agentscope.io/${route})`; + }), + "", + ]; + fs.writeFileSync(path.join(outDir, "llms.txt"), index.join("\n"), "utf8"); + + const full = ["# ReMe Documentation", ""]; + for (const relativePath of pages) { + const source = fs.readFileSync(path.join(sourceRoot, relativePath), "utf8"); + full.push(``, "", source, "", "---", ""); + const pageDir = path.join(outDir, relativePath.replace(/\.md$/, "")); + fs.mkdirSync(pageDir, { recursive: true }); + fs.writeFileSync(path.join(pageDir, "llms.txt"), source, "utf8"); + } + fs.writeFileSync(path.join(outDir, "llms-full.txt"), full.join("\n"), "utf8"); +} + +function sourcePathFor(relativePath: string) { + return sourceMap[relativePath] || `docs/${relativePath}`; +} + +function sourceLastUpdated(relativePath: string): number | undefined { + const sourcePath = sourcePathFor(relativePath); + try { + const timestamp = execFileSync("git", ["log", "-1", "--format=%ct", "--", sourcePath], { + cwd: repositoryRoot, + encoding: "utf8", + }).trim(); + if (timestamp) return Number(timestamp) * 1000; + } catch { + // Fall back to the canonical file timestamp outside a Git checkout. + } + try { + return fs.statSync(path.join(repositoryRoot, sourcePath)).mtimeMs; + } catch { + return undefined; + } +} + +const legacyRedirectScript = `(() => { + const routes = ${JSON.stringify(legacyRoutes)}; + const id = new URLSearchParams(window.location.search).get("doc"); + const target = id && routes[id]; + const base = ${JSON.stringify(base)}; + if (target) { + const destination = /^https?:/.test(target) + ? target + : base.replace(/\\/$/, "") + target; + window.location.replace(destination + window.location.hash); + return; + } + const root = base.endsWith("/") ? base : base + "/"; + if (window.location.pathname === root) { + window.location.replace(root + "zh/" + window.location.hash); + } +})();`; + +function nav(language: "zh" | "en"): DefaultTheme.NavItem[] { + const zh = language === "zh"; + return [ + { text: zh ? "开始使用" : "Get Started", link: `/${language}/quick_start` }, + { text: zh ? "核心概念" : "Concepts", link: `/${language}/memory_as_file` }, + { text: zh ? "指南" : "Guides", link: `/${language}/auto_memory` }, + { text: zh ? "集成" : "Integrations", link: `/${language}/integrations` }, + { text: zh ? "API 参考" : "API Reference", link: `/${language}/reference/cli` }, + { text: zh ? "常见问题" : "FAQ", link: `/${language}/faq` }, + ]; +} + +function sidebar(language: "zh" | "en"): DefaultTheme.SidebarItem[] { + const zh = language === "zh"; + return [ + { + text: zh ? "开始使用" : "Get Started", + collapsed: false, + items: [ + { text: zh ? "项目介绍" : "Introduction", link: `/${language}/` }, + { text: zh ? "快速开始" : "Quick Start", link: `/${language}/quick_start` }, + { text: zh ? "基础配置" : "Configuration", link: `/${language}/configuration` }, + { text: zh ? "服务与部署" : "Services and Deployment", link: `/${language}/services` }, + ], + }, + { + text: zh ? "核心概念" : "Core Concepts", + collapsed: false, + items: [ + { text: zh ? "文件即记忆" : "Memory as File", link: `/${language}/memory_as_file` }, + { text: zh ? "记忆检索" : "Memory Search", link: `/${language}/memory_search` }, + { text: zh ? "自动关联" : "Auto Link", link: `/${language}/auto_link` }, + { text: zh ? "应用场景" : "Application Scenarios", link: `/${language}/reme_scene` }, + ], + }, + { + text: zh ? "记忆工作流" : "Memory Workflows", + collapsed: false, + items: [ + { text: "Auto Memory", link: `/${language}/auto_memory` }, + { text: "Auto Resource", link: `/${language}/auto_resource` }, + { text: "Auto Dream", link: `/${language}/auto_dream` }, + { text: "Proactive", link: `/${language}/proactive` }, + ], + }, + { + text: zh ? "Agent 集成" : "Agent Integrations", + collapsed: true, + items: [ + { text: zh ? "集成总览" : "Overview", link: `/${language}/integrations` }, + { text: "Claude Code", link: `/${language}/integrations/claude-code` }, + { text: "Hermes Agent", link: `/${language}/integrations/hermes` }, + { text: "TypeScript / OpenClaw / DSH", link: `/${language}/integrations/typescript` }, + ], + }, + { + text: zh ? "工作区与插件" : "Workspace and Plugins", + collapsed: true, + items: [ + { text: "ReMe Studio", link: `/${language}/workspace/studio` }, + { text: zh ? "插件管理" : "Plugin Management", link: `/${language}/plugin_management` }, + { text: zh ? "插件开发" : "Plugin Development", link: `/${language}/plugin_development` }, + { text: zh ? "每日论文" : "Daily Paper", link: `/${language}/plugins/daily-paper` }, + { text: "Auto Fin", link: `/${language}/plugins/auto-fin` }, + { text: "LME", link: `/${language}/plugins/lme` }, + { text: "BEAM", link: `/${language}/plugins/beam` }, + ], + }, + { + text: zh ? "API 参考" : "API Reference", + collapsed: true, + items: [ + { text: "CLI", link: `/${language}/reference/cli` }, + { text: zh ? "Job API" : "Job API", link: `/${language}/reference/jobs` }, + { text: "HTTP / MCP", link: `/${language}/services#http-api` }, + ], + }, + { + text: zh ? "运维" : "Operations", + collapsed: true, + items: [ + { text: zh ? "诊断、备份与恢复" : "Diagnostics, Backup, and Recovery", link: `/${language}/operations` }, + { text: zh ? "常见问题" : "FAQ", link: `/${language}/faq` }, + ], + }, + { + text: zh ? "开发者" : "Development", + collapsed: true, + items: [ + { text: zh ? "代码框架" : "Framework", link: `/${language}/framework` }, + { text: zh ? "开源与贡献" : "Contributing", link: `/${language}/contributing` }, + ], + }, + { + text: zh ? "评测" : "Benchmarks", + collapsed: true, + items: [ + { text: "BEAM", link: `/${language}/benchmarks/beam` }, + { text: "LongMemEval", link: `/${language}/benchmarks/longmemeval` }, + { text: "π-Bench", link: `/${language}/benchmarks/pibench` }, + { text: "Tool Memory / ExpG", link: `/${language}/benchmarks/toolmemory` }, + ], + }, + ]; +} + +function configureRepositoryLinks(md: any) { + for (const ruleName of ["link_open", "image"] as const) { + const original = md.renderer.rules[ruleName]; + md.renderer.rules[ruleName] = (tokens: any[], index: number, options: any, env: any, self: any) => { + const attribute = ruleName === "image" ? "src" : "href"; + const token = tokens[index]; + const attributeIndex = token.attrIndex(attribute); + const target = attributeIndex >= 0 ? token.attrs[attributeIndex][1] : ""; + if (target && !/^(?:[a-z]+:|#|\/)/i.test(target)) { + const cleanTarget = target.split("#")[0].split("?")[0]; + const generatedTarget = path.resolve(sourceRoot, path.dirname(env.relativePath), cleanTarget); + if (!fs.existsSync(generatedTarget)) { + const originalPage = sourcePathFor(env.relativePath); + const originalTarget = path.posix.normalize(path.posix.join(path.posix.dirname(originalPage), cleanTarget)); + const suffix = target.slice(cleanTarget.length); + const url = ruleName === "image" + ? `https://raw.githubusercontent.com/agentscope-ai/ReMe/main/${originalTarget}${suffix}` + : `${repository}/blob/main/${originalTarget}${suffix}`; + token.attrs[attributeIndex][1] = url; + } + } + return original ? original(tokens, index, options, env, self) : self.renderToken(tokens, index, options); + }; + } +} + +export default defineConfig({ + lang: "zh-CN", + title: "ReMe", + description: "Local-first, file-native memory for agents", + base, + cleanUrls: true, + lastUpdated: true, + ignoreDeadLinks: [/^http:\/\/localhost(?::\d+)?(?:\/|$)/], + sitemap: { + hostname: "https://reme.agentscope.io", + transformItems(items) { + const isRoot = (url: string) => url.replace(/^\/+|\/+$/g, "") === ""; + return items.filter((item) => !isRoot(item.url)).map((item) => { + const route = item.url.replace(/^\/+/, ""); + const relativePath = !route || route.endsWith("/") ? `${route}index.md` : `${route}.md`; + const links = item.links?.filter((link) => !isRoot(link.url)); + return { ...item, links, lastmod: sourceLastUpdated(relativePath) }; + }); + }, + }, + head: [ + ["link", { rel: "icon", type: "image/svg+xml", href: `${base}favicon.svg` }], + ["meta", { name: "theme-color", content: "#087f6a" }], + ["script", {}, legacyRedirectScript], + ], + markdown: { + config: configureRepositoryLinks, + }, + transformPageData(pageData, { siteConfig }) { + const sourcePath = path.join(siteConfig.srcDir, pageData.relativePath); + pageData.frontmatter._sourcePath = sourcePathFor(pageData.relativePath); + pageData.lastUpdated = sourceLastUpdated(pageData.relativePath); + try { + pageData.frontmatter._rawMarkdown = fs.readFileSync(sourcePath, "utf8"); + } catch { + pageData.frontmatter._rawMarkdown = ""; + } + }, + buildEnd(siteConfig) { + buildLlmsFiles(siteConfig.outDir); + }, + themeConfig: { + logo: "/favicon.svg", + siteTitle: "ReMe", + nav: [ + ...nav("zh"), + { + text: "语言", + items: [ + { text: "简体中文", link: "/zh/" }, + { text: "English", link: "/en/" }, + ], + }, + ], + outline: { label: "页面导航", level: [2, 3] }, + search: { + provider: "local", + options: { + locales: { + zh: { + translations: { + button: { buttonText: "搜索文档", buttonAriaLabel: "搜索文档" }, + modal: { + noResultsText: "没有找到相关内容", + resetButtonTitle: "清除查询", + footer: { selectText: "选择", navigateText: "切换", closeText: "关闭" }, + }, + }, + }, + }, + }, + }, + socialLinks: [{ icon: "github", link: repository }], + footer: { + message: "Released under the Apache-2.0 License.", + copyright: "Copyright ReMe contributors", + }, + }, + locales: { + zh: { + label: "简体中文", + lang: "zh-CN", + link: "/zh/", + themeConfig: { + nav: nav("zh"), + sidebar: { "/zh/": sidebar("zh") }, + outline: { label: "页面导航", level: [2, 3] }, + docFooter: { prev: "上一页", next: "下一页" }, + darkModeSwitchLabel: "外观", + sidebarMenuLabel: "菜单", + returnToTopLabel: "返回顶部", + langMenuLabel: "切换语言", + }, + }, + en: { + label: "English", + lang: "en-US", + link: "/en/", + themeConfig: { + nav: nav("en"), + sidebar: { "/en/": sidebar("en") }, + outline: { label: "On this page", level: [2, 3] }, + docFooter: { prev: "Previous page", next: "Next page" }, + }, + }, + }, +}); diff --git a/docs/.vitepress/legacy-routes.mjs b/docs/.vitepress/legacy-routes.mjs new file mode 100644 index 00000000..bdf3607e --- /dev/null +++ b/docs/.vitepress/legacy-routes.mjs @@ -0,0 +1,47 @@ +export const legacyRoutes = { + "readme-zh": "/zh/", + "readme-en": "/en/", + "zh-quick_start": "/zh/quick_start", + "en-quick_start": "/en/quick_start", + "zh-plugin_management": "/zh/plugin_management", + "en-plugin_management": "/en/plugin_management", + "zh-memory_as_file": "/zh/memory_as_file", + "en-memory_as_file": "/en/memory_as_file", + "zh-memory_search": "/zh/memory_search", + "en-memory_search": "/en/memory_search", + "zh-auto_memory": "/zh/auto_memory", + "en-auto_memory": "/en/auto_memory", + "zh-auto_resource": "/zh/auto_resource", + "en-auto_resource": "/en/auto_resource", + "zh-auto_link": "/zh/auto_link", + "en-auto_link": "/en/auto_link", + "zh-auto_dream": "/zh/auto_dream", + "en-auto_dream": "/en/auto_dream", + "zh-proactive": "/zh/proactive", + "en-proactive": "/en/proactive", + "zh-reme_scene": "/zh/reme_scene", + "en-reme_scene": "/en/reme_scene", + "zh-framework": "/zh/framework", + "en-framework": "/en/framework", + "zh-reme-blog": "/zh/reme-blog", + "en-reme-blog": "/en/reme-blog", + "zh-contributing": "/zh/contributing", + "en-contributing": "/en/contributing", + "typescript-zh": "/zh/integrations/typescript", + "typescript-en": "/en/integrations/typescript", + "studio-zh": "/zh/workspace/studio", + "studio-en": "/en/workspace/studio", + "daily-paper-zh": "/zh/plugins/daily-paper", + "daily-paper-en": "/en/plugins/daily-paper", + "auto-fin-zh": "/zh/plugins/auto-fin", + "auto-fin-en": "/en/plugins/auto-fin", + "beam-zh": "/zh/benchmarks/beam", + "beam-en": "/en/benchmarks/beam", + "longmemeval-zh": "/zh/benchmarks/longmemeval", + "longmemeval-en": "/en/benchmarks/longmemeval", + "pibench-zh": "/zh/benchmarks/pibench", + "pibench-en": "/en/benchmarks/pibench", + "toolmemory-zh": "/zh/benchmarks/toolmemory", + "toolmemory-en": "/en/benchmarks/toolmemory", + "agents-guide": "https://github.com/agentscope-ai/ReMe/blob/main/AGENTS.md", +}; diff --git a/docs/.vitepress/theme/CopyMarkdownButton.vue b/docs/.vitepress/theme/CopyMarkdownButton.vue new file mode 100644 index 00000000..b3805638 --- /dev/null +++ b/docs/.vitepress/theme/CopyMarkdownButton.vue @@ -0,0 +1,32 @@ + + + diff --git a/docs/.vitepress/theme/SourceLink.vue b/docs/.vitepress/theme/SourceLink.vue new file mode 100644 index 00000000..cebc353e --- /dev/null +++ b/docs/.vitepress/theme/SourceLink.vue @@ -0,0 +1,15 @@ + + + diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css new file mode 100644 index 00000000..5f4974ac --- /dev/null +++ b/docs/.vitepress/theme/custom.css @@ -0,0 +1,224 @@ +:root { + --vp-layout-max-width: 1560px; + --vp-c-brand-1: #087f6a; + --vp-c-brand-2: #086554; + --vp-c-brand-3: #19a98f; + --vp-c-brand-soft: rgba(8, 127, 106, 0.14); + --vp-c-bg: #ffffff; + --vp-c-bg-alt: #f4f7f5; + --vp-c-bg-elv: #ffffff; + --vp-c-bg-soft: #f1f6f3; + --vp-c-text-1: #17221d; + --vp-c-text-2: #526159; + --vp-c-text-3: #718078; + --vp-c-divider: #dce5e0; + --vp-font-family-base: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --vp-font-family-mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace; + --reme-blue: #3156d9; + --reme-green: #087f6a; +} + +.dark { + --vp-c-brand-1: #57dfc3; + --vp-c-brand-2: #35c6a9; + --vp-c-brand-3: #087f6a; + --vp-c-brand-soft: rgba(87, 223, 195, 0.14); + --vp-c-bg: #0d1512; + --vp-c-bg-alt: #09100d; + --vp-c-bg-elv: #14201b; + --vp-c-bg-soft: #17251f; + --vp-c-text-1: #edf7f3; + --vp-c-text-2: #bacbc4; + --vp-c-text-3: #91a49c; + --vp-c-divider: #283a33; +} + +body { + background: + radial-gradient(circle at 8% 8%, rgba(25, 201, 176, 0.055), transparent 28rem), + var(--vp-c-bg); +} + +.VPNav { + border-bottom: 1px solid color-mix(in srgb, var(--vp-c-divider) 84%, transparent); + background: color-mix(in srgb, var(--vp-c-bg) 88%, transparent); + backdrop-filter: blur(18px) saturate(140%); +} + +.VPNavBarTitle .logo { + width: 30px; + height: 30px; +} + +.VPNavBarTitle .title { + font-weight: 780; + letter-spacing: -0.02em; +} + +.VPNavBarSearch .DocSearch-Button, +.VPNavBarSearch button { + min-width: 190px; + border: 1px solid var(--vp-c-divider); + border-radius: 10px; + background: var(--vp-c-bg-alt); +} + +.VPSidebar { + border-right: 1px solid var(--vp-c-divider); + background: color-mix(in srgb, var(--vp-c-bg-alt) 82%, transparent); +} + +.VPSidebarItem .text { + font-size: 14px; +} + +.VPSidebarItem.level-0 > .item > .text { + color: var(--vp-c-text-1); + font-weight: 750; +} + +.VPSidebarItem.is-active > .item .link > .text { + color: var(--vp-c-brand-1); +} + +.VPDocAsideOutline { + border-left-color: var(--vp-c-divider); +} + +.VPDoc .container > .content { + min-width: 0; +} + +.VPDoc .content-container { + max-width: 900px !important; +} + +.vp-doc { + color: var(--vp-c-text-1); + font-size: 16px; + line-height: 1.78; +} + +.vp-doc h1 { + margin-bottom: 28px; + font-size: clamp(36px, 5vw, 52px); + line-height: 1.08; + letter-spacing: -0.045em; +} + +.vp-doc h2 { + margin-top: 52px; + border-top-color: var(--vp-c-divider); + font-size: 27px; + letter-spacing: -0.025em; +} + +.vp-doc h3 { + margin-top: 34px; + font-size: 20px; +} + +.vp-doc :not(pre) > code { + border-radius: 5px; + color: color-mix(in srgb, var(--vp-c-brand-1) 82%, var(--vp-c-text-1)); +} + +.vp-doc div[class*="language-"] { + border: 1px solid var(--vp-c-divider); + border-radius: 12px; + box-shadow: inset 3px 0 0 color-mix(in srgb, var(--vp-c-brand-1) 62%, transparent); +} + +.copy-markdown-wrap { + display: flex; + justify-content: flex-end; + margin-bottom: 18px; +} + +.copy-markdown { + display: inline-flex; + align-items: center; + gap: 7px; + min-height: 34px; + padding: 6px 12px; + border: 1px solid var(--vp-c-divider); + border-radius: 9px; + color: var(--vp-c-text-2); + background: var(--vp-c-bg-soft); + cursor: pointer; + font-size: 13px; + font-weight: 650; +} + +.copy-markdown:hover, +.copy-markdown.copied { + border-color: var(--vp-c-brand-1); + color: var(--vp-c-brand-1); +} + +.copy-markdown svg { + width: 15px; + height: 15px; + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 2; +} + +.source-link-wrap { + margin-top: 48px; + padding-top: 20px; + border-top: 1px solid var(--vp-c-divider); + font-size: 13px; +} + +.source-link-wrap a { + color: var(--vp-c-text-3); + text-decoration: none; +} + +.source-link-wrap a:hover { + color: var(--vp-c-brand-1); +} + +.VPHome { + background: + radial-gradient(circle at 14% 14%, rgba(25, 201, 176, 0.14), transparent 30rem), + radial-gradient(circle at 86% 10%, rgba(49, 86, 217, 0.11), transparent 28rem); +} + +.VPHero .name { + background: linear-gradient(120deg, var(--reme-green), var(--reme-blue)); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.VPHero .name, +.VPHero .text { + letter-spacing: -0.05em; +} + +.VPHero .image-bg { + background: linear-gradient(135deg, rgba(25, 201, 176, 0.28), rgba(49, 86, 217, 0.2)); + filter: blur(46px); +} + +.VPFeature { + border-color: color-mix(in srgb, var(--vp-c-brand-1) 18%, var(--vp-c-divider)); + border-radius: 16px; + background: linear-gradient(150deg, var(--vp-c-bg-elv), var(--vp-c-bg-soft)); + transition: transform 160ms ease, box-shadow 160ms ease; +} + +.VPFeature:hover { + transform: translateY(-3px); + box-shadow: 0 16px 34px rgba(21, 58, 43, 0.1); +} + +@media (max-width: 768px) { + .vp-doc h1 { font-size: 34px; } + .vp-doc h2 { margin-top: 44px; font-size: 24px; } + .copy-markdown-wrap { margin-top: -8px; } +} diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 00000000..5edbc9e7 --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,15 @@ +import { h } from "vue"; +import DefaultTheme from "vitepress/theme"; +import CopyMarkdownButton from "./CopyMarkdownButton.vue"; +import SourceLink from "./SourceLink.vue"; +import "./custom.css"; + +export default { + extends: DefaultTheme, + Layout() { + return h(DefaultTheme.Layout, null, { + "doc-before": () => h(CopyMarkdownButton), + "doc-after": () => h(SourceLink), + }); + }, +}; diff --git a/docs/en/configuration.md b/docs/en/configuration.md new file mode 100644 index 00000000..49e84bc1 --- /dev/null +++ b/docs/en/configuration.md @@ -0,0 +1,157 @@ +--- +title: Configuration +description: ReMe configuration files, environment expansion, command-line overrides, and core components. +--- + +# Configuration + +ReMe uses YAML or JSON to describe its Service, Jobs, and Components. The built-in default is `reme/config/default.yaml`. Select another configuration at startup and apply command-line overrides when needed. + +## Precedence + +Configuration is merged in this order, with later values winning: + +1. `application_defaults` from enabled plugins. +2. The selected file; `default` is used when none is specified. +3. CLI dot-notation overrides. + +```bash +reme start +reme start config=demo +reme start config=/absolute/path/to/app.yaml +reme start service.port=8181 workspace_dir=/data/reme +``` + +`config` accepts a built-in name or a `.yaml`, `.yml`, or `.json` file. Overrides are deep-merged, so changing `service.port` preserves sibling service settings. + +## CLI values + +Arguments use `key=value`; leading `-` or `--` is accepted: + +```bash +reme start --service.port=8181 --service.web_enabled=false +``` + +Values support null, booleans, numbers, JSON arrays and objects, quoted JSON strings, and plain strings. Numeric-looking values with leading zeroes, such as `007`, remain strings. Quote values such as `"true"` in JSON when they must remain strings. + +## Environment variables + +Configuration recursively expands: + +```yaml +api_key: ${LLM_API_KEY} +base_url: ${LLM_BASE_URL:-https://example.com/v1} +``` + +`${VAR}` fails when undefined; `${VAR:-default}` uses its fallback. ReMe also searches for `.env` from the command's working directory through at most five parents. + +Keep secrets in `.env` or the process environment, never in committed configuration. + +## Application fields + +| Field | Default | Purpose | +|---|---|---| +| `app_name` | `ReMe` | Display name | +| `workspace_dir` | `.reme` | User-owned workspace root, normalized to an absolute path | +| `metadata_dir` | `metadata` | Rebuildable indexes, graphs, and catalogs | +| `session_dir` | `session` | Agent sessions; standard transcripts use `session/dialog` | +| `mem_session_dir` | `mem_session` | Agent-wrapper sessions and configuration | +| `resource_dir` | `resource` | External resources | +| `daily_dir` | `daily` | Daily memory | +| `digest_dir` | `digest` | Consolidated long-term memory | +| `timezone` | `Asia/Shanghai` | IANA timezone used for dates and cron jobs | +| `language` | empty | Default language for LLM interactions | +| `plugins` | `[]` | Installed plugins enabled for this Application | +| `service` | HTTP | Service configuration | +| `jobs` | default Jobs | Job configurations by name | +| `components` | defaults | Components grouped by type and name | + +`session_dir` must remain workspace-relative. + +## LLM + +The default LLM uses an OpenAI-compatible interface: + +```yaml +components: + as_llm: + default: + backend: openai + model: qwen3.7-plus + context_size: 200000 + credential: + api_key: ${LLM_API_KEY:-} + base_url: ${LLM_BASE_URL:-} +``` + +Built-in registrations include `openai`, `anthropic`, `dashscope`, `deepseek`, `gemini`, `moonshot`, `ollama`, and `xai`. Their detailed model fields follow the corresponding AgentScope wrappers. + +File operations, BM25 search, and wikilink traversal do not require an LLM. Evolution workflows such as `auto_memory`, `auto_resource`, and `auto_dream` do. + +## Embeddings + +Vector retrieval is disabled by default. Credentials alone do not enable it: configure `as_embedding`, `embedding_store`, and connect the store to `file_store`. + +```yaml +components: + as_embedding: + default: + backend: openai + model: text-embedding-v4 + dimensions: 1024 + credential: + api_key: ${EMBEDDING_API_KEY} + base_url: ${EMBEDDING_BASE_URL:-https://dashscope.aliyuncs.com/compatible-mode/v1} + embedding_store: + default: + backend: local + as_embedding: default + file_store: + default: + backend: local + embedding_store: default + keyword_index: default + file_graph: default +``` + +Rebuild the embedding index after changing the model or dimensions. + +## Service and Jobs + +Minimal HTTP configuration: + +```yaml +service: + backend: http + host: 127.0.0.1 + port: 2333 + web_enabled: true + mcp_enabled: true + mcp_path: /mcp +``` + +A Job declares a backend, parameter schema, and ordered Steps: + +```yaml +jobs: + example: + backend: base + description: Example job + parameters: + type: object + properties: + text: { type: string } + required: [text] + steps: + - backend: example_step +``` + +Set `enable_serve: false` to keep a Job internal. Background and cron Jobs are never service-exposed. + +## Inspect the effective configuration + +```bash +reme app_config +``` + +The result is the merged, validated configuration with secrets redacted. Use it when diagnosing plugin or override precedence. The authoritative contracts remain `reme/schema/application_config.py` and `reme/config/default.yaml`. diff --git a/docs/en/contributing.md b/docs/en/contributing.md index ad962169..99c9fac1 100644 --- a/docs/en/contributing.md +++ b/docs/en/contributing.md @@ -209,6 +209,13 @@ Documentation lives under: docs/ ``` +User guides should have matching `docs/zh/` and `docs/en/` versions and appear in the corresponding navigation in +`docs/.vitepress/config.mts`. The ReMe Studio, TypeScript, plugin, and benchmark READMEs remain canonical in their own +directories; `github-pages/scripts/generate-content.mjs` mirrors them during builds. Never edit `.generated/` or `dist/`. + +The Job API reference is generated from `reme/config/default.yaml`. Update that YAML and its tests when a default Job +contract changes rather than editing generated pages. + Documentation should: - Use clear titles that directly identify a capability or flow. @@ -216,6 +223,15 @@ Documentation should: - Use real repository paths such as `reme/config/default.yaml`, `reme/steps/`, and `tests/unit/`. - Describe default behavior according to the current code, `pyproject.toml`, and default configuration. +Validate the documentation site with: + +```bash +cd github-pages +npm ci +npm test +npm run build +``` + --- ## Getting Help diff --git a/docs/en/faq.md b/docs/en/faq.md new file mode 100644 index 00000000..6aeb113a --- /dev/null +++ b/docs/en/faq.md @@ -0,0 +1,71 @@ +--- +title: Frequently Asked Questions +description: Quick answers for ReMe installation, services, models, retrieval, files, and plugins. +--- + +# Frequently Asked Questions + +## Do basic file operations require a model API key? + +No. `write`, `read`, `list`, `stat`, BM25 search, and wikilink traversal work without model credentials. `auto_memory`, `auto_resource`, and `auto_dream` require an LLM. + +## Why is search still BM25-only after setting an embedding key? + +Embeddings are disabled by default. Configure `as_embedding` and `embedding_store`, then connect `file_store.default.embedding_store` to that component. See [Configuration](./configuration.md#embeddings). + +## Why did `reme reindex` not discover a new file? + +`reindex` rebuilds indexes from current `file_chunks`; it does not scan the workspace. Check `index_update_loop`, the watched directory and extension, and `health_check`. + +## How do I use another workspace? + +```bash +reme start workspace_dir=/absolute/path/to/memory +``` + +Ordinary CLI calls discover the running service, so they do not need the workspace argument again. + +## What if port 2333 is occupied? + +Do not stop an unknown listener. Select another port: + +```bash +reme start service.port=8181 +``` + +Then confirm it with `reme find_reme`. + +## Why is an installed plugin missing its Jobs? + +Installation only makes the distribution discoverable in the active Python environment. Enable it for the Application: + +```bash +reme start plugins='["auto-fin"]' +``` + +Restart a running service after changing package or enablement state. + +## May I edit workspace Markdown directly? + +Yes. Files are the source of truth and watchers ingest changes. Keep frontmatter valid, use complete workspace-relative wikilinks, and avoid unconditional concurrent saves. + +## May I expose ReMe publicly? + +Not with the default configuration alone. Jobs can write and delete, HTTP CORS is permissive, and there is no general authentication layer. Use a controlled network or authenticated TLS reverse proxy and restrict `service.jobs`. + +## How should I back up and migrate memory? + +Stop writes and back up the complete workspace. `session/`, `resource/`, `daily/`, and `digest/` are the key sources; `metadata/` can be backed up or rebuilt. See [Diagnostics, Backup, and Recovery](./operations.md). + +## Why is Studio unavailable? + +The base `reme-ai` package has no frontend assets. Install `reme-ai[web]` or `reme-ai[core]`, or set `service.web_static_dir`. Missing Studio assets do not disable the Job API. + +## Which capabilities does the running service expose? + +```bash +reme help +reme app_config +``` + +Static documentation describes defaults; plugins and custom configuration may change the active service. diff --git a/docs/en/index.md b/docs/en/index.md new file mode 100644 index 00000000..a1b925c8 --- /dev/null +++ b/docs/en/index.md @@ -0,0 +1,36 @@ +--- +layout: home +title: ReMe Documentation +titleTemplate: false +hero: + name: ReMe + text: Memory that works for agents + tagline: Files remain yours. ReMe turns conversations and resources into readable, editable, searchable, interconnected local files. + image: + src: /favicon.svg + alt: ReMe + actions: + - theme: brand + text: Quick Start + link: /en/quick_start + - theme: alt + text: Configuration + link: /en/configuration +features: + - icon: 📁 + title: Memory as files + details: Workspace files are the durable source of truth; indexes, graphs, and caches remain rebuildable. + link: /en/memory_as_file + - icon: 🧠 + title: Memory workflows + details: Turn conversations and resources into daily notes, then consolidate them into connected long-term digests. + link: /en/auto_memory + - icon: 🔎 + title: Search and graph + details: Combine keyword and optional vector retrieval with wikilink graph expansion. + link: /en/memory_search + - icon: 🔌 + title: Agent integrations + details: Connect existing agents through the CLI, HTTP, MCP, and host adapters. + link: /en/integrations +--- diff --git a/docs/en/integrations.md b/docs/en/integrations.md new file mode 100644 index 00000000..03b2cf0a --- /dev/null +++ b/docs/en/integrations.md @@ -0,0 +1,63 @@ +--- +title: Agent Integrations +description: Connect ReMe to agents through the CLI, HTTP, MCP, Skills, and host adapters. +--- + +# Agent Integrations + +ReMe keeps memory in an independent service and a user-owned workspace. Multiple agents can call the same memory system without binding storage to one model or host. + +## Choose an interface + +| Scenario | Recommended interface | +|---|---| +| Local script or hook | ReMe CLI | +| Application backend | HTTP Client | +| Tool-protocol host | MCP | +| TypeScript agent | `@agentscope-ai/reme` | +| Claude Code | MCP + Skill + Stop Hook | +| Hermes Agent | Memory provider adapter | +| Codex or another coding agent | `reme_memory` Skill or MCP | + +## General memory loop + +1. Before answering, call `search` for relevant memory. +2. Use `read` on high-value results and `traverse` when relationships matter. +3. Retain workspace-relative source paths in the answer. +4. At session end, pass source messages to `auto_memory`. +5. Let background or scheduled workflows consolidate daily notes into digest memory. + +An empty search result must remain empty; do not present model inference as recalled history. + +## MCP + +The default HTTP service exposes streamable HTTP MCP at `http://127.0.0.1:2333/mcp`. Common tools include `search`, `read`, `traverse`, `list`, `auto_memory`, and `proactive`. + +Use `service.jobs` to expose a read-only subset or keep write tools in a separate configuration. + +## CLI and Skill + +`skills/reme_memory/SKILL.md` defines a general workflow for agents that can run local commands: installation checks, service discovery, retrieval, reading, and persistence boundaries. + +It deliberately avoids silently modifying Python environments, stopping unknown processes on port conflicts, writing recalled tool output back as conversation source, or persisting credentials. + +## TypeScript, OpenClaw, and DeepSeek Harness + +See [TypeScript Agent Integrations](./integrations/typescript.md) for the shared HTTP client, DeepSeek Harness adapter, OpenClaw adapter, and package validation. + +## Claude Code + +`integrations/claude_code/` provides streamable HTTP MCP configuration, a `reme-memory` Skill, and a Stop hook that calls `auto_memory_cc`. Follow that directory's README for installation. + +## Hermes Agent + +`integrations/hermes_agent/` provides a memory provider that recalls context before model calls and asynchronously invokes `auto_memory` after each turn. + +## Production guidance + +- choose a stable absolute `workspace_dir`; +- reuse a service discovered by `reme find_reme`; +- treat `reme help` as the active Job contract; +- apply timeouts and failure logging to writes; +- do not block the host's core response path when memory is temporarily unavailable; +- use authentication, TLS, and a minimal Job allowlist for remote access. diff --git a/docs/en/operations.md b/docs/en/operations.md new file mode 100644 index 00000000..50160661 --- /dev/null +++ b/docs/en/operations.md @@ -0,0 +1,102 @@ +--- +title: Diagnostics, Backup, and Recovery +description: ReMe health checks, logs, index maintenance, workspace backup, migration, and recovery. +--- + +# Diagnostics, Backup, and Recovery + +ReMe recovery protects user-owned workspace files and rebuilds catalogs, indexes, and graphs from those sources. Never delete or rewrite user memory merely to repair derived state. + +## Quick diagnosis + +Run these in order: + +```bash +reme find_reme +reme version +reme health_check +reme status +reme app_config +``` + +- `find_reme` confirms the actual host, port, and PID; +- `version` verifies that the CLI reaches the service; +- `health_check` reports component health; +- `status` estimates stateful component memory and process RSS; +- `app_config` returns the effective configuration with secrets redacted. + +## Logs and common symptoms + +`log_to_console` and `log_to_file` control logging. For startup failures, inspect the first exception rather than later client connection errors. + +| Symptom | Check first | +|---|---| +| CLI cannot find ReMe | `reme find_reme`, process state, startup directory, and port | +| Automatic memory fails | LLM backend, model, API key, and base URL | +| Search is BM25-only | Whether an embedding store is connected to `file_store` | +| New files are absent | Directory, extension, watcher, and `health_check` | +| Studio fails but API works | Installed web extra, static path, and browser console | +| Installed plugin is unavailable | Python interpreter, `plugins` configuration, and service restart | + +## Index maintenance + +```bash +reme reindex scope=all +reme reindex scope=bm25 +reme reindex scope=embedding +``` + +`reindex` rebuilds BM25 and/or embedding indexes from the current `file_chunks`. It does not scan the workspace, rechunk files, or rebuild the wikilink graph. Diagnose the watcher first when ingestion is the problem. + +Rebuild a daily index page separately: + +```bash +reme daily_reindex date=2026-09-04 +``` + +## Backup + +Stop writes or stop the service, then back up the complete workspace. The most important sources are: + +- `session/` for conversation sources; +- `resource/` for external resources; +- `daily/` for daily memory; +- `digest/` for consolidated memory. + +`metadata/` contains indexes, graphs, and catalogs. Backing it up accelerates restoration, but it is not the sole source of truth. + +Use an explicit, stable absolute `workspace_dir` for durable deployments rather than relying on an incidental `.reme/` under the current directory. + +## Migrate a workspace + +1. Stop the old service to prevent writes during the copy. +2. Copy the complete workspace while preserving timestamps. +3. Start with the new absolute path: + +```bash +reme start workspace_dir=/new/location/reme-memory +``` + +4. Run `health_check`, `status`, and a representative `search`. +5. Rebuild embeddings if their model or dimensions changed. + +Do not push a workspace containing private conversations to a public repository. + +## Recover derived state + +Do not remove anything until a backup exists. Then: + +1. preserve `session/`, `resource/`, `daily/`, and `digest/`; +2. record the effective configuration and component backends; +3. verify that the failure is limited to `metadata/`; +4. move suspect derived state to an isolated backup location; +5. restart with the same configuration and let watchers rebuild; +6. validate search, graph traversal, and daily indexes. + +The internal layout of metadata files is not a public automation contract. + +## Concurrent editing + +When Studio or an editor saves a complete file, pass the mtime from `stat` as `save.expected_mtime`. A save then fails if another actor changed the file after it was opened, avoiding silent overwrites. + +File Jobs enforce workspace containment and per-path locking. Do not bypass them to write arbitrary absolute paths. diff --git a/docs/en/plugin_development.md b/docs/en/plugin_development.md new file mode 100644 index 00000000..074033c3 --- /dev/null +++ b/docs/en/plugin_development.md @@ -0,0 +1,101 @@ +--- +title: Plugin Development +description: Create, register, configure, test, and publish a ReMe plugin. +--- + +# Plugin Development + +A ReMe plugin is a regular Python distribution exposed through the `reme.plugins` entry-point group. Its package-level `plugin.yaml` can register Step and Component backends and provide default Application configuration. + +## Minimal structure + +```text +my-plugin/ +├── pyproject.toml +└── src/my_plugin/ + ├── __init__.py + ├── plugin.yaml + └── steps.py +``` + +`pyproject.toml`: + +```toml +[project.entry-points."reme.plugins"] +my-plugin = "my_plugin" +``` + +`plugin.yaml`: + +```yaml +name: my-plugin +backends: + my_step: my_plugin.steps:MyStep +application_defaults: + jobs: + my_action: + backend: base + description: Run my plugin action + parameters: + type: object + properties: + text: { type: string } + required: [text] + steps: + - backend: my_step +``` + +## Implement a Step + +```python +from reme.components.component_registry import R +from reme.steps.base_step import BaseStep + + +@R.register("my_step") +class MyStep(BaseStep): + async def execute(self): + self.context.response.answer = self.context.data["text"] +``` + +Step instances belong to one Job invocation. Put shared in-memory state under a narrow `app_context.metadata` key. Promote state that needs lifecycle, locking, or persistence to a Component or workspace file. + +## Configuration merge + +`application_defaults` is a partial `ApplicationConfig`: + +```text +plugin defaults < selected/default config < CLI overrides +``` + +Plugins must not rewrite user configuration. Their backends enter an Application-local registry only when the plugin appears in that Application's `plugins` list. + +## Local validation + +```bash +reme plugins validate ./path/to/my-plugin +reme plugins install ./path/to/my-plugin --editable +reme plugins list +reme plugins show my-plugin +reme start plugins='["my-plugin"]' +reme my_action text=hello +``` + +Validation imports plugin code, so run it only for trusted sources. + +## Test boundaries + +- create workspaces with `tmp_path`; +- mock network, model, and subprocess boundaries; +- verify disabled plugins do not mutate the built-in registry; +- verify plugin defaults and explicit configuration precedence; +- keep tasks, clients, and executors under Component lifecycle; +- never delete or rewrite user source files to repair derived state. + +The repository's Daily Paper, Auto Fin, LME, and BEAM plugins are complete examples. + +## Compatibility + +Legacy Python Plugin descriptors and the `reme.configs` entry point remain supported during migration, but new plugins should use `plugin.yaml`. Enablement always belongs to an Application rather than a process-global switch. + +See [Plugin Management](./plugin_management.md) for installation, upgrades, and removal. diff --git a/docs/en/quick_start.md b/docs/en/quick_start.md index a15edef2..f946ac39 100644 --- a/docs/en/quick_start.md +++ b/docs/en/quick_start.md @@ -1,5 +1,12 @@ +--- +title: Quick Start +description: Install and start ReMe, then complete a first file, retrieval, and automatic-memory workflow. +--- + # Quick Start +This page gets one working loop running. See [Configuration](./configuration.md) for the full configuration contract and [Services and Deployment](./services.md) for HTTP or MCP integration. + ## Installation ReMe requires Python 3.11+. @@ -237,3 +244,5 @@ You can also specify a YAML or JSON configuration file: ```bash reme start config=/path/to/custom.yaml ``` + +Continue with the [CLI Reference](./reference/cli.md), [Job API Reference](./reference/jobs.md), or [Diagnostics, Backup, and Recovery](./operations.md). diff --git a/docs/en/reference/cli.md b/docs/en/reference/cli.md new file mode 100644 index 00000000..5a3c372d --- /dev/null +++ b/docs/en/reference/cli.md @@ -0,0 +1,87 @@ +--- +title: CLI Reference +description: ReMe command syntax, service invocation, configuration overrides, and plugin commands. +--- + +# CLI Reference + +The basic syntax is: + +```text +reme ACTION key=value ... +``` + +## Start an Application + +```bash +reme start +reme start config=demo +reme start workspace_dir=/data/reme service.port=8181 +reme start job=search query="keywords" limit=5 +``` + +`start job=` runs one Job through a one-shot service; plain `start` runs the configured Service. + +## Call Jobs + +Once a service is running, each action name is a Job name: + +```bash +reme help +reme health_check +reme search query="project decision" limit=10 +reme read path=digest/wiki/project.md start_line=1 end_line=80 +``` + +Use JSON for structured values: + +```bash +reme auto_memory \ + session_id=example \ + messages='[{"role":"user","content":"Remember this preference"}]' +``` + +Client-selection arguments—`backend`, `transport`, `host`, `port`, `timeout`, `command`, `args`, and `show_metadata`—configure the client and never leak into the Job payload. + +## Configuration overrides + +```bash +reme start \ + config=/path/to/custom.yaml \ + service.port=8181 \ + service.web_enabled=false \ + plugins='["auto-fin"]' +``` + +Leading `-` or `--` is optional. Use dots for nested keys and JSON for arrays and objects. + +## Service discovery + +```bash +reme find_reme +``` + +This reports a discovered service but never starts or replaces a process. + +## Plugin commands + +Package management runs locally rather than through HTTP or MCP: + +```bash +reme plugins list +reme plugins show auto-fin +reme plugins validate auto-fin +reme plugins install reme-auto-fin +reme plugins uninstall auto-fin +``` + +See [Plugin Management](../plugin_management.md) for the complete workflow. + +## Discover active capabilities + +The [Job API Reference](./jobs.md) describes the default configuration. Plugins and custom YAML may change the running service, so automation should prefer: + +```bash +reme help +reme app_config +``` diff --git a/docs/en/services.md b/docs/en/services.md new file mode 100644 index 00000000..c0be01a0 --- /dev/null +++ b/docs/en/services.md @@ -0,0 +1,115 @@ +--- +title: Services and Deployment +description: Run ReMe through HTTP, SSE, MCP, the CLI, and ReMe Studio while respecting its local security boundary. +--- + +# Services and Deployment + +ReMe can run as a local HTTP service, a standalone MCP server, or a one-shot CLI Job. The default starts HTTP on `127.0.0.1:2333` and serves JSON, SSE, streamable HTTP MCP, and optional ReMe Studio from one process. + +## HTTP API + +```bash +reme start +reme start service.host=127.0.0.1 service.port=8181 +``` + +Regular Jobs become `POST /`: + +```bash +curl -s http://127.0.0.1:2333/search \ + -H 'Content-Type: application/json' \ + -d '{"query":"user preferences","limit":5}' +``` + +Job arguments live at the request body's top level. A regular response follows the `Response` schema: + +```json +{"success": true, "answer": "...", "metadata": {}} +``` + +Unhandled Step failures become unsuccessful responses. + +## Streaming and SSE + +Jobs with `backend: stream` also use `POST /`, returning `text/event-stream`. Error paths emit an error chunk and always terminate the stream. The default `chat` Job is streaming: + +```bash +curl -N http://127.0.0.1:2333/chat \ + -H 'Content-Type: application/json' \ + -d '{"query":"Summarize my long-term preferences"}' +``` + +MCP does not expose Stream Jobs. + +## MCP + +The default HTTP service mounts streamable HTTP MCP at `/mcp`: + +```yaml +service: + backend: http + mcp_enabled: true + mcp_path: /mcp + mcp_stateless_http: false +``` + +For a standalone MCP service: + +```bash +reme start service.backend=mcp service.transport=stdio +reme start service.backend=mcp service.transport=sse service.port=2333 +reme start service.backend=mcp service.transport=streamable-http service.port=2333 +``` + +MCP tools come from non-stream Jobs with `enable_serve: true`. Use `service.jobs` as an allowlist. `injected_job_kwargs` adds server-managed values that callers cannot override. + +```yaml +service: + backend: http + jobs: [search, read, traverse, auto_memory] + injected_job_kwargs: + tenant_id: local-user + tool_error_on_failure: true +``` + +## ReMe Studio + +After installing `reme-ai[web]` or `reme-ai[core]`, the default HTTP origin also serves Studio: + +```text +http://127.0.0.1:2333/ +``` + +Disable it with `service.web_enabled=false` or select a build with `service.web_static_dir`. Missing static assets do not prevent the Job API from starting. + +## One-shot Jobs + +```bash +reme start job=search query="user preferences" limit=5 +``` + +This selects the one-shot CLI Service while retaining the normal Application, Component, and Job lifecycle. + +## Service discovery + +```bash +reme find_reme +``` + +Ordinary `reme ` commands prefer the running service's actual backend, host, port, and transport. They fall back to local configuration only when no service is discovered. + +## Security boundary + +ReMe is local-first: + +- the default binds to `127.0.0.1`; +- HTTP CORS allows any origin; +- Jobs may write, move, or delete files; +- the service layer has no general-purpose user authentication. + +Do not expose the default service directly to the public internet. For remote access, place it on a controlled network or behind an authenticated TLS reverse proxy, apply access controls and request-size limits, and expose only necessary Jobs. + +## OpenAPI + +FastAPI exposes the active endpoints through `/docs`, `/redoc`, and `/openapi.json`. The Studio SPA fallback preserves these reserved paths. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..6ed2b528 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,43 @@ +--- +layout: home +title: ReMe Documentation +titleTemplate: false +head: + - - meta + - http-equiv: refresh + content: "0; url=/zh/" + - - link + - rel: canonical + href: https://reme.agentscope.io/zh/ +hero: + name: ReMe + text: 让 Agent 真正记住 + tagline: 文件属于你,记忆服务于 Agent。ReMe 将对话和资料沉淀为可读、可编辑、可检索、相互链接的本地文件。 + image: + src: /favicon.svg + alt: ReMe + actions: + - theme: brand + text: 快速开始 + link: /zh/quick_start + - theme: alt + text: 核心概念 + link: /zh/memory_as_file +features: + - icon: 📁 + title: Local-first + details: Workspace 文件是持久事实源;索引、图谱和缓存都可以重新构建。 + link: /zh/memory_as_file + - icon: 🧠 + title: Memory workflows + details: 将对话和资料写入 daily,自动整理为互相关联的长期 digest。 + link: /zh/auto_memory + - icon: 🔎 + title: Search and graph + details: 结合关键词、可选向量检索与 wikilink 图谱,渐进式展开上下文。 + link: /zh/memory_search + - icon: 🔌 + title: Agent integrations + details: 通过 CLI、HTTP、MCP 和宿主适配器接入已有 Agent。 + link: /zh/integrations +--- diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg new file mode 100644 index 00000000..aeb6a94e --- /dev/null +++ b/docs/public/favicon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/docs/zh/configuration.md b/docs/zh/configuration.md new file mode 100644 index 00000000..6fdeb191 --- /dev/null +++ b/docs/zh/configuration.md @@ -0,0 +1,168 @@ +--- +title: 基础配置 +description: ReMe 配置文件、环境变量、命令行覆盖和核心组件配置。 +--- + +# 基础配置 + +ReMe 使用 YAML 或 JSON 描述 Service、Job 和 Component。默认配置位于 `reme/config/default.yaml`;启动时可以选择其他配置,再用命令行覆盖其中的字段。 + +## 配置优先级 + +配置按下面的顺序合并,靠后的值优先: + +1. 已启用插件提供的 `application_defaults`。 +2. 选中的配置文件;未指定时使用内置 `default`。 +3. 命令行 dot notation 覆盖。 + +```bash +reme start +reme start config=demo +reme start config=/absolute/path/to/app.yaml +reme start service.port=8181 workspace_dir=/data/reme +``` + +`config` 支持内置配置名以及 `.yaml`、`.yml`、`.json` 文件。覆盖采用深度合并,不会因为修改 `service.port` 而丢失 `service` 下的其他字段。 + +## 值的解析 + +CLI 参数使用 `key=value`,前导 `-` 或 `--` 也会被接受: + +```bash +reme start --service.port=8181 --service.web_enabled=false +``` + +值支持: + +- `null`、布尔值、整数和浮点数; +- JSON 数组和对象; +- JSON 引号字符串; +- 普通字符串。 + +类似 `007` 的前导零字符串不会被转换成数字。需要保留 `true`、`false` 等字面字符串时,使用 JSON 引号:`value='"true"'`。 + +## 环境变量 + +配置文件会递归展开两种表达式: + +```yaml +api_key: ${LLM_API_KEY} +base_url: ${LLM_BASE_URL:-https://example.com/v1} +``` + +`${VAR}` 在变量未定义时会报错;`${VAR:-default}` 使用默认值。ReMe 还会从命令启动目录向上查找 `.env`,最多检查五级父目录。 + +不要把密钥提交到配置文件或 Git。推荐把密钥放在 `.env` 或进程环境中。 + +## Application 字段 + +| 字段 | 默认值 | 作用 | +|---|---|---| +| `app_name` | `ReMe` | 应用显示名称 | +| `workspace_dir` | `.reme` | 用户拥有的 workspace 根目录,会规范化为绝对路径 | +| `metadata_dir` | `metadata` | 索引、图谱和 catalog 等派生状态 | +| `session_dir` | `session` | Agent 对话记录;标准 transcript 位于 `session/dialog` | +| `mem_session_dir` | `mem_session` | Agent wrapper 的会话和配置 | +| `resource_dir` | `resource` | 外部资料 | +| `daily_dir` | `daily` | Daily memory | +| `digest_dir` | `digest` | 长期整理后的记忆 | +| `timezone` | `Asia/Shanghai` | Cron、日期和梦境流程使用的 IANA 时区 | +| `language` | 空 | LLM 交互默认语言 | +| `plugins` | `[]` | 为当前 Application 启用的已安装插件 | +| `service` | HTTP | 服务端配置 | +| `jobs` | 默认 Job | Job 名到 Job 配置的映射 | +| `components` | 默认组件 | 按类型和名称组织的组件配置 | + +`session_dir` 必须保持 workspace-relative。其他 workspace 子目录也应使用清晰、稳定的相对名称。 + +## LLM 配置 + +默认 LLM 使用 OpenAI-compatible 接口: + +```yaml +components: + as_llm: + default: + backend: openai + model: qwen3.7-plus + context_size: 200000 + credential: + api_key: ${LLM_API_KEY:-} + base_url: ${LLM_BASE_URL:-} +``` + +可注册的内置 backend 包括 `openai`、`anthropic`、`dashscope`、`deepseek`、`gemini`、`moonshot`、`ollama` 和 `xai`。实际字段由对应 AgentScope model wrapper 决定。 + +基础文件操作、BM25 检索、wikilink 遍历不需要 LLM。`auto_memory`、`auto_resource`、`auto_dream` 等演化流程需要可用 LLM。 + +## Embedding 配置 + +向量检索默认关闭。只设置 `EMBEDDING_API_KEY` 不会自动启用它;还需要同时启用 `as_embedding`、`embedding_store`,并把它连接到 `file_store`: + +```yaml +components: + as_embedding: + default: + backend: openai + model: text-embedding-v4 + dimensions: 1024 + credential: + api_key: ${EMBEDDING_API_KEY} + base_url: ${EMBEDDING_BASE_URL:-https://dashscope.aliyuncs.com/compatible-mode/v1} + embedding_store: + default: + backend: local + as_embedding: default + file_store: + default: + backend: local + embedding_store: default + keyword_index: default + file_graph: default +``` + +修改 embedding 模型或维度后,应重新构建 embedding 索引。 + +## Service 和 Job + +最小 HTTP 配置: + +```yaml +service: + backend: http + host: 127.0.0.1 + port: 2333 + web_enabled: true + mcp_enabled: true + mcp_path: /mcp +``` + +Job 由 backend、参数 schema 和顺序执行的 Step 组成: + +```yaml +jobs: + example: + backend: base + description: Example job + parameters: + type: object + properties: + text: { type: string } + required: [text] + steps: + - backend: example_step +``` + +设置 `enable_serve: false` 可以保留内部 Job、禁止 Service 暴露。后台和 Cron Job始终不会作为请求端点暴露。 + +## 查看生效配置 + +服务启动后运行: + +```bash +reme app_config +``` + +返回的是已合并、已校验并隐藏密钥后的配置。排查覆盖顺序或插件配置时,应以它为准,而不是只查看某一个 YAML 文件。 + +完整字段定义以 `reme/schema/application_config.py` 和 `reme/config/default.yaml` 为准。 diff --git a/docs/zh/contributing.md b/docs/zh/contributing.md index 2b5c65e0..e2cdbdfc 100644 --- a/docs/zh/contributing.md +++ b/docs/zh/contributing.md @@ -190,6 +190,12 @@ pytest tests/unit/test_reme_cli.py docs/ ``` +用户指南应同时提供 `docs/zh/` 与 `docs/en/` 版本,并在 `docs/.vitepress/config.mts` 的对应导航中注册。ReMe Studio、 +TypeScript、插件和评测的 README 是各自目录中的规范源文件;`github-pages/scripts/generate-content.mjs` 会在构建时镜像它们, +不要编辑 `.generated/` 或 `dist/`。 + +`Job API 参考`由 `reme/config/default.yaml` 自动生成。修改默认 Job 参数时更新 YAML 和测试,不要手工维护生成页。 + 建议文档保持: - 标题明确,直接说明能力或流程。 @@ -197,6 +203,15 @@ docs/ - 涉及路径时使用仓库内真实路径,例如 `reme/config/default.yaml`、`reme/steps/`、`tests/unit/`。 - 涉及默认行为时,以当前代码和 `pyproject.toml`、默认配置为准。 +文档站检查: + +```bash +cd github-pages +npm ci +npm test +npm run build +``` + --- ## 获取帮助 diff --git a/docs/zh/faq.md b/docs/zh/faq.md new file mode 100644 index 00000000..563a93bc --- /dev/null +++ b/docs/zh/faq.md @@ -0,0 +1,75 @@ +--- +title: 常见问题 +description: ReMe 安装、服务、模型、检索、文件和插件问题的快速答案。 +--- + +# 常见问题 + +## 基础文件操作需要模型 API Key 吗? + +不需要。`write`、`read`、`list`、`stat`、BM25 搜索和 wikilink 遍历可以在没有模型凭据时运行。`auto_memory`、`auto_resource` 和 `auto_dream` 需要 LLM。 + +## 为什么配置了 Embedding Key 仍然只有 BM25? + +Embedding 默认未启用。除了凭据,还必须配置 `as_embedding`、`embedding_store`,并让 `file_store.default.embedding_store` 指向该组件。参见[基础配置](./configuration.md#embedding-配置)。 + +## 为什么 `reme reindex` 没有发现新文件? + +`reindex` 只从当前 `file_chunks` 重建 BM25 或 embedding 索引,不扫描 workspace。检查 `index_update_loop` watcher、文件目录、后缀和 `health_check`。 + +## 怎样使用另一个 workspace? + +启动时传入稳定的绝对路径: + +```bash +reme start workspace_dir=/absolute/path/to/memory +``` + +普通 CLI 调用会发现运行服务,不必重复 workspace 参数。 + +## 端口 2333 被占用怎么办? + +不要停止未知监听者。选择另一个端口: + +```bash +reme start service.port=8181 +``` + +然后用 `reme find_reme` 确认发现结果。 + +## 为什么插件安装后仍然没有对应 Job? + +安装只让 distribution 在当前 Python 环境中可见。还需要在应用配置中启用: + +```bash +reme start plugins='["auto-fin"]' +``` + +修改安装或启用状态后需要重启已运行的服务。 + +## 可以直接编辑 workspace 中的 Markdown 吗? + +可以。文件是事实源,watcher 会摄取修改。应保留有效 frontmatter、使用完整 workspace-relative wikilink,并避免同时由多个编辑器无条件覆盖同一文件。 + +## 可以把服务暴露到公网吗? + +默认配置不适合直接公网暴露。服务包含写入和删除 Job,HTTP CORS 宽松,且没有通用认证层。请使用受控网络或带 TLS、认证、访问控制的反向代理,并限制 `service.jobs`。 + +## 怎样备份和迁移? + +停止写入后备份整个 workspace。`session/`、`resource/`、`daily/` 和 `digest/` 是最重要的用户数据;`metadata/` 可以随同备份,也可以从源文件重建。详见[诊断、备份与恢复](./operations.md)。 + +## Studio 找不到怎么办? + +基础 `reme-ai` 包不包含前端资源。安装 `reme-ai[web]` 或 `reme-ai[core]`,或通过 `service.web_static_dir` 指向构建产物。Studio 缺失不会影响 Job API。 + +## 当前服务到底开放了哪些能力? + +运行: + +```bash +reme help +reme app_config +``` + +静态文档描述默认配置;运行服务可能由自定义配置和插件改变。 diff --git a/docs/zh/index.md b/docs/zh/index.md new file mode 100644 index 00000000..f06269c9 --- /dev/null +++ b/docs/zh/index.md @@ -0,0 +1,36 @@ +--- +layout: home +title: ReMe 文档 +titleTemplate: false +hero: + name: ReMe + text: 让 Agent 真正记住 + tagline: 文件属于你,记忆服务于 Agent。ReMe 将对话和资料沉淀为可读、可编辑、可检索、相互链接的本地文件。 + image: + src: /favicon.svg + alt: ReMe + actions: + - theme: brand + text: 快速开始 + link: /zh/quick_start + - theme: alt + text: 查看配置 + link: /zh/configuration +features: + - icon: 📁 + title: 文件即记忆 + details: Workspace 文件是持久事实源;索引、图谱和缓存都可以重新构建。 + link: /zh/memory_as_file + - icon: 🧠 + title: 自动记忆 + details: 将对话和资料写入 daily,自动整理为互相关联的长期 digest。 + link: /zh/auto_memory + - icon: 🔎 + title: 检索与图谱 + details: 结合关键词、可选向量检索与 wikilink 图谱,渐进式展开上下文。 + link: /zh/memory_search + - icon: 🔌 + title: Agent 集成 + details: 通过 CLI、HTTP、MCP 和宿主适配器接入已有 Agent。 + link: /zh/integrations +--- diff --git a/docs/zh/integrations.md b/docs/zh/integrations.md new file mode 100644 index 00000000..ab239c15 --- /dev/null +++ b/docs/zh/integrations.md @@ -0,0 +1,88 @@ +--- +title: Agent 集成 +description: 通过 CLI、HTTP、MCP、Skill 和宿主适配器把 ReMe 接入 Agent。 +--- + +# Agent 集成 + +ReMe 把记忆能力放在独立服务和用户拥有的 workspace 中。Agent 可以通过标准接口调用同一套记忆,而不必把存储逻辑绑定到某一个模型或宿主。 + +## 选择接入方式 + +| 场景 | 推荐方式 | +|---|---| +| 本机脚本或 Hook | ReMe CLI | +| 应用后端 | HTTP Client | +| 支持工具协议的 Agent | MCP | +| TypeScript Agent | `@agentscope-ai/reme` | +| Claude Code | MCP + Skill + Stop Hook | +| Hermes Agent | Memory provider adapter | +| Codex 或其他 coding agent | `reme_memory` Skill 或 MCP | + +## 通用接入循环 + +一个完整但可控的 Agent 记忆循环通常包含: + +1. 会话开始或回答前,用 `search` 找到相关记忆; +2. 对高价值结果使用 `read`,必要时用 `traverse` 展开关系; +3. 在回答中保留 workspace-relative 来源路径; +4. 会话结束后,把原始消息交给 `auto_memory`; +5. 由后台或定时任务把 daily 内容整理到 digest。 + +搜索不到内容时应明确返回空结果,不应把模型推测当成历史记忆。 + +## MCP + +默认 HTTP 服务在 `http://127.0.0.1:2333/mcp` 提供 streamable HTTP MCP。常用工具包括: + +- `search` +- `read` +- `traverse` +- `list` +- `auto_memory` +- `proactive` + +根据宿主风险模型,可以用 `service.jobs` 只暴露只读工具,或将写入工具放在单独配置中。 + +## CLI 和 Skill + +仓库中的 `skills/reme_memory/SKILL.md` 描述了一个通用 Agent 工作流,包括安装检查、服务发现、检索、读取和写入边界。它适合能够执行本地命令的 Agent。 + +Skill 不应: + +- 未经允许安装或升级 Python 环境; +- 发现端口冲突后停止未知进程; +- 把召回的工具结果再次写入对话来源; +- 将密钥或敏感信息写入记忆。 + +## TypeScript、OpenClaw 与 DeepSeek Harness + +统一 TypeScript 客户端和宿主适配器见 [TypeScript Agent 集成](./integrations/typescript.md)。它包含: + +- HTTP Client; +- DeepSeek Harness adapter; +- OpenClaw adapter; +- 构建与发布检查。 + +## Claude Code + +仓库的 `integrations/claude_code/` 提供: + +- streamable HTTP MCP 配置; +- `reme-memory` Skill; +- 会话停止时调用 `auto_memory_cc` 的 Hook。 + +完整安装步骤以仓库中的 `integrations/claude_code/README.md` 为准。 + +## Hermes Agent + +`integrations/hermes_agent/` 提供 memory provider:模型调用前检索相关记忆,每轮结束后异步调用 `auto_memory`。完整配置见该目录 README。 + +## 生产接入建议 + +- 明确选择稳定、绝对的 `workspace_dir`; +- 启动前复用 `reme find_reme` 发现的服务; +- 以 `reme help` 为当前 Job 契约; +- 为写入动作设置超时和失败日志; +- 不因记忆服务暂时不可用而阻塞宿主的核心回答流程; +- 对远程访问使用认证、TLS 和最小 Job allowlist。 diff --git a/docs/zh/integrations/claude-code.md b/docs/zh/integrations/claude-code.md new file mode 100644 index 00000000..17f78ab4 --- /dev/null +++ b/docs/zh/integrations/claude-code.md @@ -0,0 +1,67 @@ +--- +title: Claude Code 集成 +description: 通过 MCP、reme-memory Skill 和 Stop Hook 将 Claude Code 连接到 ReMe。 +--- + +# Claude Code 集成 + +ReMe 的 Claude Code 插件提供长期记忆召回,并在每次会话结束后异步记录对话。Daily 到 digest 的整理仍由共享的 ReMe 服务负责。 + +## 能力 + +- 通过 MCP 使用 `search`、`traverse`、`daily_list`、`frontmatter_read`、`read`、`auto_memory_cc` 等工具; +- `reme-memory` Skill 在回答前召回长期记忆并保留来源路径; +- Stop Hook 只把 Claude Code `session_id` 传给服务端,服务端从本地 transcript 解析会话; +- 记录在脱离 Claude Code 的后台进程中进行,不延迟退出;服务不可用时记录日志并结束。 + +## 部署模型 + +插件连接到用户预先启动的共享 HTTP MCP 服务,不为每个 Claude Code 窗口创建 ReMe。这样所有窗口共享一个 workspace、一组 watcher 和一次 dream cron。 + +## 准备 ReMe + +```bash +pip install "reme-ai[core]" +``` + +在稳定目录配置 LLM 环境,然后启动: + +```bash +reme start service.backend=http +``` + +默认 JSON Job API 和 MCP 地址分别位于同一个 `127.0.0.1:2333` 服务,MCP 路径是 `/mcp`。使用其他端口时,必须同步修改插件的 `.mcp.json`。 + +默认搜索使用 BM25;只有启用向量检索时才需要 Embedding 配置。 + +## 安装插件 + +在 Claude Code 中运行: + +```text +/plugin marketplace add ./integrations/claude_code +/plugin install reme@reme-marketplace +``` + +重启 Claude Code,再运行 `/mcp`,确认 `reme` server 和工具已经连接。 + +## Hook 与路径 + +- MCP 配置:`integrations/claude_code/reme/.mcp.json`; +- 自动记忆 Hook:`integrations/claude_code/reme/hooks/auto_memory.py`; +- Hook 日志:`integrations/claude_code/reme/logs/auto_memory_hook.log`; +- 默认 transcript 根目录:`~/.claude/projects`; +- 可通过 `CLAUDE_CONFIG_DIR` 修改 transcript 根目录; +- 可通过 `REME_HOST`、`REME_PORT` 覆盖 Hook 使用的服务地址。 + +Hook 需要 `python3` 位于 `PATH`。MCP 工具名前缀可能随 Claude Code 版本包含 server segment;Skill 使用 `mcp__reme__*` 匹配这一差异。 + +## 验证 + +1. `reme health_check` 返回健康; +2. Claude Code `/mcp` 显示 ReMe; +3. `reme-memory` 能召回一条已存在记忆; +4. 完成测试会话后,Hook 日志没有错误; +5. 对应内容出现在当天 daily note 中。 + +英文原始部署说明位于 `integrations/claude_code/README.md`。 diff --git a/docs/zh/integrations/hermes.md b/docs/zh/integrations/hermes.md new file mode 100644 index 00000000..2371b1f8 --- /dev/null +++ b/docs/zh/integrations/hermes.md @@ -0,0 +1,59 @@ +--- +title: Hermes Agent 集成 +description: 使用 ReMe memory provider 在 Hermes 调用模型前召回、每轮结束后异步记录。 +--- + +# Hermes Agent 集成 + +Hermes memory provider 连接到一个已经运行的 ReMe HTTP 服务,在每次模型调用前召回相关记忆,并在用户/助手回合完成后异步调用 `auto_memory`。 + +## Workspace 隔离 + +ReMe 的搜索范围是一个完整 workspace。多个 Hermes profile 指向同一个 workspace 时会共享召回结果;需要隔离时,为每个 profile 使用独立 workspace 和端点。 + +```bash +reme start \ + workspace_dir="/absolute/path/to/reme-hermes-default" \ + service.backend=http \ + service.host=127.0.0.1 \ + service.port=2333 +``` + +自动记忆需要 LLM;默认 BM25 搜索不需要 Embedding。 + +## 安装与配置 + +```bash +hermes plugins install agentscope-ai/ReMe/integrations/hermes_agent +hermes memory setup +``` + +选择 `reme`,接受默认的 `http://127.0.0.1:2333`,或输入上一步使用的端点。Setup 会先调用 `health_check`,只有新端点健康时才替换现有 provider 配置。 + +配置存放在 `$HERMES_HOME/reme.json`: + +```json +{ + "endpoint": "http://127.0.0.1:2333", + "request_timeout": 600.0, + "recall_timeout": 5.0, + "health_timeout": 2.0, + "health_retry_seconds": 30.0, + "shutdown_timeout": 30.0, + "recall_limit": 5 +} +``` + +运行 `hermes memory status` 检查安装和配置。新的 Hermes 会话还会重新检查端点健康状态。 + +## 生命周期和失败行为 + +- `prefetch` 调用 ReMe `search`,Hermes 将结果放入受保护的 memory context; +- `sync_turn` 把完成的回合加入串行后台写队列,再调用 `auto_memory`; +- cron、flush 和 subagent context 不写入对话记忆; +- 健康检查失败后,在 cooldown 结束前暂停召回和记录; +- 召回与写入有独立 cooldown,单项失败不会关闭另一项; +- 召回使用较短超时,避免慢搜索长期阻塞模型调用; +- shutdown 会在有限时间内排空写队列,ReMe 服务仍由用户独立管理。 + +英文权威安装说明位于 `integrations/hermes_agent/README.md`。 diff --git a/docs/zh/operations.md b/docs/zh/operations.md new file mode 100644 index 00000000..43e4bcbd --- /dev/null +++ b/docs/zh/operations.md @@ -0,0 +1,106 @@ +--- +title: 诊断、备份与恢复 +description: ReMe 服务健康检查、日志、索引维护、备份迁移和常见恢复流程。 +--- + +# 诊断、备份与恢复 + +ReMe 的恢复原则是:保护 workspace 中的用户文件,通过源文件重建索引、图谱和 catalog。不要为了修复索引而删除或改写用户记忆。 + +## 快速诊断 + +依次执行: + +```bash +reme find_reme +reme version +reme health_check +reme status +reme app_config +``` + +- `find_reme`:服务是否存在,以及实际 host、port、PID; +- `version`:CLI 能否成功访问服务; +- `health_check`:组件健康状态; +- `status`:状态组件的内存估算和进程 RSS; +- `app_config`:隐藏密钥后的实际生效配置。 + +## 日志 + +`log_to_console` 和 `log_to_file` 控制日志目标。排查启动失败时先查看第一条异常,而不是后续客户端连接错误。 + +常见类别: + +| 现象 | 优先检查 | +|---|---| +| CLI 找不到服务 | `reme find_reme`、启动目录、端口和进程状态 | +| 自动记忆失败 | LLM backend、model、API key、base URL | +| 只有 BM25 结果 | embedding 组件是否真正接入 `file_store` | +| 新文件没有进入搜索 | 文件所在目录、后缀、watcher 和 `health_check` | +| Studio 空白但 API 正常 | web extra、静态构建路径和浏览器控制台 | +| 插件安装后不可用 | 当前 Python 解释器、`plugins` 配置、服务重启 | + +## 索引维护 + +```bash +reme reindex scope=all +reme reindex scope=bm25 +reme reindex scope=embedding +``` + +`reindex` 从当前 `file_chunks` 重建 BM25 和/或 embedding 派生索引。它不会扫描 workspace、重新分块或重建 wikilink 图谱。 + +如果问题发生在文件摄取阶段,应先确认后台 watcher 正常运行;不能把 `reindex` 当成通用“重新扫描”命令。 + +Daily 索引页可单独重建: + +```bash +reme daily_reindex date=2026-09-04 +``` + +## 备份 + +停止写入或停止服务后,优先备份整个 workspace。最重要的目录是: + +- `session/`:原始对话来源; +- `resource/`:外部资料; +- `daily/`:每日记忆; +- `digest/`:长期记忆。 + +`metadata/` 包含索引、图谱和 file catalog。一起备份可以加速恢复,但它不是唯一事实源。 + +不要只备份进程目录下偶然生成的 `.reme/`;生产使用应明确设置稳定的绝对 `workspace_dir`。 + +## 迁移 workspace + +1. 停止旧服务,避免迁移期间继续写入。 +2. 复制完整 workspace,并保留文件时间信息。 +3. 使用新的绝对路径启动: + +```bash +reme start workspace_dir=/new/location/reme-memory +``` + +4. 运行 `health_check`、`status` 和一次代表性 `search`。 +5. 如果 embedding 模型或维度发生变化,再重建 embedding 索引。 + +普通 Markdown 和资源文件可以使用版本控制或同步工具;包含敏感对话的 workspace 不应推送到公开仓库。 + +## 从派生状态故障恢复 + +在确认备份可用前,不要删除任何内容。恢复顺序应为: + +1. 保留 `session/`、`resource/`、`daily/` 和 `digest/`; +2. 记录当前配置和组件 backend; +3. 确认故障只发生在 `metadata/`; +4. 将有问题的派生状态移到隔离备份位置; +5. 用同一配置启动 ReMe,让 watcher 从源文件重建; +6. 验证搜索、图谱和 Daily 索引。 + +具体 metadata 文件属于实现细节,不应在自动化脚本里依赖其内部格式。 + +## 并发编辑 + +Studio 或其他编辑器保存完整文件时,应使用 `stat` 返回的 mtime 作为 `save.expected_mtime`。如果文件在打开后被外部修改,保存会失败,从而避免静默覆盖。 + +文件 Job 会校验 workspace containment,并对同一路径加锁。不要绕过这些 Job 直接向不受控制的绝对路径写入。 diff --git a/docs/zh/plugin_development.md b/docs/zh/plugin_development.md new file mode 100644 index 00000000..67a6d10b --- /dev/null +++ b/docs/zh/plugin_development.md @@ -0,0 +1,101 @@ +--- +title: 插件开发 +description: 创建、注册、配置、测试和发布 ReMe 插件。 +--- + +# 插件开发 + +ReMe 插件是一个普通 Python distribution,通过 `reme.plugins` entry-point group 暴露 package-level `plugin.yaml`。插件可以注册新的 Step、Component backend,并提供默认 Application 配置。 + +## 最小结构 + +```text +my-plugin/ +├── pyproject.toml +└── src/my_plugin/ + ├── __init__.py + ├── plugin.yaml + └── steps.py +``` + +`pyproject.toml`: + +```toml +[project.entry-points."reme.plugins"] +my-plugin = "my_plugin" +``` + +`plugin.yaml`: + +```yaml +name: my-plugin +backends: + my_step: my_plugin.steps:MyStep +application_defaults: + jobs: + my_action: + backend: base + description: Run my plugin action + parameters: + type: object + properties: + text: { type: string } + required: [text] + steps: + - backend: my_step +``` + +## 实现 Step + +```python +from reme.components.component_registry import R +from reme.steps.base_step import BaseStep + + +@R.register("my_step") +class MyStep(BaseStep): + async def execute(self): + self.context.response.answer = self.context.data["text"] +``` + +Step 实例属于单次 Job 调用。跨调用的内存状态应放在带命名空间的 `app_context.metadata`;需要生命周期、锁或持久化时,应升级为 Component 或 workspace 文件。 + +## 配置合并 + +`application_defaults` 是不完整的 `ApplicationConfig`。合并顺序为: + +```text +插件默认值 < 选中/default 配置 < CLI 覆盖 +``` + +插件不应自动修改用户的配置文件。只有在 Application 的 `plugins` 列表中显式启用后,插件 backend 才会加入该 Application 的局部 registry。 + +## 本地验证 + +```bash +reme plugins validate ./path/to/my-plugin +reme plugins install ./path/to/my-plugin --editable +reme plugins list +reme plugins show my-plugin +reme start plugins='["my-plugin"]' +reme my_action text=hello +``` + +校验会导入插件代码,因此只应对可信源码执行。 + +## 测试边界 + +- 使用 `tmp_path` 创建 workspace; +- Mock 网络、模型和子进程; +- 验证插件未启用时不会污染 built-in registry; +- 验证默认配置与显式配置的合并优先级; +- 验证后台任务、客户端和 executor 都由 Component 生命周期关闭; +- 验证失败不会删除或重写用户源文件。 + +仓库中的 `plugins/daily_paper`、`plugins/auto-fin`、`plugins/lme` 和 `plugins/beam` 是完整参考实现。 + +## 兼容性 + +迁移期间仍兼容旧的 Python Plugin descriptor 和 `reme.configs` entry point,但新插件应使用 `plugin.yaml`。不要依赖进程级全局 enable/disable 状态;插件启用始终属于具体 Application 配置。 + +包管理命令、升级与卸载行为见[插件管理](./plugin_management.md)。 diff --git a/docs/zh/quick_start.md b/docs/zh/quick_start.md index ee41626a..d7f7a43c 100644 --- a/docs/zh/quick_start.md +++ b/docs/zh/quick_start.md @@ -1,5 +1,12 @@ +--- +title: 快速开始 +description: 安装并启动 ReMe,完成文件写入、检索和自动记忆的第一个闭环。 +--- + # 快速开始 +本页用于完成第一次可运行闭环。需要完整配置字段时查看[基础配置](./configuration.md);接入 HTTP 或 MCP 时查看[服务与部署](./services.md)。 + ## 安装 ReMe 要求 Python 3.11+。 @@ -228,3 +235,5 @@ reme start \ ```bash reme start config=/path/to/custom.yaml ``` + +下一步可以查看 [CLI 参考](./reference/cli.md)、[Job API 参考](./reference/jobs.md)和[诊断、备份与恢复](./operations.md)。 diff --git a/docs/zh/reference/cli.md b/docs/zh/reference/cli.md new file mode 100644 index 00000000..3caa7cde --- /dev/null +++ b/docs/zh/reference/cli.md @@ -0,0 +1,87 @@ +--- +title: CLI 参考 +description: ReMe 命令行语法、服务调用、配置覆盖与插件命令。 +--- + +# CLI 参考 + +ReMe 的基本语法是: + +```text +reme ACTION key=value ... +``` + +## 启动应用 + +```bash +reme start +reme start config=demo +reme start workspace_dir=/data/reme service.port=8181 +reme start job=search query="关键词" limit=5 +``` + +`start job=` 运行一次性 Job;普通 `start` 启动配置中的 Service。 + +## 调用 Job + +服务运行后,Action 名就是 Job 名: + +```bash +reme help +reme health_check +reme search query="项目决策" limit=10 +reme read path=digest/wiki/project.md start_line=1 end_line=80 +``` + +复杂值使用 JSON: + +```bash +reme auto_memory \ + session_id=example \ + messages='[{"role":"user","content":"记住这条偏好"}]' +``` + +服务选择参数 `backend`、`transport`、`host`、`port`、`timeout`、`command`、`args` 和 `show_metadata` 只用于构造客户端,不会泄漏到 Job 参数。 + +## 配置覆盖 + +```bash +reme start \ + config=/path/to/custom.yaml \ + service.port=8181 \ + service.web_enabled=false \ + plugins='["auto-fin"]' +``` + +参数前的 `-` 或 `--` 可以省略。嵌套键使用点号,数组和对象使用 JSON。 + +## 服务发现 + +```bash +reme find_reme +``` + +成功时输出可复用的服务信息;找不到服务时不会自动启动新进程。 + +## 插件命令 + +插件包管理是本地命令,不经过 HTTP 或 MCP: + +```bash +reme plugins list +reme plugins show auto-fin +reme plugins validate auto-fin +reme plugins install reme-auto-fin +reme plugins uninstall auto-fin +``` + +完整说明见[插件管理](../plugin_management.md)。 + +## 发现当前能力 + +默认 Job 参数见 [Job API 参考](./jobs.md)。运行配置可能由插件和自定义 YAML 改变,因此自动化程序应优先调用: + +```bash +reme help +reme app_config +``` diff --git a/docs/zh/services.md b/docs/zh/services.md new file mode 100644 index 00000000..9cfea053 --- /dev/null +++ b/docs/zh/services.md @@ -0,0 +1,131 @@ +--- +title: 服务与部署 +description: 使用 ReMe 的 HTTP、SSE、MCP 和 Studio 服务,并理解默认安全边界。 +--- + +# 服务与部署 + +ReMe 可以作为本地 HTTP 服务、独立 MCP Server 或一次性 CLI Job 运行。默认模式是在 `127.0.0.1:2333` 启动 HTTP 服务,并在同一进程中提供 JSON API、SSE、MCP 与可选的 ReMe Studio。 + +## HTTP 服务 + +```bash +reme start +reme start service.host=127.0.0.1 service.port=8181 +``` + +普通 Job 暴露为 `POST /`: + +```bash +curl -s http://127.0.0.1:2333/search \ + -H 'Content-Type: application/json' \ + -d '{"query":"用户偏好","limit":5}' +``` + +请求体允许 Job 参数位于顶层。响应遵循 `Response`: + +```json +{ + "success": true, + "answer": "...", + "metadata": {} +} +``` + +未被 Step 捕获的错误会转换成 `success: false` 的响应。 + +## Streaming 与 SSE + +`backend: stream` 的 Job 仍使用 `POST /`,但响应类型是 `text/event-stream`。每个 chunk 使用统一的 streaming schema;失败时会发出错误 chunk,并以终止事件结束。 + +默认 `chat` 是 Stream Job: + +```bash +curl -N http://127.0.0.1:2333/chat \ + -H 'Content-Type: application/json' \ + -d '{"query":"总结我的长期偏好"}' +``` + +MCP 不暴露 Stream Job。 + +## MCP + +默认 HTTP 服务会在 `/mcp` 挂载 streamable HTTP MCP: + +```yaml +service: + backend: http + mcp_enabled: true + mcp_path: /mcp + mcp_stateless_http: false +``` + +也可以改用独立 MCP Service: + +```bash +reme start service.backend=mcp service.transport=stdio +reme start service.backend=mcp service.transport=sse service.port=2333 +reme start service.backend=mcp service.transport=streamable-http service.port=2333 +``` + +MCP tool 来自 `enable_serve: true` 的非流式 Job。`service.jobs` 可以设置允许列表;`injected_job_kwargs` 可以注入服务端管理、调用方不能覆盖的参数。 + +```yaml +service: + backend: http + jobs: [search, read, traverse, auto_memory] + injected_job_kwargs: + tenant_id: local-user + tool_error_on_failure: true +``` + +## ReMe Studio + +安装 `reme-ai[web]` 或 `reme-ai[core]` 后,默认 HTTP 地址同时提供 ReMe Studio: + +```text +http://127.0.0.1:2333/ +``` + +可通过配置关闭或指定自定义构建: + +```yaml +service: + web_enabled: false + # web_static_dir: /absolute/path/to/static +``` + +静态资源缺失不会阻止 Job API 启动。 + +## 一次性 Job + +需要脚本式执行而不常驻服务时: + +```bash +reme start job=search query="用户偏好" limit=5 +``` + +它会切换到一次性 CLI Service,但仍经过正常的 Application、Component 和 Job 生命周期。 + +## 服务发现 + +```bash +reme find_reme +``` + +ReMe 会记录本机运行服务的启动参数。普通 `reme ` 优先使用实际运行服务的 backend、host、port 和 transport;找不到运行服务时才回退到本地配置。 + +## 安全边界 + +ReMe 默认定位为本地服务: + +- 默认绑定 `127.0.0.1`; +- HTTP CORS 配置允许任意 origin; +- Job 可进行文件写入、移动和删除; +- 当前服务层不提供通用用户认证。 + +不要直接把默认服务暴露到公网。需要远程访问时,在受控网络或带身份认证、TLS、访问控制和请求大小限制的反向代理后部署,并通过 `service.jobs` 只开放必要 Job。 + +## OpenAPI + +HTTP 服务使用 FastAPI。启用 HTTP 服务时,可以通过 `/docs`、`/redoc` 和 `/openapi.json` 查看当前配置实际注册的端点;Studio 的 SPA fallback 不会覆盖这些保留路径。 diff --git a/github-pages/README.md b/github-pages/README.md index 2be3e6a4..c4b09810 100644 --- a/github-pages/README.md +++ b/github-pages/README.md @@ -1,8 +1,8 @@ -# ReMe GitHub Pages +# ReMe documentation site -This directory contains the standalone Vite documentation site published at . The -GitHub Pages fallback is . It does not depend on the ReMe Studio application in -`reme_studio/`. +This package builds the VitePress site published at . The canonical documentation lives in +`docs/`; selected product, integration, plugin, and benchmark READMEs are mirrored into a disposable source tree during +the build. Do not edit `.generated/` or `dist/`. ## Requirements @@ -11,79 +11,41 @@ GitHub Pages fallback is . It does not de ## Local development -From the repository root: - ```bash cd github-pages -npm install +npm ci npm run dev ``` -Open the URL printed by Vite, normally . The development server watches the frontend source. -When a repository Markdown file changes, restart the development command to regenerate the documentation content. +The development server prints its local URL. Restart it after changing a mirrored README or `reme/config/default.yaml` +so the generated source tree and Job reference are refreshed. Changes under `docs/` are also refreshed on restart. -For subsequent installs or CI-compatible dependency installation, use: - -```bash -npm ci -``` - -## Preview the production build - -Build and start the preview server: +## Validation ```bash +npm test npm run build npm run preview ``` -Open the URL printed by Vite, normally . Production assets use relative paths so the same build -works on both the custom domain and the GitHub Pages project path. +The test suite verifies bilingual core pages, canonical-source mappings, generated Job coverage, and disposable output. +The production build is written to `github-pages/dist/` for the existing GitHub Pages workflow. -The generated `dist/` and `.generated/` directories are disposable build output and are excluded from Git. +## Sources -## Documentation sources - -The build script reads the canonical repository files directly. Do not edit generated copies under `.generated/` or -`dist/`. - -- `README.md` and `README_ZH.md`: project introductions -- `docs/en/` and `docs/zh/`: English and Chinese guides -- `docs/figure/`: documentation images -- `reme_studio/README.md` and `reme_studio/README_ZH.md`: ReMe Studio guide -- `typescript/README.md` and `typescript/README_ZH.md`: TypeScript client, DeepSeek Harness, and OpenClaw integration guide +- `docs/`: canonical guides, VitePress configuration, theme, and brand assets +- `reme/config/default.yaml`: generated callable Job reference +- `reme_studio/README*.md`: ReMe Studio +- `typescript/README*.md`: TypeScript client and adapters - `plugins/*/README*.md`: plugin guides -- `benchmark/{beam,longmemeval,pibench,toolmemory}/README*.md`: benchmark guides and results -- `AGENTS.md`: repository development guide +- `benchmark/*/README*.md`: benchmark guides +- `scripts/generate-content.mjs`: source mirroring and reference generation -To add or reorganize a document in the site navigation, update -[`scripts/generate-content.mjs`](./scripts/generate-content.mjs). Presentation and interaction code lives in `src/`. - -## Project structure - -```text -github-pages/ -├── index.html -├── package.json -├── scripts/ -│ └── generate-content.mjs -├── src/ -│ ├── main.js -│ └── styles.css -└── vite.config.js -``` +When adding a canonical guide, add both `docs/zh/.md` and `docs/en/.md`, then include it in the appropriate +sidebar in `docs/.vitepress/config.mts`. Add repository-owned READMEs to `externalDocuments` in the generator rather than +duplicating their full content under `docs/`. ## Deployment -The repository workflow `.github/workflows/deploy-docs.yml` builds this directory and publishes `dist/` to GitHub Pages. -It runs after relevant documentation or site files change on `main`, and it can also be started manually from the -GitHub Actions page. - -The repository's **Settings → Pages → Build and deployment → Source** must be set to **GitHub Actions**. Its custom -domain must be set to `reme.agentscope.io`; `public/CNAME` preserves that domain in the published artifact. - -Useful links: - -- ReMe documentation: -- GitHub Pages fallback: -- ReMe repository: +`.github/workflows/deploy-docs.yml` uses the reusable documentation build workflow and publishes `dist/` to GitHub +Pages. `public/CNAME` preserves the `reme.agentscope.io` custom domain. diff --git a/github-pages/index.html b/github-pages/index.html deleted file mode 100644 index 3655d5ee..00000000 --- a/github-pages/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - ReMe Documentation - - -
- - - diff --git a/github-pages/package-lock.json b/github-pages/package-lock.json index 726cc77f..48930a39 100644 --- a/github-pages/package-lock.json +++ b/github-pages/package-lock.json @@ -7,21 +7,377 @@ "": { "name": "reme-github-pages", "version": "0.1.0", - "dependencies": { - "dompurify": "^3.2.6", - "marked": "^16.2.1" - }, "devDependencies": { - "vite": "^7.1.1" + "vitepress": "1.6.4", + "yaml": "^2.8.1" }, "engines": { "node": ">=22.13.0" } }, + "node_modules/@algolia/abtesting": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.23.0.tgz", + "integrity": "sha512-j45MBISstltys9QyQ4xf6quRiN1g7vMuwQL9VM4dx8YuRZvCQ173b9royZAx6iAbRX3IB1VnG1z//NuwyQ8jpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.57.0.tgz", + "integrity": "sha512-JVFFujiZUCguk5tz3LZr4fTQxqpIrj4/Jw3SI7kMljSqtfLxYn/s/TWH0J2s4iNfsDpxPhgFGMotCpmDI4kZ8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.57.0.tgz", + "integrity": "sha512-6KqECK4ED3JJQEoDrQWnGPQzElA828xAD4qK5ceawNNyP/LcSvzAoLHjFkoTPksZ/kxj6VUtCRH+IHZesLltng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.57.0.tgz", + "integrity": "sha512-uqpGF3oXYsoCbQq5d7BzNrNTfIfuvJyGP1CKvSW27T9boUg7KOwyxsAw1AX0a3jSW2HrYEJ/NN+Z4MiGivbpeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.57.0.tgz", + "integrity": "sha512-u5NboJVJXDEFplvNnqqX4CxkXPYysjJRj47hOSh9329H8kG5gFLKJBIiS5utMQ+GZm8xQl3Te7NInDk6elEADQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.57.0.tgz", + "integrity": "sha512-uzc0b2LmHAK9/QID4xeo35OG84AkZl4YewkCqawqAOGLjT2eZpM/OZx45ESygMHG30Ws+ZTSdluPtMJcUnrbWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.57.0.tgz", + "integrity": "sha512-dIAhnM6ue/ssa5PjgNfu4g8A4yTojl9ZOUzZU3wIaIKRerL2R/3Emuf9n/D6ICXXP167KC6XCeC7nliSw7cuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.57.0.tgz", + "integrity": "sha512-2TTPTTKSJmCptvhCm4Xf3bBYMqZni+Pgc2hVdqc4l9wsBpSJNVTVIKpnd10OubUgkGcmppVDj1XQqYaf6EnPSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.57.0.tgz", + "integrity": "sha512-W4JseHKt+pzOxlFV+T3MWEG0h4Z2Se5zjoXUD0ewlw8aOWMG/yjRdopUdLQsXULepB/My2tDuZjkwk2sMfsUrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.57.0.tgz", + "integrity": "sha512-BrxJVE0/eLinEPICCD7BKN/2xnt0nkjge70u8zzE2ISP3fuB3tjLgcwpanUycvlHBFLI4gK0l5ol54p6IYuR/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.57.0.tgz", + "integrity": "sha512-Gc29jkeiLKlVfHvyrIgyUHHE+aYTdXEeLfK42rjr5/1TTVsYwUJz0XkvoIBIqfMjcDg6gXeHb1jTUZ0H+SYIlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.57.0.tgz", + "integrity": "sha512-PIPnPN7MP3fp2VAi01BVXhCWmD366ZB2Hkq5TlYKtThd4KxUtMmaaNDpFgVCTXtSIqWVZLJntOHRvxg/sIPd8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.57.0.tgz", + "integrity": "sha512-AX3RlOudXMdTwtwUqdAf5hAVLvXfOZZH1FZh6ALDdrhVLT0TtAIe48N6nYcWcTnwoTxK/wDIQqZ19IMjK8zJAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.57.0.tgz", + "integrity": "sha512-cWZc1dKb7wy9/wPpwMtL1y89gK2G7y2A47Coa7zwf1ydtIeJm4+S+XxoQ2b/ZRiQnrC1YHavLjYUPDCdnT7Khg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", - "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -32,13 +388,13 @@ "aix" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", - "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -49,13 +405,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", - "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -66,13 +422,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", - "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -83,13 +439,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", - "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -100,13 +456,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", - "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -117,13 +473,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", - "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -134,13 +490,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", - "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -151,13 +507,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", - "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -168,13 +524,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", - "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -185,13 +541,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", - "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -202,13 +558,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", - "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -219,13 +575,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", - "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -236,13 +592,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", - "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -253,13 +609,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", - "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -270,13 +626,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", - "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -287,13 +643,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", - "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -304,30 +660,13 @@ "linux" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", - "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", - "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -338,30 +677,13 @@ "netbsd" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", - "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", - "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -372,30 +694,13 @@ "openbsd" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", - "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", - "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -406,13 +711,13 @@ "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", - "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -423,13 +728,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", - "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -440,13 +745,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", - "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -457,9 +762,33 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.94", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.94.tgz", + "integrity": "sha512-l8UWzVxKaqZd9ABsE/M/9p6NyGkQnmCnOoZyhQmjlXCtY5PuL2rcWxOFk2l9pk7ux3ERMPkTLE4jl6kQpTkwxA==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@napi-rs/lzma-linux-x64-gnu": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", @@ -827,6 +1156,93 @@ "win32" ] }, + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -834,26 +1250,483 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "dev": true, "license": "MIT", - "optional": true + "dependencies": { + "@types/unist": "*" + } }, - "node_modules/dompurify": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz", - "integrity": "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-NoQ2yGlLWj4wpxMs+TYmRKk3thDrQ97agr7sFqfLsAlvoS8SNQuTrlObhFqG9iugdTtgOE9jpJ6FNM4ZGsa5xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.42.tgz", + "integrity": "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.42", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz", + "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.42.tgz", + "integrity": "sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/compiler-core": "3.5.42", + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-ssr": "3.5.42", + "@vue/shared": "3.5.42", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.19", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.42.tgz", + "integrity": "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz", + "integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.10" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz", + "integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.10", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz", + "integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.42.tgz", + "integrity": "sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.42.tgz", + "integrity": "sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.42.tgz", + "integrity": "sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.42", + "@vue/runtime-core": "3.5.42", + "@vue/shared": "3.5.42", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.42.tgz", + "integrity": "sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.42.tgz", + "integrity": "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/algoliasearch": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.57.0.tgz", + "integrity": "sha512-HpND7MBGctOAkd1GoQoDZCGoCpqNTS5NG1LuhElFet3RdLJkwnyTYZXZhXwtpAQPrI36fqQ3eT6KQrdKDTKu3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.23.0", + "@algolia/client-abtesting": "5.57.0", + "@algolia/client-analytics": "5.57.0", + "@algolia/client-common": "5.57.0", + "@algolia/client-insights": "5.57.0", + "@algolia/client-personalization": "5.57.0", + "@algolia/client-query-suggestions": "5.57.0", + "@algolia/client-search": "5.57.0", + "@algolia/ingestion": "1.57.0", + "@algolia/monitoring": "1.57.0", + "@algolia/recommend": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/copy-anything": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.1.0.tgz", + "integrity": "sha512-ufbM3smX/Jbnpk5wcQjzd1MgBpzmqfNETUAyZNrGwU9foRlyHoGzMMBBCRzEhQLBjZfFDE1W2ufPXX2vdWkV8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/esbuild": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", - "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -861,53 +1734,49 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18" + "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.2", - "@esbuild/android-arm": "0.28.2", - "@esbuild/android-arm64": "0.28.2", - "@esbuild/android-x64": "0.28.2", - "@esbuild/darwin-arm64": "0.28.2", - "@esbuild/darwin-x64": "0.28.2", - "@esbuild/freebsd-arm64": "0.28.2", - "@esbuild/freebsd-x64": "0.28.2", - "@esbuild/linux-arm": "0.28.2", - "@esbuild/linux-arm64": "0.28.2", - "@esbuild/linux-ia32": "0.28.2", - "@esbuild/linux-loong64": "0.28.2", - "@esbuild/linux-mips64el": "0.28.2", - "@esbuild/linux-ppc64": "0.28.2", - "@esbuild/linux-riscv64": "0.28.2", - "@esbuild/linux-s390x": "0.28.2", - "@esbuild/linux-x64": "0.28.2", - "@esbuild/netbsd-arm64": "0.28.2", - "@esbuild/netbsd-x64": "0.28.2", - "@esbuild/openbsd-arm64": "0.28.2", - "@esbuild/openbsd-x64": "0.28.2", - "@esbuild/openharmony-arm64": "0.28.2", - "@esbuild/sunos-x64": "0.28.2", - "@esbuild/win32-arm64": "0.28.2", - "@esbuild/win32-ia32": "0.28.2", - "@esbuild/win32-x64": "0.28.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "dependencies": { + "tabbable": "^6.4.0" } }, "node_modules/fsevents": { @@ -925,18 +1794,209 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/marked": { - "version": "16.4.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", - "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, "license": "MIT", - "bin": { - "marked": "bin/marked.js" + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" }, - "engines": { - "node": ">= 20" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.18", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", @@ -956,6 +2016,25 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -963,19 +2042,6 @@ "dev": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", @@ -1005,6 +2071,70 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/preact": { + "version": "10.29.8", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz", + "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rollup": { "version": "4.62.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", @@ -1051,6 +2181,31 @@ "fsevents": "~2.3.2" } }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1061,42 +2216,192 @@ "node": ">=0.10.0" } }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tabbable": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz", + "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/vite": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", - "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0 || ^0.28.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -1105,25 +2410,19 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, - "jiti": { - "optional": true - }, "less": { "optional": true }, @@ -1144,14 +2443,99 @@ }, "terser": { "optional": true - }, - "tsx": { + } + } + }, + "node_modules/vitepress": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz", + "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { "optional": true }, - "yaml": { + "postcss": { "optional": true } } + }, + "node_modules/vue": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.42.tgz", + "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-sfc": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/server-renderer": "3.5.42", + "@vue/shared": "3.5.42" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/github-pages/package.json b/github-pages/package.json index 4ace932f..a9a0eb6d 100644 --- a/github-pages/package.json +++ b/github-pages/package.json @@ -7,16 +7,14 @@ "node": ">=22.13.0" }, "scripts": { - "dev": "node scripts/generate-content.mjs && vite", - "build": "node scripts/generate-content.mjs && vite build", - "preview": "vite preview", - "test": "node scripts/generate-content.mjs && node --test tests/*.test.mjs" - }, - "dependencies": { - "dompurify": "^3.2.6", - "marked": "^16.2.1" + "content": "node scripts/generate-content.mjs", + "dev": "npm run content && vitepress dev .generated/site", + "build": "npm run content && vitepress build .generated/site --outDir dist && node scripts/verify-build.mjs", + "preview": "vitepress preview .generated/site --outDir dist", + "test": "npm run content && node --test tests/*.test.mjs" }, "devDependencies": { - "vite": "^7.1.1" + "vitepress": "1.6.4", + "yaml": "^2.8.1" } } diff --git a/github-pages/scripts/generate-content.mjs b/github-pages/scripts/generate-content.mjs index 05054730..1a01f1f5 100644 --- a/github-pages/scripts/generate-content.mjs +++ b/github-pages/scripts/generate-content.mjs @@ -1,249 +1,191 @@ import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; +import { parse as parseYaml } from "yaml"; const siteDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const repoDir = path.resolve(siteDir, ".."); -const outputDir = path.join(siteDir, ".generated", "content"); +const outputDir = path.join(siteDir, ".generated", "site"); -const navigationGroupOrder = [ - "overview", - "start", - "integration", - "fundamentals", - "automation", - "concepts", - "workspace", - "plugins", - "benchmarks", - "development", +const externalDocuments = [ + ["en/integrations/claude-code.md", "integrations/claude_code/README.md"], + ["en/integrations/hermes.md", "integrations/hermes_agent/README.md"], + ["zh/integrations/typescript.md", "typescript/README_ZH.md"], + ["en/integrations/typescript.md", "typescript/README.md"], + ["zh/workspace/studio.md", "reme_studio/README_ZH.md"], + ["en/workspace/studio.md", "reme_studio/README.md"], + ["zh/plugins/daily-paper.md", "plugins/daily_paper/README_ZH.md"], + ["en/plugins/daily-paper.md", "plugins/daily_paper/README.md"], + ["zh/plugins/auto-fin.md", "plugins/auto-fin/README_ZH.md"], + ["en/plugins/auto-fin.md", "plugins/auto-fin/README.md"], + ["zh/plugins/lme.md", "plugins/lme/README_ZH.md"], + ["en/plugins/lme.md", "plugins/lme/README.md"], + ["zh/plugins/beam.md", "plugins/beam/README_ZH.md"], + ["en/plugins/beam.md", "plugins/beam/README.md"], + ["zh/benchmarks/beam.md", "benchmark/beam/README_ZH.md"], + ["en/benchmarks/beam.md", "benchmark/beam/README.md"], + ["zh/benchmarks/longmemeval.md", "benchmark/longmemeval/README_ZH.md"], + ["en/benchmarks/longmemeval.md", "benchmark/longmemeval/README.md"], + ["zh/benchmarks/pibench.md", "benchmark/pibench/README_ZH.md"], + ["en/benchmarks/pibench.md", "benchmark/pibench/README.md"], + ["zh/benchmarks/toolmemory.md", "benchmark/toolmemory/README_ZH.md"], + ["en/benchmarks/toolmemory.md", "benchmark/toolmemory/README.md"], ]; -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 groupNames = { + zh: { + system: "系统与诊断", + memory: "记忆演化", + retrieval: "检索与图谱", + daily: "Daily Note", + files: "文件操作", + }, + en: { + system: "System and diagnostics", + memory: "Memory evolution", + retrieval: "Retrieval and graph", + daily: "Daily notes", + files: "File operations", + }, }; -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 jobGroups = { + version: "system", + app_config: "system", + chat: "system", + health_check: "system", + status: "system", + help: "system", + auto_dream: "memory", + auto_memory: "memory", + auto_memory_cc: "memory", + auto_resource: "memory", + proactive: "memory", + traverse: "retrieval", + graph_snapshot: "retrieval", + reindex: "retrieval", + search: "retrieval", + node_search: "retrieval", + daily_list: "daily", + daily_reindex: "daily", + daily_write: "daily", + frontmatter_delete: "files", + frontmatter_read: "files", + frontmatter_update: "files", + stat: "files", + list: "files", + move: "files", + delete: "files", + read: "files", + load: "files", + read_image: "files", + write: "files", + save: "files", + edit: "files", }; -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"); +function typeLabel(schema = {}) { + if (schema.oneOf) return schema.oneOf.map(typeLabel).join(" or "); + if (schema.type === "array") return `${typeLabel(schema.items || {})}[]`; + return schema.type || "any"; } -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", - }, - ]; +function markdownCell(value) { + if (value === undefined) return "—"; + const rendered = typeof value === "string" ? value : JSON.stringify(value); + return rendered + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll("|", "\\|") + .replaceAll("\n", " "); +} - 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, - }); - } +function buildJobReference(config, language) { + const isZh = language === "zh"; + const jobs = Object.entries(config.jobs || {}).filter(([, job]) => !["background", "cron"].includes(job.backend)); + const sections = new Map(); - 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, - }); - } + for (const [name, job] of jobs) { + const group = jobGroups[name] || "system"; + if (!sections.has(group)) sections.set(group, []); + sections.get(group).push([name, job]); } - return [...documents, ...sharedDocuments].sort( - (left, right) => navigationGroupOrder.indexOf(left.group) - navigationGroupOrder.indexOf(right.group), - ); + const lines = [ + "---", + `title: ${isZh ? "Job API 参考" : "Job API Reference"}`, + `description: ${isZh ? "从默认配置自动生成的可调用 Job、参数和服务边界。" : "Callable jobs, parameters, and service boundaries generated from the default configuration."}`, + "---", + "", + `# ${isZh ? "Job API 参考" : "Job API Reference"}`, + "", + isZh + ? "本页从 `reme/config/default.yaml` 自动生成。它描述默认应用中的可调用 Job;插件和自定义配置可以增加、删除或覆盖 Job。运行 `reme help` 可查看当前服务的实际能力。" + : "This page is generated from `reme/config/default.yaml`. It describes callable jobs in the default application; plugins and custom configurations may add, remove, or override jobs. Run `reme help` to inspect the active service.", + "", + isZh + ? "> 后台 Job 和 Cron Job 不通过服务暴露,因此不列入调用参考。" + : "> Background and cron jobs are not service-exposed and are omitted from the callable reference.", + "", + ]; + + for (const [group, entries] of sections) { + lines.push(`## ${groupNames[language][group]}`, ""); + for (const [name, job] of entries) { + const properties = job.parameters?.properties || {}; + const required = new Set(job.parameters?.required || []); + lines.push(`### \`${name}\``, "", markdownCell(job.description || ""), ""); + lines.push("```bash", `reme ${name}${Object.keys(properties).length ? " ..." : ""}`, "```", ""); + if (!Object.keys(properties).length) { + lines.push(isZh ? "无参数。" : "No parameters.", ""); + continue; + } + lines.push( + isZh + ? "| 参数 | 类型 | 必填 | 默认值 | 说明 |" + : "| Parameter | Type | Required | Default | Description |", + "|---|---|---:|---|---|", + ); + for (const [parameter, schema] of Object.entries(properties)) { + lines.push( + `| \`${parameter}\` | \`${markdownCell(typeLabel(schema))}\` | ${required.has(parameter) ? (isZh ? "是" : "yes") : (isZh ? "否" : "no")} | ${markdownCell(schema.default)} | ${markdownCell(schema.description || "—")} |`, + ); + } + lines.push(""); + } + } + return `${lines.join("\n")}\n`; } 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"), { +await cp(path.join(repoDir, "docs"), outputDir, { recursive: true, - filter: (source) => path.basename(source) !== ".DS_Store", + filter: (source) => ![".DS_Store", "plans"].includes(path.basename(source)), }); -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 cp(path.join(siteDir, "public", "CNAME"), path.join(outputDir, "public", "CNAME")); + +const sourceMap = {}; +for (const [destination, source] of externalDocuments) { + const destinationPath = path.join(outputDir, destination); + await mkdir(path.dirname(destinationPath), { recursive: true }); + await cp(path.join(repoDir, source), destinationPath); + sourceMap[destination] = source; } -await writeFile( - path.join(outputDir, "manifest.json"), - `${JSON.stringify({ documents: await buildManifest() }, null, 2)}\n`, -); + +for (const language of ["zh", "en"]) { + await cp( + path.join(repoDir, "benchmark/toolmemory/gitcha.png"), + path.join(outputDir, language, "benchmarks", "gitcha.png"), + ); +} + +const defaultConfig = parseYaml(await readFile(path.join(repoDir, "reme/config/default.yaml"), "utf8")); +for (const language of ["zh", "en"]) { + const destination = path.join(outputDir, language, "reference", "jobs.md"); + await mkdir(path.dirname(destination), { recursive: true }); + await writeFile(destination, buildJobReference(defaultConfig, language)); + sourceMap[`${language}/reference/jobs.md`] = "reme/config/default.yaml"; +} + +await writeFile(path.join(outputDir, ".source-map.json"), `${JSON.stringify(sourceMap, null, 2)}\n`); diff --git a/github-pages/scripts/verify-build.mjs b/github-pages/scripts/verify-build.mjs new file mode 100644 index 00000000..cdf6df72 --- /dev/null +++ b/github-pages/scripts/verify-build.mjs @@ -0,0 +1,91 @@ +import assert from "node:assert/strict"; +import { access, readFile, readdir } 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 outputDir = path.join(siteDir, "dist"); + +async function collectFiles(directory, prefix = "") { + const files = []; + for (const entry of await readdir(directory, { withFileTypes: true })) { + const relativePath = path.posix.join(prefix, entry.name); + if (entry.isDirectory()) files.push(...await collectFiles(path.join(directory, entry.name), relativePath)); + else files.push(relativePath); + } + return files; +} + +function pageUrl(relativePath) { + if (relativePath === "index.html") return "/"; + if (relativePath.endsWith("/index.html")) return `/${relativePath.slice(0, -"index.html".length)}`; + return `/${relativePath.slice(0, -".html".length)}`; +} + +function routeExists(pathname, files) { + const relativePath = decodeURIComponent(pathname).replace(/^\/+/, ""); + if (!relativePath) return files.has("index.html"); + if (relativePath.endsWith("/")) return files.has(`${relativePath}index.html`); + return files.has(relativePath) || files.has(`${relativePath}.html`) || files.has(`${relativePath}/index.html`); +} + +const requiredFiles = [ + "index.html", + "404.html", + "CNAME", + "favicon.svg", + "hashmap.json", + "sitemap.xml", + "llms.txt", + "llms-full.txt", + "zh/index.html", + "en/index.html", + "zh/configuration.html", + "en/configuration.html", + "zh/services.html", + "en/services.html", + "zh/reference/jobs.html", + "en/reference/jobs.html", + "zh/configuration/llms.txt", + "en/configuration/llms.txt", +]; + +for (const relativePath of requiredFiles) await access(path.join(outputDir, relativePath)); + +assert.equal((await readFile(path.join(outputDir, "CNAME"), "utf8")).trim(), "reme.agentscope.io"); + +const homepage = await readFile(path.join(outputDir, "index.html"), "utf8"); +assert.ok(homepage.includes('href="/en/"'), "root language switch must link to /en/"); +assert.ok(!homepage.includes('href="/en/ex"'), "root language switch must not produce /en/ex"); +assert.ok(homepage.includes('"studio-en":"/en/workspace/studio"'), "legacy redirects must be embedded"); + +const sitemap = await readFile(path.join(outputDir, "sitemap.xml"), "utf8"); +assert.ok(sitemap.includes(""), "sitemap must include canonical-source update times"); +assert.ok(!sitemap.includes("https://reme.agentscope.io/"), "root redirect must not be indexed"); +assert.ok(!sitemap.includes('hreflang="zh-CN" href="https://reme.agentscope.io/"'), "root must not duplicate zh-CN"); + +const ChineseConfiguration = await readFile(path.join(outputDir, "zh/configuration.html"), "utf8"); +assert.match(ChineseConfiguration, /搜索文档/); +assert.match(ChineseConfiguration, /复制 Markdown/); +assert.match(ChineseConfiguration, /在 GitHub 查看源文件/); + +const jobReference = await readFile(path.join(outputDir, "en/reference/jobs.html"), "utf8"); +assert.match(jobReference, /Job API Reference/); +assert.match(jobReference, /auto_memory/); + +const outputFiles = new Set(await collectFiles(outputDir)); +const missingLinks = []; +for (const relativePath of [...outputFiles].filter((file) => file.endsWith(".html"))) { + const html = await readFile(path.join(outputDir, relativePath), "utf8"); + const currentUrl = new URL(pageUrl(relativePath), "https://reme-docs.local"); + for (const match of html.matchAll(/]*\bhref="([^"]+)"/g)) { + const href = match[1].replaceAll("&", "&"); + if (href.startsWith("#")) continue; + const target = new URL(href, currentUrl); + if (target.origin !== currentUrl.origin) continue; + if (!routeExists(target.pathname, outputFiles)) missingLinks.push(`${relativePath}: ${href}`); + } +} +assert.deepEqual(missingLinks, [], `missing internal links:\n${missingLinks.join("\n")}`); + +console.log(`Verified ${requiredFiles.length} documentation build artifacts.`); diff --git a/github-pages/src/main.js b/github-pages/src/main.js deleted file mode 100644 index 9397ce41..00000000 --- a/github-pages/src/main.js +++ /dev/null @@ -1,458 +0,0 @@ -import DOMPurify from "dompurify"; -import { marked } from "marked"; -import { stripMarkdownFrontmatter } from "./markdown.js"; -import "./styles.css"; - -const baseUrl = import.meta.env.BASE_URL; -const repositoryUrl = "https://github.com/agentscope-ai/ReMe"; - -const copy = { - zh: { - docs: "文档", - home: "首页", - search: "搜索文档…", - noResults: "没有找到匹配的文档", - menu: "打开导航", - toc: "本页目录", - edit: "在 GitHub 查看源文件", - quickStart: "快速开始", - groups: { - overview: "项目介绍", - start: "开始使用", - fundamentals: "核心原理", - automation: "自动化能力", - concepts: "架构与场景", - integration: "Agent 集成", - workspace: "工作区", - plugins: "插件", - benchmarks: "评测", - development: "开发者规范", - }, - }, - en: { - docs: "Documentation", - home: "Home", - search: "Search documentation…", - noResults: "No matching documents", - menu: "Open navigation", - toc: "On this page", - edit: "View source on GitHub", - quickStart: "Quick start", - groups: { - overview: "Introduction", - start: "Get started", - fundamentals: "Fundamentals", - automation: "Automation", - concepts: "Architecture & scenarios", - integration: "Agent integration", - workspace: "Workspace", - plugins: "Plugins", - benchmarks: "Benchmarks", - development: "Development", - }, - }, -}; - -const state = { - language: localStorage.getItem("reme-docs-language") || "zh", - documents: [], - activeDocument: null, - query: "", -}; - -const homeCopy = { - zh: { - eyebrow: "LOCAL-FIRST · FILE-NATIVE", - title: "让 Agent 真正记住,\n也让记忆始终属于你。", - description: "ReMe 将对话和资料沉淀为可读、可编辑、可检索、相互链接的 Markdown,并提供从工作区管理到主动研究的一整套工具。", - start: "快速开始", - project: "了解 ReMe", - explore: "按目标探索", - exploreDescription: "选择你现在想完成的事情。每个入口都直接连接到对应的完整文档。", - cards: [ - { id: "studio-zh", icon: "◫", label: "管理记忆", title: "ReMe 工作台", description: "在本地 Web 工作区中浏览、编辑、搜索记忆,并探索 wikilink 图谱。", tone: "mint" }, - { id: "daily-paper-zh", icon: "◌", label: "发现与分析", title: "每日论文插件", description: "从论文榜单筛选值得阅读的工作,解析 PDF,并生成笔记与五分钟简报。", tone: "blue" }, - { id: "auto-fin-zh", icon: "↗", label: "主题研究", title: "Auto Fin 插件", description: "连接最新财联社新闻和本地历史记忆,生成可追溯的研究报告。", tone: "amber" }, - ], - benchmark: "验证记忆能力", - benchmarkDescription: "从检索规模、跨会话问答、个人智能体到工具经验,查看 ReMe 的四套评测与复现实验。", - benchmarkAction: "从 BEAM 开始", - }, - en: { - eyebrow: "LOCAL-FIRST · FILE-NATIVE", - title: "Memory that works for agents.\nFiles that remain yours.", - description: "ReMe turns conversations and resources into readable, editable, searchable, interconnected Markdown—with tools spanning workspace management and proactive research.", - start: "Quick start", - project: "Meet ReMe", - explore: "Explore by goal", - exploreDescription: "Start with what you want to accomplish. Every entry opens the complete guide.", - cards: [ - { id: "studio-en", icon: "◫", label: "Manage memory", title: "ReMe Studio", description: "Browse, edit, and search memory in a local web workspace, then explore its wikilink graph.", tone: "mint" }, - { id: "daily-paper-en", icon: "◌", label: "Discover & analyze", title: "Daily Paper Plugin", description: "Select useful papers from rankings, analyze PDFs, and create notes plus a five-minute brief.", tone: "blue" }, - { id: "auto-fin-en", icon: "↗", label: "Research topics", title: "Auto Fin Plugin", description: "Connect recent CLS news with historical local memory to produce traceable research reports.", tone: "amber" }, - ], - benchmark: "Validate memory systems", - benchmarkDescription: "Explore four reproducible evaluations covering retrieval scale, cross-session QA, personal agents, and tool-use experience.", - benchmarkAction: "Start with BEAM", - }, -}; - -const app = document.querySelector("#app"); - -app.innerHTML = ` -
- - R - ReMe - - - - -
-
- -
-
-
- -
- -`; - -const sidebar = app.querySelector(".sidebar"); -const docsShell = app.querySelector(".docs-shell"); -const documentNav = app.querySelector(".document-nav"); -const article = app.querySelector(".article"); -const toc = app.querySelector(".toc"); -const searchInput = app.querySelector("input[type='search']"); -const menuButton = app.querySelector(".menu-button"); -const backdrop = app.querySelector(".sidebar-backdrop"); - -function slugify(value) { - return value - .toLowerCase() - .trim() - .replace(/<[^>]+>/g, "") - .replace(/[^\p{Letter}\p{Number}]+/gu, "-") - .replace(/^-|-$/g, ""); -} - -function resolveDocumentPath(currentPath, target) { - const cleanTarget = target.split("#")[0].split("?")[0]; - const currentParts = currentPath.split("/"); - currentParts.pop(); - for (const part of cleanTarget.split("/")) { - if (!part || part === ".") continue; - if (part === "..") currentParts.pop(); - else currentParts.push(part); - } - return currentParts.join("/"); -} - -function configureMarkdown(document) { - const renderer = new marked.Renderer(); - const headingIds = new Map(); - - renderer.heading = ({ tokens, depth }) => { - const text = tokens.map((token) => token.text || token.raw || "").join(""); - const baseSlug = slugify(text) || "section"; - const count = headingIds.get(baseSlug) || 0; - headingIds.set(baseSlug, count + 1); - const id = count ? `${baseSlug}-${count + 1}` : baseSlug; - return `${text}`; - }; - - renderer.image = ({ href, title, text }) => { - const url = /^(https?:|data:)/.test(href) - ? href - : `${baseUrl}content/${resolveDocumentPath(document.path, href)}`; - const titleAttribute = title ? ` title="${title}"` : ""; - return `${text}`; - }; - - renderer.link = ({ href, title, tokens }) => { - const label = tokens.map((token) => token.text || token.raw || "").join(""); - const titleAttribute = title ? ` title="${title}"` : ""; - if (href.startsWith("#")) return `${label}`; - if (!/^(https?:|mailto:)/.test(href)) { - const resolved = resolveDocumentPath(document.path, href); - const localDocument = state.documents.find((item) => item.path === resolved); - if (localDocument) return `${label}`; - return `${label}`; - } - return `${label}`; - }; - - marked.use({ renderer, gfm: true, breaks: false }); -} - -function availableDocuments() { - return state.documents.filter( - (document) => document.language === state.language || document.language === "shared", - ); -} - -function documentTitle(document) { - return document.titles?.[state.language] || document.title; -} - -function renderChrome() { - const labels = copy[state.language]; - app.querySelector("[data-copy='docs']").textContent = labels.docs; - const quickStartLink = app.querySelector("[data-copy='quickStart']"); - quickStartLink.textContent = `${labels.quickStart} →`; - quickStartLink.href = `?doc=${state.language}-quick_start`; - quickStartLink.dataset.doc = `${state.language}-quick_start`; - searchInput.placeholder = labels.search; - menuButton.textContent = labels.menu; - document.documentElement.lang = state.language === "zh" ? "zh-CN" : "en"; - app.querySelectorAll("[data-language]").forEach((button) => { - button.classList.toggle("active", button.dataset.language === state.language); - }); -} - -function renderNavigation() { - const labels = copy[state.language]; - const query = state.query.trim().toLocaleLowerCase(); - const filtered = availableDocuments().filter((document) => - `${documentTitle(document)} ${document.title || ""} ${document.description}`.toLocaleLowerCase().includes(query), - ); - const groups = [...new Set(filtered.map((document) => document.group))]; - - if (!filtered.length) { - documentNav.innerHTML = ` - ${labels.home} -

${labels.noResults}

- `; - return; - } - - documentNav.innerHTML = ` - ${labels.home} - ` + groups - .map( - (group) => ` - `, - ) - .join(""); -} - -function renderHome(pushHistory = true) { - const labels = homeCopy[state.language]; - state.activeDocument = null; - docsShell.classList.add("home-view"); - article.dataset.group = "home"; - renderNavigation(); - article.innerHTML = ` -
-

${labels.eyebrow}

-

${labels.title.replace("\n", "
")}

-

${labels.description}

- -
-
-

01 / PRODUCT & PLUGINS

-

${labels.explore}

-

${labels.exploreDescription}

- -
-
-
-

02 / BENCHMARKS

-

${labels.benchmark}

-

${labels.benchmarkDescription}

-
- ${labels.benchmarkAction} → -
- `; - toc.innerHTML = ""; - closeMenu(); - if (pushHistory) history.pushState({ home: true }, "", baseUrl); - window.scrollTo({ top: 0, behavior: "instant" }); -} - -function renderToc() { - const headings = [...article.querySelectorAll("h2, h3")]; - if (!headings.length) { - toc.innerHTML = ""; - return; - } - toc.innerHTML = ` -

${copy[state.language].toc}

- ${headings - .map( - (heading) => `${heading.childNodes[0]?.textContent || heading.textContent}`, - ) - .join("")} - `; -} - -function rewriteRenderedUrls(document) { - article.querySelectorAll("img[src]").forEach((image) => { - const source = image.getAttribute("src"); - if (source && !/^(https?:|data:|\/)/.test(source)) { - image.src = `${baseUrl}content/${resolveDocumentPath(document.path, source)}`; - } - }); - - article.querySelectorAll("a[href]").forEach((link) => { - const href = link.getAttribute("href"); - if (!href || /^(https?:|mailto:|#|\/)/.test(href) || link.dataset.doc) return; - const resolved = resolveDocumentPath(document.path, href); - const localDocument = state.documents.find((item) => item.path === resolved); - if (localDocument) { - link.href = `?doc=${localDocument.id}`; - link.dataset.doc = localDocument.id; - link.removeAttribute("target"); - return; - } - link.href = `${repositoryUrl}/blob/main/${resolved}`; - link.target = "_blank"; - link.rel = "noreferrer"; - }); -} - -async function openDocument(id, pushHistory = true) { - const fallbackId = state.language === "zh" ? "readme-zh" : "readme-en"; - const document = state.documents.find((item) => item.id === id) || state.documents.find((item) => item.id === fallbackId); - if (document.language !== "shared" && document.language !== state.language) { - state.language = document.language; - localStorage.setItem("reme-docs-language", state.language); - renderChrome(); - } - state.activeDocument = document; - docsShell.classList.remove("home-view"); - article.dataset.group = document.group; - renderNavigation(); - article.innerHTML = `
`; - - const response = await fetch(`${baseUrl}content/${document.path}`); - if (!response.ok) throw new Error(`Unable to load ${document.path}`); - configureMarkdown(document); - const markdown = stripMarkdownFrontmatter(await response.text()); - const body = DOMPurify.sanitize(await marked.parse(markdown), { - ADD_ATTR: ["target"], - }); - article.innerHTML = ` - -
${body}
- - `; - rewriteRenderedUrls(document); - renderToc(); - closeMenu(); - if (pushHistory) history.pushState({ doc: document.id }, "", `?doc=${document.id}`); - window.scrollTo({ top: 0, behavior: "instant" }); -} - -function closeMenu() { - sidebar.classList.remove("open"); - backdrop.classList.remove("visible"); - menuButton.setAttribute("aria-expanded", "false"); -} - -function toggleMenu() { - const open = !sidebar.classList.contains("open"); - sidebar.classList.toggle("open", open); - backdrop.classList.toggle("visible", open); - menuButton.setAttribute("aria-expanded", String(open)); -} - -app.addEventListener("click", (event) => { - const homeLink = event.target.closest("[data-home]"); - if (homeLink) { - event.preventDefault(); - renderHome(); - return; - } - const documentLink = event.target.closest("[data-doc]"); - if (documentLink) { - event.preventDefault(); - openDocument(documentLink.dataset.doc); - } - if (event.target.closest("[data-action='menu']")) toggleMenu(); - const languageButton = event.target.closest("[data-language]"); - if (languageButton && languageButton.dataset.language !== state.language) { - state.language = languageButton.dataset.language; - localStorage.setItem("reme-docs-language", state.language); - state.query = ""; - searchInput.value = ""; - renderChrome(); - renderHome(); - } -}); - -searchInput.addEventListener("input", () => { - state.query = searchInput.value; - renderNavigation(); -}); - -document.addEventListener("keydown", (event) => { - if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") { - event.preventDefault(); - searchInput.focus(); - } - if (event.key === "Escape") closeMenu(); -}); - -backdrop.addEventListener("click", closeMenu); -window.addEventListener("popstate", (event) => { - const id = event.state?.doc || new URLSearchParams(location.search).get("doc"); - if (id) openDocument(id, false); - else renderHome(false); -}); - -const manifest = await fetch(`${baseUrl}content/manifest.json`).then((response) => response.json()); -state.documents = manifest.documents; -renderChrome(); -const initialDocument = new URLSearchParams(location.search).get("doc"); -if (initialDocument) await openDocument(initialDocument, false); -else renderHome(false); diff --git a/github-pages/src/markdown.js b/github-pages/src/markdown.js deleted file mode 100644 index ef81a773..00000000 --- a/github-pages/src/markdown.js +++ /dev/null @@ -1,6 +0,0 @@ -const FRONTMATTER_PATTERN = /^\uFEFF?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/; - -/** Remove a leading YAML frontmatter block before rendering Markdown. */ -export function stripMarkdownFrontmatter(markdown) { - return markdown.replace(FRONTMATTER_PATTERN, ""); -} diff --git a/github-pages/src/styles.css b/github-pages/src/styles.css deleted file mode 100644 index 7b3ee4ad..00000000 --- a/github-pages/src/styles.css +++ /dev/null @@ -1,200 +0,0 @@ -:root { - color: #17221d; - background: #f4f7f5; - font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - font-synthesis: none; - text-rendering: optimizeLegibility; - --ink: #17221d; - --muted: #65716a; - --line: #dce5e0; - --paper: #ffffff; - --green: #087f6a; - --blue: #3156d9; - --green-soft: #e5f5ef; - --code: #f3f5f2; -} - -* { box-sizing: border-box; } -html { scroll-behavior: smooth; scroll-padding-top: 92px; } -body { - margin: 0; - min-width: 320px; - background: - radial-gradient(circle at 8% 9%, rgba(27, 193, 164, 0.06), transparent 26rem), - #f4f7f5; -} -button, input { font: inherit; } -a { color: inherit; } - -.topbar { - position: fixed; - inset: 0 0 auto 0; - z-index: 30; - height: 66px; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 28px; - border-bottom: 1px solid rgba(213, 225, 219, 0.85); - background: rgba(250, 252, 251, 0.88); - backdrop-filter: blur(18px) saturate(140%); -} - -.brand { display: flex; align-items: center; gap: 11px; color: var(--ink); text-decoration: none; font-weight: 760; } -.brand-mark { - display: grid; - place-items: center; - width: 34px; - height: 34px; - border-radius: 11px; - color: white; - background: linear-gradient(145deg, #19c9b0, #3156d9 82%); - box-shadow: 0 7px 18px rgba(24, 123, 114, 0.2); - font-family: Georgia, serif; - font-size: 21px; -} -.brand-divider { width: 1px; height: 20px; background: var(--line); margin-left: 2px; } -.brand-section { color: var(--muted); font-weight: 520; } -.top-actions { display: flex; align-items: center; gap: 18px; } -.github-link, .quick-start-link { color: #37443d; text-decoration: none; font-size: 13px; font-weight: 650; } -.github-link:hover, .quick-start-link:hover { color: var(--green); } -.quick-start-link { padding: 8px 12px; border: 1px solid #d7e5df; border-radius: 9px; background: rgba(255, 255, 255, 0.72); } -.language-switch { display: flex; padding: 3px; border: 1px solid var(--line); border-radius: 9px; background: #f5f7f4; } -.language-switch button { padding: 5px 9px; border: 0; border-radius: 6px; color: var(--muted); background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; } -.language-switch button.active { color: var(--ink); background: white; box-shadow: 0 1px 3px rgba(20, 40, 30, 0.1); } -.menu-button { display: none; border: 1px solid var(--line); border-radius: 8px; background: white; padding: 7px 10px; cursor: pointer; } - -.docs-shell { display: grid; grid-template-columns: 276px minmax(0, 1fr) 224px; max-width: 1540px; min-height: 100vh; margin: 0 auto; padding-top: 66px; } -.docs-shell.home-view { grid-template-columns: 276px minmax(0, 1fr); } -.docs-shell.home-view .toc-panel { display: none; } -.sidebar { position: sticky; top: 66px; height: calc(100vh - 66px); padding: 25px 20px 18px; overflow-y: auto; border-right: 1px solid var(--line); background: rgba(247, 250, 248, 0.78); } -.search-box { display: flex; align-items: center; gap: 8px; height: 41px; padding: 0 11px; border: 1px solid #d8e3dd; border-radius: 11px; color: #7a857e; background: rgba(255, 255, 255, 0.84); box-shadow: 0 5px 18px rgba(29, 65, 48, 0.035); } -.search-box:focus-within { border-color: #78aa8e; box-shadow: 0 0 0 3px rgba(22, 120, 76, 0.1); } -.search-box input { width: 100%; border: 0; outline: 0; color: var(--ink); background: transparent; font-size: 13px; } -.search-box kbd { padding: 2px 5px; border: 1px solid var(--line); border-radius: 4px; background: #f7f8f6; font-size: 10px; } -.document-nav { padding: 12px 0 52px; } -.home-link { position: relative; display: block; margin-top: 9px; padding: 9px 10px 9px 13px; border-radius: 8px; color: #536058; text-decoration: none; font-size: 13px; } -.home-link:hover { color: var(--ink); background: #f0f3ef; } -.home-link.active { color: #086b5a; background: linear-gradient(90deg, #dff3ec, #eaf6f2); font-weight: 700; } -.nav-group { margin-top: 21px; } -.nav-group h2 { margin: 0 10px 7px; color: #8a948e; font-size: 10px; font-weight: 800; letter-spacing: 0.11em; text-transform: uppercase; } -.nav-group a { position: relative; display: block; padding: 7px 10px 7px 13px; border-radius: 8px; color: #536058; text-decoration: none; font-size: 13px; line-height: 1.4; } -.nav-group a:hover { color: var(--ink); background: #f0f3ef; } -.nav-group a.active { color: #086b5a; background: linear-gradient(90deg, #dff3ec, #eaf6f2); font-weight: 700; } -.nav-group a.active::before { position: absolute; top: 9px; bottom: 9px; left: 0; width: 3px; border-radius: 3px; background: linear-gradient(#17b79d, #3470d8); content: ""; } -.empty-state { padding: 24px 10px; color: var(--muted); font-size: 13px; } -.sidebar-footer { position: sticky; bottom: -18px; display: flex; align-items: center; gap: 8px; margin: 0 -20px; padding: 14px 22px 18px; border-top: 1px solid var(--line); color: #7c8880; background: #f7faf8; font: 600 10px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.04em; text-transform: uppercase; } -.status-dot { width: 6px; height: 6px; border-radius: 50%; background: #29a869; box-shadow: 0 0 0 3px #dff3e8; } - -.article-wrap { min-width: 0; padding: 58px clamp(32px, 5.8vw, 86px) 100px; background: rgba(255, 255, 255, 0.94); } -.article { width: 100%; max-width: 820px; margin: 0 auto; } -.article[data-group="home"] { max-width: 980px; } -.home-hero { padding: 34px 0 76px; } -.home-eyebrow, .section-kicker { margin: 0 0 17px; color: #12806d; font: 750 11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.13em; } -.home-hero h1 { margin: 0; color: #102019; font-size: clamp(46px, 6.3vw, 76px); line-height: 1.15; letter-spacing: -0.055em; } -.home-lead { margin: 27px 0 0; color: #526159; font-size: 18px; line-height: 1.72; } -.home-actions { display: flex; flex-wrap: wrap; gap: 11px; margin-top: 31px; } -.home-actions a { padding: 11px 17px; border-radius: 10px; text-decoration: none; font-size: 14px; font-weight: 720; } -.primary-action { color: white; background: #087f6a; box-shadow: 0 8px 22px rgba(8, 127, 106, 0.2); } -.secondary-action { border: 1px solid #d5e2dc; color: #34443c; background: white; } -.home-explore { padding-top: 58px; border-top: 1px solid var(--line); } -.home-explore h2, .benchmark-callout h2 { margin: 0; color: #15251d; font-size: 30px; letter-spacing: -0.025em; } -.section-lead { max-width: 620px; margin: 10px 0 25px; color: var(--muted); line-height: 1.65; } -.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; } -.feature-card { position: relative; display: flex; min-height: 260px; flex-direction: column; padding: 23px; overflow: hidden; border: 1px solid #dce8e2; border-radius: 16px; color: var(--ink); background: linear-gradient(155deg, #fff, #f4faf7); text-decoration: none; transition: transform 160ms ease, box-shadow 160ms ease; } -.feature-card:hover { transform: translateY(-3px); box-shadow: 0 16px 34px rgba(29, 68, 49, 0.1); } -.feature-card.blue { background: linear-gradient(155deg, #fff, #f1f5ff); } -.feature-card.amber { background: linear-gradient(155deg, #fff, #fbf7ec); } -.feature-icon { display: grid; place-items: center; width: 42px; height: 42px; margin-bottom: 32px; border-radius: 12px; color: #08705e; background: #dbf2ea; font-size: 22px; } -.blue .feature-icon { color: #3156b8; background: #e5ebff; } -.amber .feature-icon { color: #9b6818; background: #f8eac8; } -.feature-label { margin-bottom: 7px; color: #718078; font: 700 10px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.08em; text-transform: uppercase; } -.feature-card strong { font-size: 20px; } -.feature-description { margin-top: 10px; color: #66736c; font-size: 13px; line-height: 1.6; } -.feature-arrow { position: absolute; right: 22px; bottom: 18px; color: #6a7870; font-size: 19px; } -.benchmark-callout { display: flex; align-items: end; justify-content: space-between; gap: 35px; margin-top: 62px; padding: 36px; border-radius: 17px; color: white; background: linear-gradient(125deg, #142a22, #1c473b); } -.benchmark-callout .section-kicker { color: #74d4bb; } -.benchmark-callout h2 { color: white; } -.benchmark-callout p:not(.section-kicker) { max-width: 610px; margin: 10px 0 0; color: #c3d4cd; line-height: 1.65; } -.benchmark-callout > a { flex: none; padding: 10px 14px; border: 1px solid rgba(255,255,255,.25); border-radius: 9px; color: white; text-decoration: none; font-size: 13px; font-weight: 700; } -.article-meta { display: flex; gap: 8px; margin-bottom: 22px; color: #7d8d84; font: 600 11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; } -.article-meta span:first-child { padding: 3px 8px; border-radius: 999px; color: #08705e; background: #e6f5ef; } -.markdown-body { color: #27332d; font-size: 16px; line-height: 1.78; } -.markdown-body > :first-child { margin-top: 0; } -.markdown-body h1 { margin: 0 0 30px; color: #112019; font-size: clamp(36px, 5vw, 54px); line-height: 1.06; letter-spacing: -0.04em; } -.markdown-body h2 { margin: 58px 0 18px; padding-top: 4px; color: #14241c; font-size: 27px; line-height: 1.25; letter-spacing: -0.02em; } -.markdown-body h3 { margin: 35px 0 12px; color: #1f3027; font-size: 20px; line-height: 1.35; } -.markdown-body p, .markdown-body ul, .markdown-body ol { margin: 14px 0; } -.markdown-body li { margin: 5px 0; } -.markdown-body a { color: var(--green); text-decoration-color: #9cc8ae; text-underline-offset: 3px; } -.markdown-body a:hover { text-decoration-color: var(--green); } -.markdown-body img { display: block; max-width: 100%; height: auto; margin: 30px auto; border-radius: 14px; } -/* README badges are linked images. Keep them in a compact row instead of applying the figure layout above. */ -.article[data-group="overview"] .markdown-body > p:has(> a > img[src*="img.shields.io"]) { - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 7px; - max-width: 690px; - margin: 20px auto; -} -.article[data-group="overview"] .markdown-body > p > a > img[src*="img.shields.io"] { - display: inline-block; - width: auto; - max-height: 24px; - margin: 0; - border-radius: 4px; - vertical-align: middle; -} -.markdown-body p[align="center"] { text-align: center; } -.article[data-group="overview"] .markdown-body > p:first-child img { max-width: min(470px, 72%); margin-top: 8px; filter: drop-shadow(0 18px 25px rgba(44, 85, 164, 0.1)); } -.markdown-body code { padding: 2px 5px; border-radius: 5px; background: var(--code); color: #315844; font: 0.88em/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; } -.markdown-body pre { margin: 24px 0; padding: 19px 21px; overflow-x: auto; border: 1px solid #dce5e0; border-radius: 12px; background: linear-gradient(145deg, #f5f8f6, #f8faf9); box-shadow: inset 3px 0 0 #7bd0b6; } -.markdown-body pre code { padding: 0; color: #263b30; background: none; font-size: 13px; } -.markdown-body blockquote { margin: 24px 0; padding: 4px 20px; border-left: 3px solid #68aa85; color: #53635a; background: #f5faf7; } -.markdown-body table { display: block; width: 100%; margin: 24px 0; overflow-x: auto; border-collapse: collapse; font-size: 14px; } -.markdown-body th, .markdown-body td { padding: 10px 13px; border: 1px solid var(--line); text-align: left; } -.markdown-body th { background: #f4f6f3; } -.markdown-body hr { margin: 44px 0; border: 0; border-top: 1px solid var(--line); } -.article-footer { margin-top: 70px; padding-top: 20px; border-top: 1px solid var(--line); } -.article-footer a { color: var(--muted); text-decoration: none; font-size: 13px; } -.article-footer a:hover { color: var(--green); } -.loading-line { width: 55%; height: 12px; margin-top: 40px; border-radius: 9px; background: linear-gradient(90deg, #edf0ec, #f8faf7, #edf0ec); background-size: 200% 100%; animation: loading 1.2s infinite; } -@keyframes loading { to { background-position: -200% 0; } } - -.toc-panel { position: sticky; top: 66px; height: calc(100vh - 66px); padding: 58px 24px; overflow-y: auto; border-left: 1px solid #e9efeb; background: rgba(252, 253, 252, 0.92); } -.toc h2 { margin: 0 0 12px; color: #8a948e; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; } -.toc a { display: block; padding: 5px 0; color: #7a857e; text-decoration: none; font-size: 12px; line-height: 1.45; } -.toc a:hover { color: var(--green); } -.toc .toc-h3 { padding-left: 12px; } -.sidebar-backdrop { display: none; } - -@media (max-width: 1120px) { - .docs-shell { grid-template-columns: 250px minmax(0, 1fr); } - .toc-panel { display: none; } -} - -@media (max-width: 760px) { - .topbar { height: 60px; padding: 0 16px; } - .brand-section, .brand-divider, .github-link { display: none; } - .quick-start-link { font-size: 12px; } - .menu-button { display: block; max-width: 112px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .top-actions { gap: 9px; } - .docs-shell { display: block; padding-top: 60px; } - .sidebar { position: fixed; z-index: 25; top: 60px; bottom: 0; left: 0; width: min(310px, 86vw); height: auto; transform: translateX(-105%); transition: transform 180ms ease; box-shadow: 16px 0 35px rgba(20, 40, 30, 0.12); } - .sidebar.open { transform: translateX(0); } - .sidebar-backdrop { position: fixed; z-index: 20; inset: 60px 0 0; width: 100%; border: 0; background: rgba(18, 30, 23, 0.35); } - .sidebar-backdrop.visible { display: block; } - .article-wrap { padding: 38px 20px 72px; } - .article-meta { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } - .markdown-body { font-size: 15px; } - .markdown-body h1 { font-size: 34px; } - .markdown-body h2 { margin-top: 46px; font-size: 24px; } - .article[data-group="overview"] .markdown-body > p:first-child img { max-width: 84%; } - .home-hero { padding: 20px 0 54px; } - .home-hero h1 { font-size: 43px; } - .home-lead { font-size: 16px; } - .feature-grid { grid-template-columns: 1fr; } - .feature-card { min-height: 225px; } - .benchmark-callout { align-items: flex-start; flex-direction: column; padding: 28px 24px; } -} diff --git a/github-pages/tests/content-manifest.test.mjs b/github-pages/tests/content-manifest.test.mjs deleted file mode 100644 index bc1a8a0b..00000000 --- a/github-pages/tests/content-manifest.test.mjs +++ /dev/null @@ -1,23 +0,0 @@ -import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; -import test from "node:test"; - -const manifestUrl = new URL("../.generated/content/manifest.json", import.meta.url); - -test("omits retired Agent documents and places Agent integration after getting started", async () => { - const manifest = JSON.parse(await readFile(manifestUrl, "utf8")); - const documents = manifest.documents; - const groups = [...new Set(documents.map((document) => document.group))]; - - assert.equal(documents.some((document) => document.id === "reme-memory-skill"), false); - assert.equal(documents.some((document) => document.sourcePath.endsWith("agent_integration_plan.md")), false); - assert.deepEqual( - documents - .filter((document) => document.group === "plugins") - .map((document) => document.title || document.titles?.en), - ["每日论文插件", "Auto Fin 插件", "Daily Paper Plugin", "Auto Fin Plugin"], - ); - assert.equal(documents.some((document) => document.group === "cookbooks"), false); - assert.ok(groups.indexOf("integration") > groups.indexOf("start")); - assert.ok(groups.indexOf("integration") < groups.indexOf("fundamentals")); -}); diff --git a/github-pages/tests/generated-content.test.mjs b/github-pages/tests/generated-content.test.mjs new file mode 100644 index 00000000..cf699a5d --- /dev/null +++ b/github-pages/tests/generated-content.test.mjs @@ -0,0 +1,90 @@ +import assert from "node:assert/strict"; +import { access, readFile } from "node:fs/promises"; +import path from "node:path"; +import test from "node:test"; +import { fileURLToPath } from "node:url"; +import { parse as parseYaml } from "yaml"; +import { legacyRoutes } from "../../docs/.vitepress/legacy-routes.mjs"; + +const siteDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const repoDir = path.resolve(siteDir, ".."); +const generatedDir = path.join(siteDir, ".generated", "site"); + +test("generates every required bilingual guide", async () => { + const names = [ + "configuration.md", + "services.md", + "operations.md", + "integrations.md", + "plugin_development.md", + "faq.md", + "reference/cli.md", + "reference/jobs.md", + ]; + for (const language of ["zh", "en"]) { + for (const name of names) await access(path.join(generatedDir, language, name)); + } + await access(path.join(generatedDir, "zh/integrations/claude-code.md")); + await access(path.join(generatedDir, "en/integrations/claude-code.md")); + await access(path.join(generatedDir, "zh/integrations/hermes.md")); + await access(path.join(generatedDir, "en/integrations/hermes.md")); +}); + +test("maps mirrored pages back to their canonical repository sources", async () => { + const sourceMap = JSON.parse(await readFile(path.join(generatedDir, ".source-map.json"), "utf8")); + assert.equal(sourceMap["zh/integrations/typescript.md"], "typescript/README_ZH.md"); + assert.equal(sourceMap["en/integrations/claude-code.md"], "integrations/claude_code/README.md"); + assert.equal(sourceMap["en/integrations/hermes.md"], "integrations/hermes_agent/README.md"); + assert.equal(sourceMap["en/workspace/studio.md"], "reme_studio/README.md"); + assert.equal(sourceMap["zh/plugins/lme.md"], "plugins/lme/README_ZH.md"); + assert.equal(sourceMap["en/reference/jobs.md"], "reme/config/default.yaml"); +}); + +test("generates the callable Job reference from default.yaml", async () => { + const config = parseYaml(await readFile(path.join(repoDir, "reme/config/default.yaml"), "utf8")); + const callableJobs = Object.entries(config.jobs) + .filter(([, job]) => !["background", "cron"].includes(job.backend)) + .map(([name]) => name); + + for (const language of ["zh", "en"]) { + const reference = await readFile(path.join(generatedDir, language, "reference", "jobs.md"), "utf8"); + for (const job of callableJobs) assert.ok(reference.includes(`### ${"`"}${job}${"`"}`), job); + } +}); + +test("keeps generated content disposable and excludes internal plans", async () => { + await assert.rejects(access(path.join(generatedDir, "plans"))); + await access(path.join(generatedDir, ".vitepress", "config.mts")); + await access(path.join(generatedDir, "public", "favicon.svg")); + assert.equal( + (await readFile(path.join(generatedDir, "public", "CNAME"), "utf8")).trim(), + "reme.agentscope.io", + ); +}); + +test("maps every legacy query-string document ID to a generated page", async () => { + assert.equal(Object.keys(legacyRoutes).length, 45); + assert.equal(legacyRoutes["studio-en"], "/en/workspace/studio"); + assert.equal(legacyRoutes["en-quick_start"], "/en/quick_start"); + assert.equal(legacyRoutes["agents-guide"], "https://github.com/agentscope-ai/ReMe/blob/main/AGENTS.md"); + + for (const [id, route] of Object.entries(legacyRoutes)) { + if (route.startsWith("https://")) continue; + assert.match(route, /^\/(?:zh|en)\//, id); + const relative = route.endsWith("/") ? `${route.slice(1)}index.md` : `${route.slice(1)}.md`; + await access(path.join(generatedDir, relative)); + } +}); + +test("tracks every generated input in documentation CI and deployment", async () => { + const requiredPaths = [ + "reme/config/default.yaml", + "integrations/claude_code/README.md", + "integrations/hermes_agent/README.md", + "benchmark/toolmemory/gitcha.png", + ]; + for (const workflow of ["ci-docs.yml", "deploy-docs.yml"]) { + const source = await readFile(path.join(repoDir, ".github/workflows", workflow), "utf8"); + for (const requiredPath of requiredPaths) assert.ok(source.includes(requiredPath), `${workflow}: ${requiredPath}`); + } +}); diff --git a/github-pages/tests/markdown.test.mjs b/github-pages/tests/markdown.test.mjs deleted file mode 100644 index 129b6190..00000000 --- a/github-pages/tests/markdown.test.mjs +++ /dev/null @@ -1,15 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; -import { stripMarkdownFrontmatter } from "../src/markdown.js"; - -test("strips leading YAML frontmatter before rendering", () => { - assert.equal( - stripMarkdownFrontmatter("---\nname: reme_memory\ndescription: Memory skill\n---\n\n# ReMe Memory\n"), - "\n# ReMe Memory\n", - ); -}); - -test("preserves Markdown without frontmatter", () => { - const markdown = "# ReMe Memory\n\nContent\n"; - assert.equal(stripMarkdownFrontmatter(markdown), markdown); -}); diff --git a/github-pages/vite.config.js b/github-pages/vite.config.js deleted file mode 100644 index 1445f872..00000000 --- a/github-pages/vite.config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from "vite"; - -export default defineConfig({ - base: "./", - publicDir: ".generated", - build: { - outDir: "dist", - emptyOutDir: true, - }, -});