@page.su/ai-blog-cli 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +145 -0
  2. package/dist/api-client.d.ts +39 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +163 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/api-client.test.d.ts +2 -0
  7. package/dist/api-client.test.d.ts.map +1 -0
  8. package/dist/api-client.test.js +83 -0
  9. package/dist/api-client.test.js.map +1 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +74 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/commands/build.d.ts +4 -0
  15. package/dist/commands/build.d.ts.map +1 -0
  16. package/dist/commands/build.js +158 -0
  17. package/dist/commands/build.js.map +1 -0
  18. package/dist/commands/code-repo.d.ts +4 -0
  19. package/dist/commands/code-repo.d.ts.map +1 -0
  20. package/dist/commands/code-repo.js +102 -0
  21. package/dist/commands/code-repo.js.map +1 -0
  22. package/dist/commands/comments.d.ts +4 -0
  23. package/dist/commands/comments.d.ts.map +1 -0
  24. package/dist/commands/comments.js +53 -0
  25. package/dist/commands/comments.js.map +1 -0
  26. package/dist/commands/demo.d.ts +4 -0
  27. package/dist/commands/demo.d.ts.map +1 -0
  28. package/dist/commands/demo.js +72 -0
  29. package/dist/commands/demo.js.map +1 -0
  30. package/dist/commands/helpers.d.ts +21 -0
  31. package/dist/commands/helpers.d.ts.map +1 -0
  32. package/dist/commands/helpers.js +66 -0
  33. package/dist/commands/helpers.js.map +1 -0
  34. package/dist/commands/knowledge.d.ts +4 -0
  35. package/dist/commands/knowledge.d.ts.map +1 -0
  36. package/dist/commands/knowledge.js +146 -0
  37. package/dist/commands/knowledge.js.map +1 -0
  38. package/dist/commands/post.d.ts +4 -0
  39. package/dist/commands/post.d.ts.map +1 -0
  40. package/dist/commands/post.js +207 -0
  41. package/dist/commands/post.js.map +1 -0
  42. package/dist/commands/scout.d.ts +4 -0
  43. package/dist/commands/scout.d.ts.map +1 -0
  44. package/dist/commands/scout.js +48 -0
  45. package/dist/commands/scout.js.map +1 -0
  46. package/dist/commands/series.d.ts +4 -0
  47. package/dist/commands/series.d.ts.map +1 -0
  48. package/dist/commands/series.js +101 -0
  49. package/dist/commands/series.js.map +1 -0
  50. package/dist/commands/skills.d.ts +3 -0
  51. package/dist/commands/skills.d.ts.map +1 -0
  52. package/dist/commands/skills.js +79 -0
  53. package/dist/commands/skills.js.map +1 -0
  54. package/dist/commands/taxonomy.d.ts +4 -0
  55. package/dist/commands/taxonomy.d.ts.map +1 -0
  56. package/dist/commands/taxonomy.js +52 -0
  57. package/dist/commands/taxonomy.js.map +1 -0
  58. package/dist/commands/uploads.d.ts +4 -0
  59. package/dist/commands/uploads.d.ts.map +1 -0
  60. package/dist/commands/uploads.js +37 -0
  61. package/dist/commands/uploads.js.map +1 -0
  62. package/dist/config.d.ts +19 -0
  63. package/dist/config.d.ts.map +1 -0
  64. package/dist/config.js +84 -0
  65. package/dist/config.js.map +1 -0
  66. package/dist/config.test.d.ts +2 -0
  67. package/dist/config.test.d.ts.map +1 -0
  68. package/dist/config.test.js +53 -0
  69. package/dist/config.test.js.map +1 -0
  70. package/dist/index.d.ts +3 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +100 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/prompts/index.d.ts +9 -0
  75. package/dist/prompts/index.d.ts.map +1 -0
  76. package/dist/prompts/index.js +178 -0
  77. package/dist/prompts/index.js.map +1 -0
  78. package/dist/resources/syntax-spec.d.ts +23 -0
  79. package/dist/resources/syntax-spec.d.ts.map +1 -0
  80. package/dist/resources/syntax-spec.js +105 -0
  81. package/dist/resources/syntax-spec.js.map +1 -0
  82. package/dist/resources/syntax-spec.test.d.ts +2 -0
  83. package/dist/resources/syntax-spec.test.d.ts.map +1 -0
  84. package/dist/resources/syntax-spec.test.js +47 -0
  85. package/dist/resources/syntax-spec.test.js.map +1 -0
  86. package/dist/tools/build.d.ts +13 -0
  87. package/dist/tools/build.d.ts.map +1 -0
  88. package/dist/tools/build.js +181 -0
  89. package/dist/tools/build.js.map +1 -0
  90. package/dist/tools/code-repos.d.ts +5 -0
  91. package/dist/tools/code-repos.d.ts.map +1 -0
  92. package/dist/tools/code-repos.js +149 -0
  93. package/dist/tools/code-repos.js.map +1 -0
  94. package/dist/tools/comments.d.ts +12 -0
  95. package/dist/tools/comments.d.ts.map +1 -0
  96. package/dist/tools/comments.js +87 -0
  97. package/dist/tools/comments.js.map +1 -0
  98. package/dist/tools/demos.d.ts +5 -0
  99. package/dist/tools/demos.d.ts.map +1 -0
  100. package/dist/tools/demos.js +98 -0
  101. package/dist/tools/demos.js.map +1 -0
  102. package/dist/tools/glossary.d.ts +4 -0
  103. package/dist/tools/glossary.d.ts.map +1 -0
  104. package/dist/tools/glossary.js +139 -0
  105. package/dist/tools/glossary.js.map +1 -0
  106. package/dist/tools/helpers.d.ts +44 -0
  107. package/dist/tools/helpers.d.ts.map +1 -0
  108. package/dist/tools/helpers.js +65 -0
  109. package/dist/tools/helpers.js.map +1 -0
  110. package/dist/tools/knowledge.d.ts +4 -0
  111. package/dist/tools/knowledge.d.ts.map +1 -0
  112. package/dist/tools/knowledge.js +140 -0
  113. package/dist/tools/knowledge.js.map +1 -0
  114. package/dist/tools/math-concepts.d.ts +4 -0
  115. package/dist/tools/math-concepts.d.ts.map +1 -0
  116. package/dist/tools/math-concepts.js +158 -0
  117. package/dist/tools/math-concepts.js.map +1 -0
  118. package/dist/tools/posts.d.ts +35 -0
  119. package/dist/tools/posts.d.ts.map +1 -0
  120. package/dist/tools/posts.js +278 -0
  121. package/dist/tools/posts.js.map +1 -0
  122. package/dist/tools/scout.d.ts +10 -0
  123. package/dist/tools/scout.d.ts.map +1 -0
  124. package/dist/tools/scout.js +111 -0
  125. package/dist/tools/scout.js.map +1 -0
  126. package/dist/tools/series.d.ts +12 -0
  127. package/dist/tools/series.d.ts.map +1 -0
  128. package/dist/tools/series.js +120 -0
  129. package/dist/tools/series.js.map +1 -0
  130. package/dist/tools/syntax-capabilities.d.ts +15 -0
  131. package/dist/tools/syntax-capabilities.d.ts.map +1 -0
  132. package/dist/tools/syntax-capabilities.js +859 -0
  133. package/dist/tools/syntax-capabilities.js.map +1 -0
  134. package/dist/tools/taxonomy.d.ts +4 -0
  135. package/dist/tools/taxonomy.d.ts.map +1 -0
  136. package/dist/tools/taxonomy.js +73 -0
  137. package/dist/tools/taxonomy.js.map +1 -0
  138. package/dist/tools/uploads.d.ts +15 -0
  139. package/dist/tools/uploads.d.ts.map +1 -0
  140. package/dist/tools/uploads.js +56 -0
  141. package/dist/tools/uploads.js.map +1 -0
  142. package/dist/tools/workflows.d.ts +9 -0
  143. package/dist/tools/workflows.d.ts.map +1 -0
  144. package/dist/tools/workflows.js +249 -0
  145. package/dist/tools/workflows.js.map +1 -0
  146. package/package.json +41 -0
