# Momei CLI [简体中文](./README.md) | [English](./README.en-US.md) 用于将 Hexo 内容迁移到墨梅的命令行工具。当前提供十类能力:批量导入文章、基于迁移 API 的旧链接治理、基于外部自动化 API 的 AI 内容编排、分类与标签管理、灵感片段(Snippet)管理、文章版本管理、阅读量同步以及文章导出。内置请求频率限制器(令牌桶算法),遇到 429 自动指数退避重试。 ## 功能特性 - ✅ 递归扫描目录中的 Markdown 文件并解析 Hexo Front-matter - ✅ 兼容站内导入/导出的常用 Front-matter 别名,如 `abbrlink`、`description`、`image`、`audio` 等 - ✅ 将 Front-matter 转换为当前导入 API 所需结构,包括 `metadata.audio` - ✅ 将 `date` 同步映射为 `createdAt` 和 `publishedAt`,并据此自动推导文章状态 - ✅ 通过 Open API 批量导入文章到墨梅站点 - ✅ 生成旧链接 mapping seeds,并调用迁移链接治理接口 - ✅ 调用外部自动化 API 执行标题建议、标签推荐、分类推荐、整篇翻译、封面图生成、音频生成与任务查询 - ✅ 支持 dry run、并发导入、报告导出与失败重试 - ✅ 分类的增删改查管理,支持多语言与分页 - ✅ 标签的增删改查管理,支持多语言与分页 - ✅ 灵感片段(Snippet)的增删改查、详情查询与转文章 - ✅ 文章版本创建与版本列表查看 - ✅ 从 D1 (hexo-cloudflare-counter) 同步阅读量到 Momei,`max(现有, D1)` 防累加 - ✅ 请求频率限制(令牌桶算法),429 自动重试(指数退避) ## 安装 从源码构建: ```bash cd packages/cli pnpm install pnpm build ``` 可选的全局链接: ```bash pnpm link --global ``` 构建完成后可执行: ```bash momei --help ``` ## 命令一:导入文章 基础用法: ```bash momei import --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--api-url ` | 墨梅 API 地址 | `http://localhost:3000` | | `--api-key ` | 墨梅 API Key;非 dry run 必填;提供后 dry run 会额外执行远端别名校验 | - | | `--dry-run` | 仅解析文件,不实际导入 | `false` | | `--upload-images` | 扫描 Markdown 与封面中的本地图片路径,调用上传鉴权接口后自动替换为公共 URL(dry run 仅扫描不上传) | `false` | | `--report-file ` | 保存导入校验 / 导入结果报告(JSON) | - | | `--confirm-path-aliases` | 接受 fallback / repaired 的路径别名决策 | `false` | | `--verbose` | 输出详细日志 | `false` | | `--concurrency ` | 并发导入数量 | `3` | | `--rate-limit ` | 每秒最大请求数,防止触发服务端 429 限流 | `3` | | `--max-retries ` | 429 限流时的最大重试次数(指数退避 1s/2s/4s) | `3` | 示例: ```bash # 预览导入 momei import ./hexo-blog/source/_posts --dry-run --verbose # 导入到本地开发环境 momei import ./hexo-blog/source/_posts \ --api-url http://localhost:3000 \ --api-key your-api-key-here # 导入到生产环境 momei import ./hexo-blog/source/_posts \ --api-url https://your-blog.com \ --api-key your-api-key-here \ --concurrency 5 \ --verbose ``` 如果同时提供 `--api-key`,`dry-run` 会调用 `POST /api/external/posts/validate`,输出结构化的路径别名校验报告,而不仅仅是本地解析结果。 ## 命令二:治理旧链接 `govern-links` 会扫描 Hexo 文件、生成 mapping seeds,并调用墨梅迁移链接治理接口执行 `dry-run` 或 `apply`。 基础用法: ```bash momei govern-links --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--api-url ` | 墨梅 API 地址 | `http://localhost:3000` | | `--api-key ` | 墨梅 API Key | - | | `--mode ` | `dry-run` 或 `apply` | `dry-run` | | `--domains ` | 逗号分隔的旧站域名列表 | - | | `--path-prefixes ` | 逗号分隔的受管资源路径前缀 | - | | `--scopes ` | 逗号分隔的治理范围 | `asset-url,post-link,permalink-rule` | | `--validation-mode ` | `static` 或 `static+online` | `static` | | `--legacy-origin ` | 生成 absolute seeds 时使用的旧站 origin | - | | `--report-file ` | 将报告保存为 `.json` 或 `.md` 文件 | - | | `--retry-report-id ` | 基于已有报告重试失败项 | - | | `--allow-relative-links` | 允许治理相对路径内容链接 | `false` | | `--skip-confirmation` | 有需人工确认项时仍继续 apply | `false` | | `--verbose` | 输出详细日志 | `false` | 示例: ```bash # 先做静态预检,并导出 Markdown 报告 momei govern-links ./hexo-blog/source/_posts \ --api-url http://localhost:3000 \ --api-key your-api-key-here \ --domains old-blog.example.com,legacy.example.com \ --legacy-origin https://old-blog.example.com \ --report-file ./artifacts/link-governance.md # 确认后执行 apply momei govern-links ./hexo-blog/source/_posts \ --api-url https://your-blog.com \ --api-key your-api-key-here \ --mode apply \ --domains old-blog.example.com \ --path-prefixes /uploads,/images \ --validation-mode static+online # 基于既有报告重试失败项 momei govern-links ./hexo-blog/source/_posts \ --api-url https://your-blog.com \ --api-key your-api-key-here \ --retry-report-id report_xxx \ --report-file ./artifacts/retry-report.json ``` ## 命令三:AI 自动化 AI 自动化命令通过 API Key 调用主站的外部自动化接口,适合在本地脚本、CI 或批处理流程中复用站内 AI 工作流。 ### 标题建议 ```bash momei ai suggest-titles --api-key ``` ### 标签推荐 ```bash momei ai recommend-tags --api-key ``` ### 分类推荐 ```bash momei ai recommend-categories \ --target-language en-US \ --api-key ``` ### 整篇翻译 ```bash momei ai translate-post \ --target-language en-US \ --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--source-language ` | 显式指定源语言 | 自动检测 / 使用文章语言 | | `--target-language ` | 目标语言 | 必填 | | `--target-post-id ` | 更新现有目标译文,而不是新建 | - | | `--scopes ` | 逗号分隔的翻译范围 | `title,content,summary,category,tags,coverImage,audio` | | `--target-status ` | 目标文章状态,`draft` 或 `pending` | `draft` | | `--slug-strategy ` | slug 策略:`source`、`translate`、`ai` | `source` | | `--category-strategy ` | 分类策略:`cluster` 或 `suggest` | `cluster` | | `--preview` | 仅生成可审核预览,不直接写入文章 | `false` | | `--confirm-preview-task ` | 基于既有预览任务执行最终落库 | - | | `--approved-slug ` | 应用预览时覆盖 slug | - | | `--approved-category-id ` | 应用预览时覆盖分类 | - | | `--wait` | 阻塞等待任务完成 | `false` | 预览确认工作流示例: ```bash # 先生成可审核预览 momei ai translate-post \ --target-language en-US \ --slug-strategy ai \ --category-strategy suggest \ --preview \ --api-key \ --wait # 再基于预览任务确认写入 momei ai translate-post \ --target-language en-US \ --confirm-preview-task \ --approved-slug custom-preview-slug \ --approved-category-id \ --api-key \ --wait ``` ### 封面图生成 ```bash momei ai generate-cover \ --prompt "A cinematic plum blossom illustration" \ --api-key \ --wait ``` ### 音频生成 ```bash momei ai generate-audio \ --voice zh_female_meow \ --mode speech \ --api-key ``` ### 查询任务状态 ```bash momei ai task --api-key ``` 说明: - 长任务默认立即返回 `taskId`,配合 `momei ai task ` 查询。 - 显式传入 `--wait` 时,CLI 会轮询等待并输出最终结果摘要。 - `translate-post --preview` 会返回 `needsConfirmation` 预览结果;再次传入 `--confirm-preview-task ` 才会真正落库。 - 封面图与音频任务完成后会自动回填文章字段,具体结果以任务返回值为准。 ## 命令四:发布文章 ```bash momei publish --api-key ``` 该命令用于调用外部发布接口,将草稿或待审核文章发布上线,可与 `translate-post`、`generate-cover`、`generate-audio` 组合成脚本式发布流程。 ## 命令五:分类管理 分类管理命令用于对外部 API 的分类进行增删改查操作,支持多语言、父分类和分页查询。 ### 列出分类 ```bash momei categories list --api-key ``` ### 创建分类 ```bash momei categories create \ --name "技术" \ --slug tech \ --api-key ``` ### 更新分类 ```bash momei categories update \ --name "新名称" \ --slug new-slug \ --api-key ``` ### 删除分类 ```bash momei categories delete --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--api-url ` | 墨梅 API 地址 | `http://localhost:3000` | | `--api-key ` | 墨梅 API Key | - | | `--name ` | 分类名称 | - | | `--slug ` | 分类 URL 标识 | - | | `--description ` | 分类描述 | - | | `--parent-id ` | 父分类 ID | - | | `--language ` | 分类语言 | - | | `--search ` | 搜索关键词 | - | | `--page ` | 分页页码 | - | | `--limit ` | 每页数量 | - | | `--order-by ` | 排序字段 | - | | `--order ` | 排序方向 | - | ## 命令六:标签管理 标签管理命令用于对外部 API 的标签进行增删改查操作,支持多语言和分页查询。 ### 列出标签 ```bash momei tags list --api-key ``` ### 创建标签 ```bash momei tags create \ --name "Vue.js" \ --slug vuejs \ --api-key ``` ### 更新标签 ```bash momei tags update \ --name "新名称" \ --slug new-slug \ --api-key ``` ### 删除标签 ```bash momei tags delete --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--api-url ` | 墨梅 API 地址 | `http://localhost:3000` | | `--api-key ` | 墨梅 API Key | - | | `--name ` | 标签名称 | - | | `--slug ` | 标签 URL 标识 | - | | `--language ` | 标签语言 | - | | `--search ` | 搜索关键词 | - | | `--page ` | 分页页码 | - | | `--limit ` | 每页数量 | - | | `--order-by ` | 排序字段 | - | | `--order ` | 排序方向 | - | ## 命令七:灵感片段管理 灵感片段(Snippet)管理命令用于管理碎片化灵感素材,支持增删改查、详情查询,以及将片段一键转为正式文章。 ### 列出片段 ```bash momei snippets list --api-key ``` ### 创建片段 ```bash momei snippets create \ --content "灵感笔记内容" \ --source twitter \ --api-key ``` ### 查看片段详情 ```bash momei snippets get --api-key ``` ### 更新片段 ```bash momei snippets update \ --content "更新后的内容" \ --status archived \ --api-key ``` ### 删除片段 ```bash momei snippets delete --api-key ``` ### 片段转文章 将灵感片段一键转换为正式文章: ```bash momei snippets convert --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--api-url ` | 墨梅 API 地址 | `http://localhost:3000` | | `--api-key ` | 墨梅 API Key | - | | `--content ` | 片段内容 | - | | `--source ` | 片段来源(如 `twitter`、`manual`、`wechat`) | `manual` | | `--status ` | 片段状态:`inbox`、`converted`、`archived` | `inbox` | | `--search ` | 搜索关键词 | - | | `--page ` | 分页页码 | - | | `--limit ` | 每页数量 | - | ## 命令八:同步阅读量 `sync-views` 从 [hexo-cloudflare-counter](https://github.com/CaoMeiYouRen/hexo-cloudflare-counter)(D1)导出的阅读量数据同步到 Momei 的 PostgreSQL。 合并策略为取 `max(现有阅读量, D1 阅读量)`,避免重复执行导致累加。 默认同步到 **zh-CN** 版本,可通过 `--language` 选项指定其他语言版本,或由服务端根据 `Accept-Language` 请求头自动推断。 ### D1 导出 ```bash # 从 D1 导出阅读量数据到 JSON 文件 wrangler d1 execute hexo-cloudflare-counter \ --command "SELECT url, time FROM counters WHERE time > 0" \ --json > d1-views.json ``` ### 同步到 Momei ```bash momei sync-views ./d1-views.json --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--api-url ` | 墨梅 API 地址 | `http://localhost:3000` | | `--api-key ` | 墨梅 API Key | - | | `--dry-run` | 仅解析文件,不实际同步 | `false` | | `--verbose` | 输出详细日志(含错误和未找到的 URL) | `false` | | `--language ` | 目标语言(留空则服务端自动推断或回退 zh-CN) | 自动推断 | | `--rate-limit ` | 每秒最大请求数 | `5` | | `--max-retries ` | 429 限流时的最大重试次数 | `3` | 示例: ```bash # 预览同步效果 momei sync-views ./d1-views.json --api-key your-api-key --dry-run # 执行同步 momei sync-views ./d1-views.json --api-key your-api-key --verbose # 导出后同步(一行命令) wrangler d1 execute hexo-cloudflare-counter \ --command "SELECT url, time FROM counters WHERE time > 0" \ --json | momei sync-views - --api-key your-api-key ``` > 输入文件格式支持: > - **裸数组**:`[{ "url": "...", "time": 123 }, ...]` > - **D1 导出格式**:`{ "results": [{ "url": "...", "time": 123 }, ...], "success": true, "meta": {...} }`
即 `wrangler d1 execute --command "SELECT url, time FROM counters" --json` 的直接输出,无需额外转换。 ## 命令九:导出文章 导出命令用于将博客文章批量导出为 Markdown 或 JSON 格式,方便本地归档或迁移到其他系统。 基础用法: ```bash momei export --api-key ``` 常用选项: | 选项 | 说明 | 默认值 | | --- | --- | --- | | `--api-url ` | 墨梅 API 地址 | `http://localhost:3000` | | `--api-key ` | 墨梅 API Key | - | | `--format ` | 输出格式:`markdown` 或 `json` | `markdown` | | `--language ` | 按语言过滤(如 `zh-CN`、`en-US`) | 全部 | | `--status ` | 按状态过滤(`draft`、`published`、`archived`) | 全部 | | `--category ` | 按分类 slug 过滤 | 全部 | | `--limit ` | 最大导出数量 | 全部 | Markdown 输出包含完整的 Hexo 兼容 Front-matter(标题、日期、分类、标签、摘要、封面、slug、语言、版权等)。导出完成后会输出统计数据报告。 示例: ```bash # 导出所有已发布文章为 Markdown momei export ./backup --api-key your-api-key --status published # 导出英文文章为 JSON momei export ./backup --api-key your-api-key --language en-US --format json # 导出最近 10 篇草稿 momei export ./backup --api-key your-api-key --status draft --limit 10 ``` ## 当前字段映射 | Hexo 字段 | Momei 字段 | 说明 | | --- | --- | --- | | `title` | `title` | 文章标题 | | `date` | `createdAt` + `publishedAt` | 转为 ISO 时间字符串,并同时让 `status` 变为 `published` | | `tags` | `tags` | 标签,支持字符串或数组 | | `categories` / `category` | `category` | 仅取第一个分类作为主分类 | | `slug` / `abbrlink` | `slug` | 参与 canonical slug 选择;冲突或非法时会先进入导入前校验 | | `description` / `desc` / `excerpt` | `summary` | 文章摘要 | | `image` / `cover` / `thumb` | `coverImage` | 文章封面 | | `copyright` / `license` | `copyright` | 版权或许可说明 | | `language` / `lang` | `language` | 语言;缺失时默认 `zh-CN` | | `translationId` / `translation_id` | `translationId` | 翻译簇 ID | | `audio` / `audio_url` / `media` | `metadata.audio.url` | 音频地址 | | `audio_duration` / `duration` | `metadata.audio.duration` | 音频时长;支持秒数或 `HH:mm:ss` | | `audio_size` / `medialength` / `mediaLength` | `metadata.audio.size` | 音频大小 | | `audio_mime_type` / `mediatype` / `mediaType` | `metadata.audio.mimeType` | 音频 MIME 类型 | | `audio_language` / `audio_locale` | `metadata.audio.language` | 音频 locale | | `metadata.audio` | `metadata.audio` | 兼容读取嵌套音频元数据 | | 正文内容 | `content` | Markdown 正文内容 | `permalink` 在当前 CLI 中不再作为 canonical slug 导入,而是主要用于两件事: 1. 导入前通过 `POST /api/external/posts/validate` 执行历史路径别名审计。 2. 在 `govern-links` 命令中生成旧链接映射种子。 当前实现中,以下常见字段不会被导入命令映射: - `updated` - `disableComment` - `audio_translation_id`、`audioTranslationId`、`audio_post_id`、`audioPostId`、`audio_mode` - `tts_provider`、`tts_voice`、`tts_generated_at`、`ttsGeneratedAt`、`tts_language`、`tts_locale`、`tts_translation_id`、`ttsTranslationId`、`tts_post_id`、`ttsPostId`、`tts_mode` - `metadata.tts` - `metadata.scaffold`、`metadata.publish.intent`、`metadata.integration.memosId` - `publishIntent`、`syncToMemos`、`pushOption`、`pushCriteria` - `views`、`tagBindings` ## 导入规则 1. 标题缺失时回退为 `Untitled`。 2. `slug` 优先使用 `slug` 或 `abbrlink`;若显式别名不可用,会在校验报告中给出 fallback / repair / skip 决策,而不是静默改写。 3. 有 `date` 时同时写入 `createdAt` 与 `publishedAt`,并将 `status` 设为 `published`;没有 `date` 时 `status` 为 `draft`。 4. `visibility` 当前固定为 `public`。 5. 标签支持字符串和数组;分类支持字符串和数组,但最终只保留第一个分类。 6. CLI 支持读取 `metadata.audio` 以及音频基础别名字段;但不会导入 TTS 信息,也不会自动构造 `metadata.scaffold`、`metadata.publish.intent` 等其他 metadata 子结构。 ## API Key 获取 1. 登录墨梅博客后台。 2. 进入“设置” -> “API Keys”。 3. 创建新的 API Key。 4. 将生成结果用于 CLI 调用。 ## 开发命令 ```bash pnpm install pnpm build pnpm dev pnpm test pnpm typecheck pnpm lint ``` ## 故障排除 1. `--api-key` 无效:确认 Key 未过期且具备外部 API 权限。 2. 连接失败:检查 `--api-url` 是否正确,以及主应用是否已启动。 3. 导入失败:加上 `--verbose`,必要时结合 `--report-file` 查看校验报告、冲突项和跳过原因。 4. 链接治理失败:先运行 `dry-run`,必要时结合 `--report-file` 和 `--retry-report-id` 分析问题。 5. 自动化任务长时间未完成:使用 `momei ai task ` 检查任务状态,并确认主站 AI 提供商配置有效。 6. 文件解析失败:确认 Markdown Front-matter 为合法 YAML。 ## 许可证 MIT ## 相关链接 - [墨梅博客](https://github.com/CaoMeiYouRen/momei) - [Hexo 官方文档](https://hexo.io/docs/)