@@ -0,0 +1,178 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * 写作辅助类 MCP Prompts。
4
+ *
5
+ * 每个模板在 messages 开头都引导 AI 先调 `describe_workflows` 获取完整工作流路线图,
6
+ * 再按推荐步骤执行。大文章场景引导使用 outline/section 精准读写工作流。
7
+ */
8
+ export function registerPrompts(server) {
9
+ // ─── write-tutorial-post ────────────────────────────────────────────────
10
+ server.registerPrompt("write-tutorial-post", {
11
+ title: "Write a tutorial post",
12
+ description: "技术教程模板:含 callout 提醒、live-demo 多文件代码沙箱、图片配图。",
13
+ argsSchema: {
14
+ topic: z.string().describe("教程主题,例如 'React Server Components 入门'"),
15
+ audience: z
16
+ .string()
17
+ .describe("目标读者画像,例如 '有 1-2 年前端经验的工程师'")
18
+ .optional(),
19
+ },
20
+ }, ({ topic, audience }) => ({
21
+ messages: [
22
+ {
23
+ role: "user",
24
+ content: {
25
+ type: "text",
26
+ text: [
27
+ `请写一篇技术教程文章:${topic}。`,
28
+ audience ? `目标读者:${audience}。` : "",
29
+ "",
30
+ "准备工作(按顺序执行):",
31
+ "0) 先调用 `describe_workflows` 获取完整工作流指南,按 'create-post' 工作流执行。",
32
+ "1) 调用 `post.describe_syntax_capabilities` 了解 14 类高级 Markdown 语法(首次写文章时)。",
33
+ "2) 调用 `taxonomy.list` 获取合法的 tagIds / categoryIds。",
34
+ "3) 可选:调用 `knowledge.find_or_suggest` 查找正文涉及的术语。",
35
+ "4) 可选:调用 `scout.search_items` 搜索相关参考资料。",
36
+ "",
37
+ "写作约束:",
38
+ "- 参考语法资源:mcp://syntax-spec/overview、callout、live-demo、image-attributes、checklist",
39
+ "- 文章结构推荐:背景动机 → 核心概念 → 渐进式示例(含 ```live-demo) → 常见坑(用 callout) → 总结",
40
+ "- 超长文章(>10000字):先 `post.create` 创建骨架,再用 `post.append_content` 分批追加章节",
41
+ "- 写好正文后必须 `post.validate_markdown` 校验,errors 必须修复",
42
+ "- 创建为 `status=draft`,让作者决定何时发布",
43
+ ]
44
+ .filter(Boolean)
45
+ .join("\n"),
46
+ },
47
+ },
48
+ ],
49
+ }));
50
+ // ─── write-deep-dive ────────────────────────────────────────────────────
51
+ server.registerPrompt("write-deep-dive", {
52
+ title: "Write a deep-dive analysis",
53
+ description: "深度解析模板:含 mermaid 架构图、KaTeX 数学公式、参考文献引用。",
54
+ argsSchema: {
55
+ topic: z.string().describe("深度解析的主题"),
56
+ depthHint: z
57
+ .string()
58
+ .describe("希望深入的方向,例如 '内部数据结构与时间复杂度'")
59
+ .optional(),
60
+ },
61
+ }, ({ topic, depthHint }) => ({
62
+ messages: [
63
+ {
64
+ role: "user",
65
+ content: {
66
+ type: "text",
67
+ text: [
68
+ `请写一篇深度解析文章:${topic}。`,
69
+ depthHint ? `重点方向:${depthHint}。` : "",
70
+ "",
71
+ "准备工作(按顺序执行):",
72
+ "0) 先调用 `describe_workflows` 获取完整工作流指南,按 'create-post' 工作流执行。",
73
+ "1) 参考语法资源:mcp://syntax-spec/mermaid、math、footnote、site-post-reference",
74
+ "2) 调用 `taxonomy.list` 获取分类和标签。",
75
+ "3) 调用 `scout.search_items` 搜索相关论文/文档作为参考资料。",
76
+ "",
77
+ "写作约束:",
78
+ "- 至少包含一个 mermaid 图与一组数学公式",
79
+ "- 引用论文/文档用 ```ref 参考文献语法(用 `post.build_reference` 构造),不要用 GFM 脚注",
80
+ "- 站内引用前先用 `post.list_for_reference` 校验 slug 存在",
81
+ "- 超长文章:先创建骨架,再用 `post.append_content` 分批追加",
82
+ "- 写完后 `post.validate_markdown` 校验",
83
+ "- 创建为 `status=draft`",
84
+ ]
85
+ .filter(Boolean)
86
+ .join("\n"),
87
+ },
88
+ },
89
+ ],
90
+ }));
91
+ // ─── write-changelog ────────────────────────────────────────────────────
92
+ server.registerPrompt("write-changelog", {
93
+ title: "Write a changelog post",
94
+ description: "变更说明模板:版本号 + 三段式(新增/优化/修复)+ 站内引用相关文档。",
95
+ argsSchema: {
96
+ version: z.string().describe("版本号,例如 v1.4.0"),
97
+ highlights: z.string().describe("本次发布要点,逗号或换行分隔").optional(),
98
+ },
99
+ }, ({ version, highlights }) => ({
100
+ messages: [
101
+ {
102
+ role: "user",
103
+ content: {
104
+ type: "text",
105
+ text: [
106
+ `请写一篇 ${version} 的变更说明(changelog)。`,
107
+ highlights ? `本次要点:${highlights}` : "",
108
+ "",
109
+ "准备工作:",
110
+ "0) 先调用 `describe_workflows` 获取工作流指南。",
111
+ "1) 调用 `taxonomy.list` 获取分类和标签。",
112
+ "2) 调用 `post.list_for_reference` 获取站内文章 slug 列表。",
113
+ "",
114
+ "写作约束:",
115
+ "- 标题形如 \"vX.Y.Z 变更说明\";slug 必须包含版本号",
116
+ "- 三段式结构:✨ 新增 / ♻️ 优化 / 🐛 修复,使用三级标题",
117
+ "- 涉及到本站文章时,用 [标题](../posts/<slug>) 站内引用(slug 必须从 list_for_reference 获取)",
118
+ "- 仅在解释复杂行为变更时插入 callout;其它用项目符号",
119
+ "- 创建为 `status=draft`",
120
+ ]
121
+ .filter(Boolean)
122
+ .join("\n"),
123
+ },
124
+ },
125
+ ],
126
+ }));
127
+ // ─── rewrite-existing-post ──────────────────────────────────────────────
128
+ server.registerPrompt("rewrite-existing-post", {
129
+ title: "Rewrite an existing post",
130
+ description: "重写已有文章:支持全量重写和章节级精准修改两种模式。",
131
+ argsSchema: {
132
+ postId: z.string().describe("要重写的文章 id (uuid)"),
133
+ intent: z
134
+ .string()
135
+ .describe("重写意图,例如 '让结构更清晰,补充 2025 年的最新进展'")
136
+ .optional(),
137
+ },
138
+ }, ({ postId, intent }) => ({
139
+ messages: [
140
+ {
141
+ role: "user",
142
+ content: {
143
+ type: "text",
144
+ text: [
145
+ `请重写文章(id=${postId})。`,
146
+ intent ? `重写目标:${intent}` : "",
147
+ "",
148
+ "准备工作:",
149
+ "0) 先调用 `describe_workflows` 获取工作流指南。",
150
+ "1) 调用 `post.get_outline` 查看文章结构和各章节大小。",
151
+ "",
152
+ "选择执行模式:",
153
+ "",
154
+ "【模式 A:章节级精准修改】(推荐,适用于只改部分章节)",
155
+ "- 按 'update-section' 工作流执行",
156
+ "- 用 `post.get_section(index)` 读取需要修改的章节",
157
+ "- 用 `post.replace_section(sectionIndex)` 替换修改后的章节",
158
+ "- 用 `post.insert_section` 在指定位置插入新章节",
159
+ "- 可重复以上步骤修改多个章节",
160
+ "",
161
+ "【模式 B:全量重写】(适用于结构大改、整体推翻重来)",
162
+ "- 按 'rewrite-post' 工作流执行",
163
+ "- 用 `post.get` 读取完整原文",
164
+ "- 改写后用 `post.update` 提交完整新版本",
165
+ "",
166
+ "通用约束:",
167
+ "- 保留原 slug 不变(避免外链失效)",
168
+ "- 写完后 `post.validate_markdown` 校验,errors 必须 0",
169
+ "- 不要主动 update_status 到 published",
170
+ ]
171
+ .filter(Boolean)
172
+ .join("\n"),
173
+ },
174
+ },
175
+ ],
176
+ }));
177
+ }
178
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ /**
4
+ * 把 docs/markdown-advanced-syntax-spec.md 的 13 个章节挂载为 MCP resource。
5
+ *
6
+ * 实现:
7
+ * - mcp-server 仅注册 URI(如 mcp://syntax-spec/live-demo),不内置文档内容
8
+ * - 内容来自 ai-blog 后端的 `/api/mcp/syntax-spec/<section>` 端点(按需读取)
9
+ * - 这样保证 ai-blog 仓库里的 spec 文档变更后,MCP 客户端无需重装 mcp-server
10
+ */
11
+ /** spec 章节定义;section 字段对应 ai-blog 端 `/api/mcp/syntax-spec/<section>` 的最后一段 */
12
+ interface SyntaxSpecSection {
13
+ uri: string;
14
+ section: string;
15
+ name: string;
16
+ description: string;
17
+ }
18
+ /** 把全部 syntax-spec 章节注册为静态 MCP resource */
19
+ export declare function registerSyntaxSpecResources(server: McpServer, api: ApiClient): void;
20
+ /** 测试用:导出全部章节列表,便于单测断言注册数量与 URI 完整性 */
21
+ export declare const SYNTAX_SPEC_SECTIONS_FOR_TEST: readonly SyntaxSpecSection[];
22
+ export {};
23
+ //# sourceMappingURL=syntax-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-spec.d.ts","sourceRoot":"","sources":["../../src/resources/syntax-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;;;;;GAOG;AAEH,8EAA8E;AAC9E,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAoFD,2CAA2C;AAC3C,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CAwBnF;AAED,uCAAuC;AACvC,eAAO,MAAM,6BAA6B,8BAAuB,CAAC"}
@@ -0,0 +1,105 @@
1
+ /** 13 个章节(spec 主文档 + checklist 附录) */
2
+ const SYNTAX_SPEC_SECTIONS = [
3
+ {
4
+ uri: "mcp://syntax-spec/overview",
5
+ section: "overview",
6
+ name: "syntax-spec / overview",
7
+ description: "ai-blog 12 类非标准语法总览(不超过 800 字)",
8
+ },
9
+ {
10
+ uri: "mcp://syntax-spec/frontmatter",
11
+ section: "frontmatter",
12
+ name: "syntax-spec / frontmatter",
13
+ description: "§1 Frontmatter(YAML)规范",
14
+ },
15
+ {
16
+ uri: "mcp://syntax-spec/callout",
17
+ section: "callout",
18
+ name: "syntax-spec / callout",
19
+ description: "§2 Callout(>[!TIP] 等)规范",
20
+ },
21
+ {
22
+ uri: "mcp://syntax-spec/mermaid",
23
+ section: "mermaid",
24
+ name: "syntax-spec / mermaid",
25
+ description: "§4 Mermaid 图表代码块规范",
26
+ },
27
+ {
28
+ uri: "mcp://syntax-spec/live-demo",
29
+ section: "live-demo",
30
+ name: "syntax-spec / live-demo",
31
+ description: "§5 Live Demo 多文件代码块规范(含 tailwind / cdn meta)",
32
+ },
33
+ {
34
+ uri: "mcp://syntax-spec/math",
35
+ section: "math",
36
+ name: "syntax-spec / math",
37
+ description: "§6 数学公式 $..$ / $$..$$ 规范",
38
+ },
39
+ {
40
+ uri: "mcp://syntax-spec/image-attributes",
41
+ section: "image-attributes",
42
+ name: "syntax-spec / image-attributes",
43
+ description: "§7 图片扩展属性(title 编码 w= / align= / ratio= 等)",
44
+ },
45
+ {
46
+ uri: "mcp://syntax-spec/image-gallery",
47
+ section: "image-gallery",
48
+ name: "syntax-spec / image-gallery",
49
+ description: "§8 图片宫格自动检测规则",
50
+ },
51
+ {
52
+ uri: "mcp://syntax-spec/image-whitelist",
53
+ section: "image-whitelist",
54
+ name: "syntax-spec / image-whitelist",
55
+ description: "§9 图片 src 白名单(前台严格模式)",
56
+ },
57
+ {
58
+ uri: "mcp://syntax-spec/url-whitelist",
59
+ section: "url-whitelist",
60
+ name: "syntax-spec / url-whitelist",
61
+ description: "§10 URL 协议白名单(链接)",
62
+ },
63
+ {
64
+ uri: "mcp://syntax-spec/footnote",
65
+ section: "footnote",
66
+ name: "syntax-spec / footnote",
67
+ description: "§11 GFM 脚注规范",
68
+ },
69
+ {
70
+ uri: "mcp://syntax-spec/site-post-reference",
71
+ section: "site-post-reference",
72
+ name: "syntax-spec / site-post-reference",
73
+ description: "§12 站内文章引用 [标题](../posts/<slug>) 规范",
74
+ },
75
+ {
76
+ uri: "mcp://syntax-spec/checklist",
77
+ section: "checklist",
78
+ name: "syntax-spec / checklist",
79
+ description: "附录 D:保存前 Checklist(AI 自检清单)",
80
+ },
81
+ ];
82
+ /** 把全部 syntax-spec 章节注册为静态 MCP resource */
83
+ export function registerSyntaxSpecResources(server, api) {
84
+ for (const section of SYNTAX_SPEC_SECTIONS) {
85
+ server.registerResource(section.name, section.uri, {
86
+ title: section.name,
87
+ description: section.description,
88
+ mimeType: "text/markdown",
89
+ }, async (uri) => {
90
+ const text = await api.getText(`/api/mcp/syntax-spec/${section.section}`);
91
+ return {
92
+ contents: [
93
+ {
94
+ uri: uri.href,
95
+ mimeType: "text/markdown",
96
+ text,
97
+ },
98
+ ],
99
+ };
100
+ });
101
+ }
102
+ }
103
+ /** 测试用:导出全部章节列表,便于单测断言注册数量与 URI 完整性 */
104
+ export const SYNTAX_SPEC_SECTIONS_FOR_TEST = SYNTAX_SPEC_SECTIONS;
105
+ //# sourceMappingURL=syntax-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-spec.js","sourceRoot":"","sources":["../../src/resources/syntax-spec.ts"],"names":[],"mappings":"AAoBA,sCAAsC;AACtC,MAAM,oBAAoB,GAAiC;IACzD;QACE,GAAG,EAAE,4BAA4B;QACjC,OAAO,EAAE,UAAU;QACnB,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EAAE,gCAAgC;KAC9C;IACD;QACE,GAAG,EAAE,+BAA+B;QACpC,OAAO,EAAE,aAAa;QACtB,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,wBAAwB;KACtC;IACD;QACE,GAAG,EAAE,2BAA2B;QAChC,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,yBAAyB;KACvC;IACD;QACE,GAAG,EAAE,2BAA2B;QAChC,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,oBAAoB;KAClC;IACD;QACE,GAAG,EAAE,6BAA6B;QAClC,OAAO,EAAE,WAAW;QACpB,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,8CAA8C;KAC5D;IACD;QACE,GAAG,EAAE,wBAAwB;QAC7B,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,0BAA0B;KACxC;IACD;QACE,GAAG,EAAE,oCAAoC;QACzC,OAAO,EAAE,kBAAkB;QAC3B,IAAI,EAAE,gCAAgC;QACtC,WAAW,EAAE,4CAA4C;KAC1D;IACD;QACE,GAAG,EAAE,iCAAiC;QACtC,OAAO,EAAE,eAAe;QACxB,IAAI,EAAE,6BAA6B;QACnC,WAAW,EAAE,eAAe;KAC7B;IACD;QACE,GAAG,EAAE,mCAAmC;QACxC,OAAO,EAAE,iBAAiB;QAC1B,IAAI,EAAE,+BAA+B;QACrC,WAAW,EAAE,uBAAuB;KACrC;IACD;QACE,GAAG,EAAE,iCAAiC;QACtC,OAAO,EAAE,eAAe;QACxB,IAAI,EAAE,6BAA6B;QACnC,WAAW,EAAE,mBAAmB;KACjC;IACD;QACE,GAAG,EAAE,4BAA4B;QACjC,OAAO,EAAE,UAAU;QACnB,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EAAE,cAAc;KAC5B;IACD;QACE,GAAG,EAAE,uCAAuC;QAC5C,OAAO,EAAE,qBAAqB;QAC9B,IAAI,EAAE,mCAAmC;QACzC,WAAW,EAAE,qCAAqC;KACnD;IACD;QACE,GAAG,EAAE,6BAA6B;QAClC,OAAO,EAAE,WAAW;QACpB,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,6BAA6B;KAC3C;CACF,CAAC;AAEF,2CAA2C;AAC3C,MAAM,UAAU,2BAA2B,CAAC,MAAiB,EAAE,GAAc;IAC3E,KAAK,MAAM,OAAO,IAAI,oBAAoB,EAAE,CAAC;QAC3C,MAAM,CAAC,gBAAgB,CACrB,OAAO,CAAC,IAAI,EACZ,OAAO,CAAC,GAAG,EACX;YACE,KAAK,EAAE,OAAO,CAAC,IAAI;YACnB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,eAAe;SAC1B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,wBAAwB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1E,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,QAAQ,EAAE,eAAe;wBACzB,IAAI;qBACL;iBACF;aACF,CAAC;QACJ,CAAC,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,uCAAuC;AACvC,MAAM,CAAC,MAAM,6BAA6B,GAAG,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=syntax-spec.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-spec.test.d.ts","sourceRoot":"","sources":["../../src/resources/syntax-spec.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { SYNTAX_SPEC_SECTIONS_FOR_TEST } from "./syntax-spec.js";
3
+ /**
4
+ * 验证 syntax-spec resource 列表:
5
+ * - 共 13 条(与 spec 文档章节一一对应)
6
+ * - URI 形如 mcp://syntax-spec/<section>
7
+ * - section slug 在 ai-blog 后端的 SECTION_HEADING_MAP 范围内
8
+ *
9
+ * 这里不做"读真实文档"的端到端测试(属于 P1.5 集成测试范畴),
10
+ * 仅做静态契约校验,确保两端 section 定义不漂移。
11
+ */
12
+ const EXPECTED_SLUGS = [
13
+ "overview",
14
+ "frontmatter",
15
+ "callout",
16
+ "mermaid",
17
+ "live-demo",
18
+ "math",
19
+ "image-attributes",
20
+ "image-gallery",
21
+ "image-whitelist",
22
+ "url-whitelist",
23
+ "footnote",
24
+ "site-post-reference",
25
+ "checklist",
26
+ ];
27
+ describe("SYNTAX_SPEC_SECTIONS_FOR_TEST", () => {
28
+ it("正好 13 个章节", () => {
29
+ expect(SYNTAX_SPEC_SECTIONS_FOR_TEST).toHaveLength(13);
30
+ });
31
+ it("section slug 与后端 SECTION_HEADING_MAP 完全一致", () => {
32
+ const slugs = SYNTAX_SPEC_SECTIONS_FOR_TEST.map((section) => section.section);
33
+ expect(slugs.sort()).toEqual([...EXPECTED_SLUGS].sort());
34
+ });
35
+ it("URI 形如 mcp://syntax-spec/<section>", () => {
36
+ for (const section of SYNTAX_SPEC_SECTIONS_FOR_TEST) {
37
+ expect(section.uri).toBe(`mcp://syntax-spec/${section.section}`);
38
+ }
39
+ });
40
+ it("name / description 都非空", () => {
41
+ for (const section of SYNTAX_SPEC_SECTIONS_FOR_TEST) {
42
+ expect(section.name.length).toBeGreaterThan(0);
43
+ expect(section.description.length).toBeGreaterThan(0);
44
+ }
45
+ });
46
+ });
47
+ //# sourceMappingURL=syntax-spec.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-spec.test.js","sourceRoot":"","sources":["../../src/resources/syntax-spec.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;;;;;;;GAQG;AAEH,MAAM,cAAc,GAAG;IACrB,UAAU;IACV,aAAa;IACb,SAAS;IACT,SAAS;IACT,WAAW;IACX,MAAM;IACN,kBAAkB;IAClB,eAAe;IACf,iBAAiB;IACjB,eAAe;IACf,UAAU;IACV,qBAAqB;IACrB,WAAW;CACZ,CAAC;AAEF,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;QACnB,MAAM,CAAC,6BAA6B,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,KAAK,GAAG,6BAA6B,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9E,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,KAAK,MAAM,OAAO,IAAI,6BAA6B,EAAE,CAAC;YACpD,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,KAAK,MAAM,OAAO,IAAI,6BAA6B,EAAE,CAAC;YACpD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC/C,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ /**
4
+ * 高级语法构造工具:post.build_frontmatter / build_live_demo / build_image
5
+ *
6
+ * 设计要点:
7
+ * - mcp-server **不直接 import** ai-blog 项目里的 ts 文件(避免路径耦合 + 打包难题)
8
+ * - 全部通过 HTTP 调用 ai-blog 后端的 `/api/mcp/build/*` 端点,复用真正的
9
+ * `buildLiveDemoBlockText` / `serializeImageAttributes` 等函数
10
+ * - 工具返回的字符串是"可以原样写进文章"的 markdown 片段
11
+ */
12
+ export declare function registerBuildTools(server: McpServer, api: ApiClient): void;
13
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/tools/build.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CAyN1E"}
@@ -0,0 +1,181 @@
1
+ import { z } from "zod";
2
+ import { toolReplyHelpers } from "./posts.js";
3
+ /**
4
+ * 高级语法构造工具:post.build_frontmatter / build_live_demo / build_image
5
+ *
6
+ * 设计要点:
7
+ * - mcp-server **不直接 import** ai-blog 项目里的 ts 文件(避免路径耦合 + 打包难题)
8
+ * - 全部通过 HTTP 调用 ai-blog 后端的 `/api/mcp/build/*` 端点,复用真正的
9
+ * `buildLiveDemoBlockText` / `serializeImageAttributes` 等函数
10
+ * - 工具返回的字符串是"可以原样写进文章"的 markdown 片段
11
+ */
12
+ export function registerBuildTools(server, api) {
13
+ // ─── post.build_frontmatter ────────────────────────────────────────────
14
+ server.registerTool("post.build_frontmatter", {
15
+ title: "Build frontmatter block",
16
+ description: "把字段拼装成合法的 YAML frontmatter(含起止 ---)。字段顺序与编辑器 MARKDOWN_METADATA_FIELDS 一致。返回字符串可直接拼到文章正文最前面。",
17
+ inputSchema: {
18
+ title: z.string().min(1),
19
+ slug: z.string().optional(),
20
+ excerpt: z.string().optional(),
21
+ status: z.enum(["draft", "published"]),
22
+ publishedAt: z.string().describe("ISO 字符串").optional(),
23
+ coverImage: z.string().optional(),
24
+ tags: z.array(z.string()).optional(),
25
+ seoTitle: z.string().optional(),
26
+ seoDescription: z.string().optional(),
27
+ canonicalUrl: z.string().optional(),
28
+ },
29
+ }, async (args) => toolReplyHelpers.safe(() => api.post("/api/mcp/build/frontmatter", args)));
30
+ // ─── post.build_live_demo ──────────────────────────────────────────────
31
+ server.registerTool("post.build_live_demo", {
32
+ title: "Build live-demo code block",
33
+ description: "构造一段合法的 ```live-demo 代码块,包含 fence meta(title / tailwind / cdn)和多文件 @file 标记。直接调用项目内 buildLiveDemoBlockText,输出可直接写入文章。",
34
+ inputSchema: {
35
+ title: z.string().describe("代码块右上角显示的标题"),
36
+ files: z
37
+ .array(z.object({
38
+ name: z.string().describe("文件名,含扩展名,如 index.html / app.tsx"),
39
+ content: z.string().describe("文件内容;保留原样缩进与换行"),
40
+ }))
41
+ .min(1),
42
+ tailwind: z.boolean().describe("是否在 iframe 内启用 Tailwind Play CDN").optional(),
43
+ cdn: z
44
+ .array(z.string())
45
+ .describe("外部 CDN URL(必须 https://),按顺序注入")
46
+ .optional(),
47
+ height: z
48
+ .number()
49
+ .int()
50
+ .min(80)
51
+ .max(720)
52
+ .describe("iframe 初始高度(像素),避免内容加载后页面跳动。范围 80-720")
53
+ .optional(),
54
+ },
55
+ }, async (args) => toolReplyHelpers.safe(() => api.post("/api/mcp/build/live-demo", args)));
56
+ // ─── post.build_reference ──────────────────────────────────────────────
57
+ server.registerTool("post.build_reference", {
58
+ title: "Build reference (```ref) block",
59
+ description: "构造一段合法的 ```ref 代码块,用于定义结构化参考文献 / 引用(论文 / 文档 / 仓库 / 视频等)。" +
60
+ "正文用 [ref:key] 行内标记引用它,渲染成可 hover 的上标角标 + 文末参考文献区。" +
61
+ "直接调用项目内 buildReferenceBlockText,输出可直接写入文章。引用外部资料首选此工具,体验优于 GFM 脚注。",
62
+ inputSchema: {
63
+ key: z
64
+ .string()
65
+ .describe("引用唯一标识,仅字母/数字/连字符/下划线;正文用 [ref:key] 引用它"),
66
+ title: z.string().describe("引用资料标题(必填)"),
67
+ authors: z.string().describe("作者 / 团队,如 'Vaswani et al.'").optional(),
68
+ source: z.string().describe("出处 / venue / 站点名,如 'NeurIPS 2017'").optional(),
69
+ url: z.string().describe("原文链接").optional(),
70
+ type: z
71
+ .enum(["paper", "blog", "doc", "repo", "video", "spec", "link"])
72
+ .describe("引用类型,决定图标与标签;默认 link")
73
+ .optional(),
74
+ note: z.string().describe("补充说明").optional(),
75
+ },
76
+ }, async (args) => toolReplyHelpers.safe(() => api.post("/api/mcp/build/reference", args)));
77
+ // ─── post.build_image ──────────────────────────────────────────────────
78
+ server.registerTool("post.build_image", {
79
+ title: "Build markdown image syntax",
80
+ description: "根据 url / alt / 扩展属性(width / align / ratio / rounded)构造合法的 markdown 图片语法。属性会被序列化进 title 字段(双引号、空格分隔)。直接调用 serializeImageAttributes + buildMarkdownImageSyntax。",
81
+ inputSchema: {
82
+ url: z.string().describe("图片 URL;推荐站内 /api/assets/oss/... 或合规 https"),
83
+ alt: z.string(),
84
+ width: z
85
+ .number()
86
+ .int()
87
+ .min(1)
88
+ .max(100)
89
+ .describe("百分比,预设 25 / 33 / 50 / 66 / 75 / 100")
90
+ .optional(),
91
+ align: z.enum(["left", "center", "right"]).optional(),
92
+ ratio: z.string().describe("如 16:9 / 4:3 / 1:1,用于骨架屏防抖").optional(),
93
+ rounded: z.boolean().describe("false 输出 no-rounded;true 不输出(默认就是有圆角)").optional(),
94
+ },
95
+ }, async (args) => toolReplyHelpers.safe(() => api.post("/api/mcp/build/image", args)));
96
+ // ─── post.build_code_group ─────────────────────────────────────────────
97
+ server.registerTool("post.build_code_group", {
98
+ title: "Build code-group block",
99
+ description: "构造一段合法的 ```code-group 代码块,包含多个 /* @tab */ 标记的语言 tab。" +
100
+ "适用于展示同一功能在不同语言中的实现(如 Python / JavaScript / cURL)。" +
101
+ "输出可直接写入文章。",
102
+ inputSchema: {
103
+ tabs: z
104
+ .array(z.object({
105
+ label: z.string().describe("Tab 显示标签,如 'Python'、'JavaScript'"),
106
+ lang: z
107
+ .string()
108
+ .describe("高亮语言(可选),如 'python'。不传则从 label 自动推断")
109
+ .optional(),
110
+ code: z.string().describe("该 tab 的代码内容"),
111
+ }))
112
+ .min(2, "至少需要 2 个 tab"),
113
+ },
114
+ }, async ({ tabs }) => {
115
+ const inner = tabs
116
+ .map((tab) => {
117
+ const langAttr = tab.lang ? ` lang=${tab.lang}` : "";
118
+ return `/* @tab ${tab.label}${langAttr} */\n${tab.code}`;
119
+ })
120
+ .join("\n\n");
121
+ const block = "```code-group\n" + inner + "\n```";
122
+ return toolReplyHelpers.toToolText(block);
123
+ });
124
+ // ─── post.build_details ────────────────────────────────────────────────
125
+ server.registerTool("post.build_details", {
126
+ title: "Build details block",
127
+ description: "构造一段合法的 :::details 折叠块,基于 HTML5 <details>/<summary> 原生标签。" +
128
+ "适用于补充说明、FAQ、技术细节等可选内容。" +
129
+ "输出可直接写入文章。",
130
+ inputSchema: {
131
+ title: z.string().describe("折叠块的标题,显示在 summary 区域"),
132
+ content: z.string().describe("折叠内容(支持完整 Markdown)"),
133
+ defaultOpen: z
134
+ .boolean()
135
+ .describe("是否默认展开;true 添加 {open} 标记,false 默认收起")
136
+ .optional(),
137
+ },
138
+ }, async ({ title, content, defaultOpen }) => {
139
+ const openAttr = defaultOpen ? "{open}" : "";
140
+ const block = `:::details[${title}]${openAttr}\n${content}\n:::`;
141
+ return toolReplyHelpers.toToolText(block);
142
+ });
143
+ // ─── post.build_timeline ───────────────────────────────────────────────
144
+ server.registerTool("post.build_timeline", {
145
+ title: "Build timeline block",
146
+ description: "构造一段合法的 :::timeline 时间轴块,展示项目里程碑、版本历史、事件发展等。" +
147
+ "每个事件用列表项格式定义,支持激活状态标记。" +
148
+ "输出可直接写入文章。",
149
+ inputSchema: {
150
+ events: z
151
+ .array(z.object({
152
+ time: z.string().describe("事件发生的时间,如 '2024-01'、'2024-Q1'"),
153
+ title: z.string().describe("事件的简短标题"),
154
+ content: z.string().describe("事件的详细描述(可选)").optional(),
155
+ active: z
156
+ .boolean()
157
+ .describe("是否标记为激活状态(实心圆点 + 高亮)")
158
+ .optional(),
159
+ }))
160
+ .min(1, "至少需要 1 个事件"),
161
+ },
162
+ }, async ({ events }) => {
163
+ const eventLines = events
164
+ .map((event) => {
165
+ const activeMarker = event.active ? " [active]" : "";
166
+ const titleLine = `- ${event.time} | ${event.title}${activeMarker}`;
167
+ if (event.content) {
168
+ const contentLines = event.content
169
+ .split("\n")
170
+ .map((line) => ` ${line}`)
171
+ .join("\n");
172
+ return `${titleLine}\n${contentLines}`;
173
+ }
174
+ return titleLine;
175
+ })
176
+ .join("\n\n");
177
+ const block = `:::timeline\n${eventLines}\n:::`;
178
+ return toolReplyHelpers.toToolText(block);
179
+ });
180
+ }
181
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/tools/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ /** 注册全部代码仓库相关工具 */
4
+ export declare function registerCodeRepoTools(server: McpServer, api: ApiClient): void;
5
+ //# sourceMappingURL=code-repos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-repos.d.ts","sourceRoot":"","sources":["../../src/tools/code-repos.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAiBlD,mBAAmB;AACnB,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CA2L7E"}