@aigne/doc-smith 0.9.8-alpha.3 → 0.9.8-alpha.4

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 (257) hide show
  1. package/CLAUDE.md +43 -0
  2. package/README.md +94 -250
  3. package/aigne.yaml +2 -149
  4. package/doc-smith/SKILL.md +117 -0
  5. package/doc-smith/references/changeset_schema.md +118 -0
  6. package/doc-smith/references/document_structure_schema.md +139 -0
  7. package/doc-smith/references/document_update_guide.md +193 -0
  8. package/doc-smith/references/structure_confirmation_guide.md +133 -0
  9. package/doc-smith/references/structure_planning_guide.md +146 -0
  10. package/doc-smith/references/user_intent_guide.md +172 -0
  11. package/doc-smith.yaml +114 -0
  12. package/main-system-prompt.md +56 -0
  13. package/package.json +3 -69
  14. package/scripts/README.md +90 -0
  15. package/scripts/install.sh +86 -0
  16. package/scripts/uninstall.sh +52 -0
  17. package/CHANGELOG.md +0 -994
  18. package/LICENSE +0 -93
  19. package/agentic-agents/common/base-info.md +0 -53
  20. package/agentic-agents/common/completer.md +0 -54
  21. package/agentic-agents/common/planner.md +0 -168
  22. package/agentic-agents/common/worker.md +0 -93
  23. package/agentic-agents/create/index.yaml +0 -129
  24. package/agentic-agents/create/objective.md +0 -44
  25. package/agentic-agents/create/set-custom-prompt.mjs +0 -27
  26. package/agentic-agents/detail/index.yaml +0 -95
  27. package/agentic-agents/detail/objective.md +0 -9
  28. package/agentic-agents/detail/set-custom-prompt.mjs +0 -88
  29. package/agentic-agents/predict-resources/index.yaml +0 -44
  30. package/agentic-agents/predict-resources/instructions.md +0 -61
  31. package/agentic-agents/structure/design-rules.md +0 -39
  32. package/agentic-agents/structure/index.yaml +0 -86
  33. package/agentic-agents/structure/objective.md +0 -14
  34. package/agentic-agents/structure/review-criteria.md +0 -55
  35. package/agentic-agents/structure/set-custom-prompt.mjs +0 -78
  36. package/agentic-agents/utils/init-workspace-cache.mjs +0 -171
  37. package/agentic-agents/utils/load-base-sources.mjs +0 -20
  38. package/agentic-agents/workspace-cache-sharing-design.md +0 -671
  39. package/agents/chat/chat-system.md +0 -38
  40. package/agents/chat/index.mjs +0 -59
  41. package/agents/chat/skills/generate-document.yaml +0 -15
  42. package/agents/chat/skills/list-documents.mjs +0 -15
  43. package/agents/chat/skills/update-document.yaml +0 -24
  44. package/agents/clear/choose-contents.mjs +0 -192
  45. package/agents/clear/clear-auth-tokens.mjs +0 -88
  46. package/agents/clear/clear-deployment-config.mjs +0 -49
  47. package/agents/clear/clear-document-config.mjs +0 -36
  48. package/agents/clear/clear-document-structure.mjs +0 -102
  49. package/agents/clear/clear-generated-docs.mjs +0 -142
  50. package/agents/clear/clear-media-description.mjs +0 -129
  51. package/agents/clear/index.yaml +0 -26
  52. package/agents/create/analyze-diagram-type-llm.yaml +0 -160
  53. package/agents/create/analyze-diagram-type.mjs +0 -297
  54. package/agents/create/check-document-structure.yaml +0 -30
  55. package/agents/create/check-need-generate-structure.mjs +0 -105
  56. package/agents/create/document-structure-tools/add-document.mjs +0 -85
  57. package/agents/create/document-structure-tools/delete-document.mjs +0 -116
  58. package/agents/create/document-structure-tools/move-document.mjs +0 -109
  59. package/agents/create/document-structure-tools/update-document.mjs +0 -84
  60. package/agents/create/generate-diagram-image.yaml +0 -60
  61. package/agents/create/generate-structure.yaml +0 -117
  62. package/agents/create/index.yaml +0 -49
  63. package/agents/create/refine-document-structure.yaml +0 -12
  64. package/agents/create/replace-d2-with-image.mjs +0 -625
  65. package/agents/create/update-document-structure.yaml +0 -54
  66. package/agents/create/user-add-document/add-documents-to-structure.mjs +0 -90
  67. package/agents/create/user-add-document/find-documents-to-add-links.yaml +0 -47
  68. package/agents/create/user-add-document/index.yaml +0 -46
  69. package/agents/create/user-add-document/prepare-documents-to-translate.mjs +0 -22
  70. package/agents/create/user-add-document/print-add-document-summary.mjs +0 -63
  71. package/agents/create/user-add-document/review-documents-with-new-links.mjs +0 -110
  72. package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +0 -78
  73. package/agents/create/user-remove-document/index.yaml +0 -40
  74. package/agents/create/user-remove-document/prepare-documents-to-translate.mjs +0 -22
  75. package/agents/create/user-remove-document/print-remove-document-summary.mjs +0 -53
  76. package/agents/create/user-remove-document/remove-documents-from-structure.mjs +0 -99
  77. package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +0 -115
  78. package/agents/create/user-review-document-structure.mjs +0 -140
  79. package/agents/create/utils/init-current-content.mjs +0 -34
  80. package/agents/create/utils/merge-document-structures.mjs +0 -30
  81. package/agents/evaluate/code-snippet.mjs +0 -97
  82. package/agents/evaluate/document-structure.yaml +0 -67
  83. package/agents/evaluate/document.yaml +0 -82
  84. package/agents/evaluate/generate-report.mjs +0 -85
  85. package/agents/evaluate/index.yaml +0 -46
  86. package/agents/history/index.yaml +0 -6
  87. package/agents/history/view.mjs +0 -78
  88. package/agents/init/check.mjs +0 -16
  89. package/agents/init/index.mjs +0 -275
  90. package/agents/init/validate.mjs +0 -16
  91. package/agents/localize/choose-language.mjs +0 -107
  92. package/agents/localize/index.yaml +0 -58
  93. package/agents/localize/record-translation-history.mjs +0 -23
  94. package/agents/localize/translate-document.yaml +0 -24
  95. package/agents/localize/translate-multilingual.yaml +0 -51
  96. package/agents/media/batch-generate-media-description.yaml +0 -46
  97. package/agents/media/generate-media-description.yaml +0 -50
  98. package/agents/media/load-media-description.mjs +0 -256
  99. package/agents/prefs/index.mjs +0 -203
  100. package/agents/publish/index.yaml +0 -26
  101. package/agents/publish/publish-docs.mjs +0 -356
  102. package/agents/publish/translate-meta.mjs +0 -103
  103. package/agents/schema/document-structure-item.yaml +0 -26
  104. package/agents/schema/document-structure-refine-item.yaml +0 -23
  105. package/agents/schema/document-structure.yaml +0 -29
  106. package/agents/update/batch-generate-document.yaml +0 -27
  107. package/agents/update/batch-update-document.yaml +0 -7
  108. package/agents/update/check-diagram-flag.mjs +0 -116
  109. package/agents/update/check-document.mjs +0 -162
  110. package/agents/update/check-generate-diagram.mjs +0 -106
  111. package/agents/update/check-sync-image-flag.mjs +0 -55
  112. package/agents/update/check-update-is-single.mjs +0 -53
  113. package/agents/update/document-tools/update-document-content.mjs +0 -303
  114. package/agents/update/generate-diagram.yaml +0 -63
  115. package/agents/update/generate-document.yaml +0 -70
  116. package/agents/update/handle-document-update.yaml +0 -103
  117. package/agents/update/index.yaml +0 -79
  118. package/agents/update/pre-check-generate-diagram.yaml +0 -44
  119. package/agents/update/save-and-translate-document.mjs +0 -76
  120. package/agents/update/sync-images-and-exit.mjs +0 -148
  121. package/agents/update/update-document-detail.yaml +0 -71
  122. package/agents/update/update-single/update-single-document-detail.mjs +0 -280
  123. package/agents/update/update-single-document.yaml +0 -7
  124. package/agents/update/user-review-document.mjs +0 -272
  125. package/agents/utils/action-success.mjs +0 -16
  126. package/agents/utils/analyze-document-feedback-intent.yaml +0 -32
  127. package/agents/utils/analyze-feedback-intent.mjs +0 -136
  128. package/agents/utils/analyze-structure-feedback-intent.yaml +0 -29
  129. package/agents/utils/check-detail-result.mjs +0 -38
  130. package/agents/utils/check-feedback-refiner.mjs +0 -81
  131. package/agents/utils/choose-docs.mjs +0 -293
  132. package/agents/utils/document-icon-generate.yaml +0 -52
  133. package/agents/utils/document-title-streamline.yaml +0 -48
  134. package/agents/utils/ensure-document-icons.mjs +0 -129
  135. package/agents/utils/exit.mjs +0 -6
  136. package/agents/utils/feedback-refiner.yaml +0 -50
  137. package/agents/utils/find-item-by-path.mjs +0 -114
  138. package/agents/utils/find-user-preferences-by-path.mjs +0 -37
  139. package/agents/utils/format-document-structure.mjs +0 -35
  140. package/agents/utils/generate-document-or-skip.mjs +0 -41
  141. package/agents/utils/handle-diagram-operations.mjs +0 -263
  142. package/agents/utils/load-all-document-content.mjs +0 -30
  143. package/agents/utils/load-document-all-content.mjs +0 -84
  144. package/agents/utils/load-sources.mjs +0 -405
  145. package/agents/utils/map-reasoning-effort-level.mjs +0 -15
  146. package/agents/utils/post-generate.mjs +0 -144
  147. package/agents/utils/read-current-document-content.mjs +0 -46
  148. package/agents/utils/save-doc-translation.mjs +0 -61
  149. package/agents/utils/save-doc.mjs +0 -88
  150. package/agents/utils/save-output.mjs +0 -26
  151. package/agents/utils/save-sidebar.mjs +0 -51
  152. package/agents/utils/skip-if-content-exists.mjs +0 -27
  153. package/agents/utils/streamline-document-titles-if-needed.mjs +0 -88
  154. package/agents/utils/transform-detail-data-sources.mjs +0 -45
  155. package/agents/utils/update-branding.mjs +0 -84
  156. package/assets/report-template/report.html +0 -198
  157. package/docs-mcp/analyze-content-relevance.yaml +0 -50
  158. package/docs-mcp/analyze-docs-relevance.yaml +0 -59
  159. package/docs-mcp/docs-search.yaml +0 -42
  160. package/docs-mcp/get-docs-detail.mjs +0 -41
  161. package/docs-mcp/get-docs-structure.mjs +0 -16
  162. package/docs-mcp/read-doc-content.mjs +0 -119
  163. package/prompts/common/document/content-rules-core.md +0 -20
  164. package/prompts/common/document/markdown-syntax-rules.md +0 -65
  165. package/prompts/common/document/media-file-list-usage-rules.md +0 -18
  166. package/prompts/common/document/openapi-usage-rules.md +0 -189
  167. package/prompts/common/document/role-and-personality.md +0 -16
  168. package/prompts/common/document/user-preferences.md +0 -9
  169. package/prompts/common/document-structure/conflict-resolution-guidance.md +0 -16
  170. package/prompts/common/document-structure/document-icon-generate.md +0 -116
  171. package/prompts/common/document-structure/document-structure-rules.md +0 -43
  172. package/prompts/common/document-structure/document-title-streamline.md +0 -86
  173. package/prompts/common/document-structure/glossary.md +0 -7
  174. package/prompts/common/document-structure/intj-traits.md +0 -5
  175. package/prompts/common/document-structure/openapi-usage-rules.md +0 -28
  176. package/prompts/common/document-structure/output-constraints.md +0 -18
  177. package/prompts/common/document-structure/user-locale-rules.md +0 -10
  178. package/prompts/common/document-structure/user-preferences.md +0 -9
  179. package/prompts/detail/custom/admonition-usage-rules.md +0 -94
  180. package/prompts/detail/custom/code-block-usage-rules.md +0 -163
  181. package/prompts/detail/custom/custom-components/x-card-usage-rules.md +0 -63
  182. package/prompts/detail/custom/custom-components/x-cards-usage-rules.md +0 -83
  183. package/prompts/detail/custom/custom-components/x-field-desc-usage-rules.md +0 -120
  184. package/prompts/detail/custom/custom-components/x-field-group-usage-rules.md +0 -80
  185. package/prompts/detail/custom/custom-components/x-field-usage-rules.md +0 -189
  186. package/prompts/detail/custom/custom-components-usage-rules.md +0 -18
  187. package/prompts/detail/diagram/generate-image-system.md +0 -135
  188. package/prompts/detail/diagram/generate-image-user.md +0 -32
  189. package/prompts/detail/diagram/guide.md +0 -29
  190. package/prompts/detail/diagram/official-examples.md +0 -712
  191. package/prompts/detail/diagram/pre-check.md +0 -23
  192. package/prompts/detail/diagram/role-and-personality.md +0 -2
  193. package/prompts/detail/diagram/rules.md +0 -46
  194. package/prompts/detail/diagram/system-prompt.md +0 -1139
  195. package/prompts/detail/diagram/user-prompt.md +0 -43
  196. package/prompts/detail/generate/detail-example.md +0 -457
  197. package/prompts/detail/generate/document-rules.md +0 -45
  198. package/prompts/detail/generate/system-prompt.md +0 -61
  199. package/prompts/detail/generate/user-prompt.md +0 -99
  200. package/prompts/detail/jsx/rules.md +0 -6
  201. package/prompts/detail/update/system-prompt.md +0 -121
  202. package/prompts/detail/update/user-prompt.md +0 -41
  203. package/prompts/evaluate/document-structure.md +0 -93
  204. package/prompts/evaluate/document.md +0 -149
  205. package/prompts/media/media-description/system-prompt.md +0 -43
  206. package/prompts/media/media-description/user-prompt.md +0 -17
  207. package/prompts/structure/check-document-structure.md +0 -93
  208. package/prompts/structure/document-rules.md +0 -21
  209. package/prompts/structure/find-documents-to-add-links.md +0 -52
  210. package/prompts/structure/generate/system-prompt.md +0 -13
  211. package/prompts/structure/generate/user-prompt.md +0 -137
  212. package/prompts/structure/review/structure-review-system.md +0 -81
  213. package/prompts/structure/structure-example.md +0 -89
  214. package/prompts/structure/structure-getting-started.md +0 -10
  215. package/prompts/structure/update/system-prompt.md +0 -93
  216. package/prompts/structure/update/user-prompt.md +0 -43
  217. package/prompts/translate/admonition.md +0 -20
  218. package/prompts/translate/code-block.md +0 -33
  219. package/prompts/translate/glossary.md +0 -6
  220. package/prompts/translate/translate-document.md +0 -305
  221. package/prompts/utils/analyze-document-feedback-intent.md +0 -54
  222. package/prompts/utils/analyze-structure-feedback-intent.md +0 -43
  223. package/prompts/utils/feedback-refiner.md +0 -105
  224. package/types/document-schema.mjs +0 -55
  225. package/types/document-structure-schema.mjs +0 -261
  226. package/utils/auth-utils.mjs +0 -275
  227. package/utils/blocklet.mjs +0 -104
  228. package/utils/check-document-has-diagram.mjs +0 -95
  229. package/utils/conflict-detector.mjs +0 -149
  230. package/utils/constants/index.mjs +0 -620
  231. package/utils/constants/linter.mjs +0 -102
  232. package/utils/d2-utils.mjs +0 -198
  233. package/utils/debug.mjs +0 -3
  234. package/utils/delete-diagram-images.mjs +0 -99
  235. package/utils/deploy.mjs +0 -86
  236. package/utils/docs-finder-utils.mjs +0 -623
  237. package/utils/evaluate/report-utils.mjs +0 -132
  238. package/utils/extract-api.mjs +0 -32
  239. package/utils/file-utils.mjs +0 -960
  240. package/utils/history-utils.mjs +0 -203
  241. package/utils/icon-map.mjs +0 -26
  242. package/utils/image-compress.mjs +0 -75
  243. package/utils/kroki-utils.mjs +0 -173
  244. package/utils/linter/index.mjs +0 -50
  245. package/utils/load-config.mjs +0 -107
  246. package/utils/markdown/index.mjs +0 -26
  247. package/utils/markdown-checker.mjs +0 -694
  248. package/utils/mermaid-validator.mjs +0 -140
  249. package/utils/mermaid-worker-pool.mjs +0 -250
  250. package/utils/mermaid-worker.mjs +0 -233
  251. package/utils/openapi/index.mjs +0 -28
  252. package/utils/preferences-utils.mjs +0 -175
  253. package/utils/request.mjs +0 -10
  254. package/utils/store/index.mjs +0 -45
  255. package/utils/sync-diagram-to-translations.mjs +0 -262
  256. package/utils/upload-files.mjs +0 -231
  257. package/utils/utils.mjs +0 -1354
@@ -1,625 +0,0 @@
1
- import { copyFile, readFile, stat } from "node:fs/promises";
2
- import path from "node:path";
3
- import fs from "fs-extra";
4
- import { createHash } from "node:crypto";
5
- import {
6
- DIAGRAM_PLACEHOLDER,
7
- d2CodeBlockRegex,
8
- diagramImageBlockRegex,
9
- ensureTmpDir,
10
- } from "../../utils/d2-utils.mjs";
11
- import { DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR } from "../../utils/constants/index.mjs";
12
- import { getContentHash, getFileName } from "../../utils/utils.mjs";
13
- import { getExtnameFromContentType } from "../../utils/file-utils.mjs";
14
- import { debug } from "../../utils/debug.mjs";
15
- import { compressImage } from "../../utils/image-compress.mjs";
16
-
17
- const SIZE_THRESHOLD = 1 * 1024 * 1024; // 1MB
18
-
19
- /**
20
- * Calculate hash for an image file
21
- * For files < 1MB: use file content
22
- * For files >= 1MB: use path + size + mtime to avoid memory issues
23
- * @param {string} absolutePath - The absolute path to the image file
24
- * @returns {Promise<string>} - The hash of the file
25
- */
26
- async function calculateImageHash(absolutePath) {
27
- const stats = await stat(absolutePath);
28
-
29
- if (stats.size < SIZE_THRESHOLD) {
30
- // Small file: use full content
31
- const content = await readFile(absolutePath);
32
- return createHash("sha256").update(content).digest("hex");
33
- }
34
-
35
- // Large file: use path + size + mtime
36
- const hashInput = `${absolutePath}:${stats.size}:${stats.mtimeMs}`;
37
- return createHash("sha256").update(hashInput).digest("hex");
38
- }
39
-
40
- /**
41
- * Replace D2 code blocks with generated image in document content
42
- * This mimics the @image insertion pattern
43
- * Saves images to assets/diagram (relative to docsDir) and replaces DIAGRAM_PLACEHOLDER with image reference
44
- *
45
- * File naming: {documentFileNameWithoutExt}-{index:02d}.{ext} (e.g., "guides-getting-started-01.jpg")
46
- * - Uses getFileName() to get the actual document filename, ensuring exact match
47
- * - Example: document "guides-getting-started.md" → diagram "guides-getting-started-01.jpg"
48
- * - Uses 2-digit zero-padded sequential numbering (01, 02, 03...) for easy sorting
49
- * - Same document + same position = same filename (overwrites on update)
50
- * - File name matches document filename (without extension) for easy tracking and identification
51
- *
52
- * Note: Images are saved immediately during replacement to ensure they exist before document save.
53
- * This is necessary because the image path is embedded in the document content.
54
- */
55
- export default async function replaceD2WithImage({
56
- imageResult,
57
- images,
58
- content,
59
- documentContent,
60
- diagramType,
61
- aspectRatio,
62
- diagramIndex,
63
- originalContent,
64
- feedback,
65
- path: docPath,
66
- docsDir,
67
- locale: inputLocale,
68
- }) {
69
- // Extract locale from imageResult if not provided directly
70
- // imageResult contains all input parameters when include_input_in_output: true
71
- const locale = inputLocale || imageResult?.locale || "en";
72
-
73
- // Extract path and docsDir from imageResult if not provided directly
74
- const finalDocPath = docPath || imageResult?.path;
75
- const finalDocsDir = docsDir || imageResult?.docsDir;
76
-
77
- // Determine which content to use for finding diagrams and final replacement
78
- // Priority:
79
- // 1. documentContent (may contain DIAGRAM_PLACEHOLDER from replaceD2WithPlaceholder)
80
- // 2. originalContent (for finding existing diagrams when updating)
81
- // 3. content (fallback)
82
- const contentForFindingDiagrams = originalContent || documentContent || content || "";
83
- // For final content, prefer documentContent first (may have placeholder), then originalContent
84
- let finalContent = documentContent || originalContent || content || "";
85
-
86
- // Extract diagram index from feedback if not explicitly provided
87
- let targetDiagramIndex = diagramIndex;
88
- if (targetDiagramIndex === undefined && feedback) {
89
- const extractedIndex = extractDiagramIndexFromFeedback(feedback);
90
- if (extractedIndex !== null) {
91
- targetDiagramIndex = extractedIndex;
92
- debug(`Extracted diagram index ${targetDiagramIndex} from feedback: "${feedback}"`);
93
- }
94
- }
95
-
96
- // Extract image from the image generation result
97
- // In team agent, image agent output is merged into the context
98
- // So we need to check both imageResult and direct images field
99
- let image = null;
100
-
101
- // First check if images array is directly available (from image agent output)
102
- // Image agent outputs: { images: [{ filename, mimeType, type: "local", path }], ... }
103
- if (images && Array.isArray(images) && images.length > 0) {
104
- image = images[0];
105
- }
106
- // Then check imageResult (might be the whole output object)
107
- else if (imageResult) {
108
- // Check for images array (from image generation agents)
109
- if (imageResult.images && Array.isArray(imageResult.images) && imageResult.images.length > 0) {
110
- image = imageResult.images[0];
111
- }
112
- // Fallback to old format
113
- else if (imageResult.imageUrl || imageResult.image || imageResult.url || imageResult.path) {
114
- image = {
115
- path: imageResult.imageUrl || imageResult.image || imageResult.url || imageResult.path,
116
- filename: path.basename(
117
- imageResult.imageUrl || imageResult.image || imageResult.url || imageResult.path,
118
- ),
119
- mimeType: imageResult.mimeType || "image/jpeg",
120
- type: "local",
121
- };
122
- }
123
- // Check nested output
124
- else if (imageResult.output) {
125
- if (
126
- imageResult.output.images &&
127
- Array.isArray(imageResult.output.images) &&
128
- imageResult.output.images.length > 0
129
- ) {
130
- image = imageResult.output.images[0];
131
- } else if (
132
- imageResult.output.imageUrl ||
133
- imageResult.output.image ||
134
- imageResult.output.url
135
- ) {
136
- image = {
137
- path: imageResult.output.imageUrl || imageResult.output.image || imageResult.output.url,
138
- filename: path.basename(
139
- imageResult.output.imageUrl || imageResult.output.image || imageResult.output.url,
140
- ),
141
- mimeType: imageResult.output.mimeType || "image/jpeg",
142
- type: "local",
143
- };
144
- }
145
- }
146
- }
147
-
148
- if (!image || !image.path || image.type !== "local") {
149
- // Debug: log what we received to help diagnose the issue
150
- debug("⚠️ No valid image found in replace-d2-with-image.mjs");
151
- debug(
152
- " - images:",
153
- images ? `${Array.isArray(images) ? images.length : "not array"} items` : "undefined",
154
- );
155
- debug(" - imageResult:", imageResult ? Object.keys(imageResult).join(", ") : "undefined");
156
- debug(
157
- " - documentContent contains DIAGRAM_PLACEHOLDER:",
158
- finalContent.includes("DIAGRAM_PLACEHOLDER"),
159
- );
160
- // If no image, return content as-is (keep D2 code blocks or placeholder)
161
- return { content: finalContent };
162
- }
163
-
164
- // Determine asset directory: assets/diagram (relative to docsDir, not in .tmp)
165
- // If docsDir is provided, use it; otherwise fallback to .tmp/assets/diagram for backward compatibility
166
- let assetDir;
167
- let relativePathPrefix;
168
-
169
- if (finalDocsDir) {
170
- // New approach: save to assets/diagram relative to docsDir (can be committed to git)
171
- assetDir = path.join(process.cwd(), finalDocsDir, "assets", "diagram");
172
- relativePathPrefix = "assets/diagram";
173
- } else {
174
- // Fallback: use .tmp/assets/diagram for backward compatibility
175
- await ensureTmpDir();
176
- assetDir = path.join(process.cwd(), DOC_SMITH_DIR, TMP_DIR, TMP_ASSETS_DIR, "diagram");
177
- relativePathPrefix = path.posix.join("..", TMP_DIR, TMP_ASSETS_DIR, "diagram");
178
- }
179
-
180
- await fs.ensureDir(assetDir);
181
-
182
- // Get file extension from source path
183
- let ext = path.extname(image.path);
184
-
185
- // If no extension found, try to determine from mimeType
186
- if (!ext && image.mimeType) {
187
- const extFromMime = getExtnameFromContentType(image.mimeType);
188
- if (extFromMime) {
189
- ext = `.${extFromMime}`;
190
- }
191
- }
192
-
193
- // Ensure we have a file extension
194
- if (!ext) {
195
- console.warn(
196
- `Could not determine file extension for diagram image from ${image.path} - using .jpg as fallback`,
197
- );
198
- ext = ".jpg";
199
- }
200
-
201
- // Find all diagram locations to determine the target index
202
- const diagramLocations = findAllDiagramLocations(contentForFindingDiagrams);
203
- let targetIndex = targetDiagramIndex !== undefined ? targetDiagramIndex : 0;
204
-
205
- if (targetIndex < 0 || targetIndex >= diagramLocations.length) {
206
- // If index is out of range, use the next available index (for new diagrams)
207
- targetIndex = diagramLocations.length;
208
- }
209
-
210
- // Generate filename based on document name and diagram index
211
- // Format: {flatDocumentName}-{index:02d}.{ext} (e.g., "guides-getting-started-01.jpg")
212
- // This ensures:
213
- // - Same document + same position = same filename (overwrite on update)
214
- // - Different documents = different filenames
215
- // - Different positions in same document = different filenames
216
- // - File name matches the actual document filename (without extension) for easy tracking
217
- // - Sequential numbering (01, 02, 03...) for easy sorting and identification
218
- let fileName;
219
-
220
- if (finalDocPath) {
221
- // Use getFileName() to get the actual document filename, then remove extension
222
- // This ensures the diagram filename exactly matches the document filename format
223
- // Example: docPath "guides/getting-started" + locale "en" -> "guides-getting-started.md"
224
- // Remove .md extension -> "guides-getting-started"
225
- const documentFileName = getFileName(finalDocPath, locale);
226
- const documentNameWithoutExt = documentFileName.replace(/\.(md|markdown)$/i, "");
227
-
228
- // Format: {documentNameWithoutExt}-{index:02d}.{ext}
229
- // Example: guides-getting-started-01.jpg, guides-getting-started-02.jpg
230
- // Using 2-digit zero-padded index for better sorting and readability
231
- const indexStr = String(targetIndex + 1).padStart(2, "0"); // Convert 0-based to 1-based, pad to 2 digits
232
- fileName = `${documentNameWithoutExt}-${indexStr}${ext}`;
233
- } else {
234
- // Fallback: use hash-based naming if path is not provided
235
- try {
236
- const imageHash = await calculateImageHash(image.path);
237
- fileName = `${imageHash}${ext}`;
238
- } catch (error) {
239
- debug(`Failed to calculate image hash, using path hash: ${error.message}`);
240
- const hash = getContentHash(image.path);
241
- fileName = `diagram-${hash}${ext}`;
242
- }
243
- }
244
-
245
- const destPath = path.join(assetDir, fileName);
246
-
247
- // Copy image from temp directory to assets directory
248
- try {
249
- // Check if source file exists
250
- if (!(await fs.pathExists(image.path))) {
251
- console.error(`Source image file does not exist: ${image.path}`);
252
- return { content: finalContent };
253
- }
254
-
255
- // Always overwrite existing file (since filename is based on document + position)
256
- // This ensures updates replace old images
257
- if (await fs.pathExists(destPath)) {
258
- debug(`Overwriting existing diagram image: ${destPath}`);
259
- }
260
- // Compress the image directly to destination path
261
- try {
262
- debug(`Compressing image directly to destination: ${image.path} -> ${destPath}`);
263
- const compressedPath = await compressImage(image.path, {
264
- quality: 85,
265
- outputPath: destPath,
266
- });
267
-
268
- // If compression failed, fallback to copying original file
269
- if (compressedPath === image.path) {
270
- debug(`Compression failed, copying original file: ${image.path}`);
271
- await copyFile(image.path, destPath);
272
- }
273
- debug(`✅ Diagram image saved to: ${destPath}`);
274
- } catch (error) {
275
- debug(`Image compression failed, copying original: ${error.message}`);
276
- // Fallback to copying original file if compression fails
277
- await copyFile(image.path, destPath);
278
- debug(`✅ Diagram image saved to: ${destPath}`);
279
- }
280
- } catch (error) {
281
- console.error(
282
- `Failed to copy diagram image from ${image.path} to ${destPath}: ${error.message}`,
283
- );
284
- debug(` Source exists: ${await fs.pathExists(image.path)}`);
285
- debug(` Dest dir exists: ${await fs.pathExists(assetDir)}`);
286
- // If copy fails, return content as-is (keep D2 code blocks or placeholder)
287
- return { content: finalContent };
288
- }
289
-
290
- // Generate alt text from document content
291
- const altText = extractAltText(documentContent);
292
-
293
- // Create relative path from markdown file to assets directory
294
- // Documents are saved in docsDir root (flattened paths), images are in docsDir/assets/diagram/
295
- // So relative path is always: assets/diagram/filename.jpg (same directory level)
296
- let relativePath;
297
- if (finalDocsDir && finalDocPath) {
298
- // All documents are in docsDir root (paths are flattened), assets are in docsDir/assets/diagram/
299
- // So relative path is simply: assets/diagram/filename.jpg
300
- relativePath = path.posix.join("assets", "diagram", fileName);
301
- } else {
302
- // Fallback: use the relativePathPrefix determined earlier
303
- relativePath = path.posix.join(relativePathPrefix, fileName);
304
- }
305
-
306
- // Create markdown image reference with markers for easy replacement
307
- // Format: <!-- DIAGRAM_IMAGE_START:type:aspectRatio -->![alt](path)<!-- DIAGRAM_IMAGE_END -->
308
- const diagramTypeTag = diagramType || "unknown";
309
- const aspectRatioTag = aspectRatio || "unknown";
310
- const imageMarkdown = `<!-- DIAGRAM_IMAGE_START:${diagramTypeTag}:${aspectRatioTag} -->\n![${altText}](${relativePath})\n<!-- DIAGRAM_IMAGE_END -->`;
311
-
312
- // Note: diagramLocations was already found above for filename generation, reuse it
313
-
314
- // Debug: log found locations
315
- if (diagramLocations.length > 0) {
316
- debug(
317
- `Found ${diagramLocations.length} diagram location(s):`,
318
- diagramLocations.map((loc) => `${loc.type} at ${loc.start}-${loc.end}`).join(", "),
319
- );
320
- }
321
-
322
- // Determine which diagram to replace
323
- // Note: targetIndex was already calculated above for filename generation, reuse it
324
-
325
- if (targetIndex < 0 || targetIndex >= diagramLocations.length) {
326
- // If index is out of range, default to first available or insert new
327
- targetIndex = diagramLocations.length > 0 ? 0 : -1;
328
- }
329
-
330
- // Replace DIAGRAM_PLACEHOLDER first (highest priority)
331
- // Check both finalContent and documentContent for placeholder
332
- const hasPlaceholder =
333
- finalContent.includes(DIAGRAM_PLACEHOLDER) || documentContent?.includes(DIAGRAM_PLACEHOLDER);
334
-
335
- if (hasPlaceholder) {
336
- debug("Replacing DIAGRAM_PLACEHOLDER");
337
- // Use documentContent if it has placeholder, otherwise use finalContent
338
- const contentWithPlaceholder = documentContent?.includes(DIAGRAM_PLACEHOLDER)
339
- ? documentContent
340
- : finalContent;
341
- finalContent = contentWithPlaceholder.replace(DIAGRAM_PLACEHOLDER, imageMarkdown);
342
- } else if (diagramLocations.length > 0 && targetIndex >= 0) {
343
- // Replace the diagram at the specified index
344
- // Use originalContent if available (for accurate position), otherwise use finalContent
345
- const contentToReplace = originalContent || finalContent;
346
- const targetLocation = diagramLocations[targetIndex];
347
- if (targetLocation) {
348
- debug(
349
- `Replacing diagram at index ${targetIndex} (type: ${targetLocation.type}, position: ${targetLocation.start}-${targetLocation.end})`,
350
- );
351
- const beforeReplace = contentToReplace.slice(0, targetLocation.start);
352
- const afterReplace = contentToReplace.slice(targetLocation.end);
353
- finalContent = beforeReplace + imageMarkdown + afterReplace;
354
- } else {
355
- debug(`⚠️ Target location at index ${targetIndex} not found`);
356
- }
357
- } else {
358
- // No diagrams found and no placeholder
359
- // This can happen when:
360
- // 1. User requests to update a diagram but no diagrams exist in the document
361
- // 2. New document generation without any diagram markers
362
- // In this case, append the diagram to the end of the document
363
- debug("⚠️ No diagram location found to replace. Appending diagram to end of document.");
364
- debug(` - Content length: ${finalContent.length}`);
365
- debug(` - Contains DIAGRAM_PLACEHOLDER: ${finalContent.includes(DIAGRAM_PLACEHOLDER)}`);
366
- debug(` - Contains DIAGRAM_IMAGE_START: ${finalContent.includes("DIAGRAM_IMAGE_START")}`);
367
- debug(` - Contains \`\`\`d2: ${finalContent.includes("```d2")}`);
368
- debug(` - Contains \`\`\`mermaid: ${finalContent.includes("```mermaid")}`);
369
-
370
- // Append diagram to the end of the document with proper spacing
371
- const trimmedContent = finalContent.trimEnd();
372
- const separator = trimmedContent && !trimmedContent.endsWith("\n") ? "\n\n" : "\n";
373
- finalContent = trimmedContent + separator + imageMarkdown;
374
- }
375
-
376
- // Sync diagram images to translation files
377
- // Only sync if we actually replaced/added a diagram (not just returned original content)
378
- if (finalContent !== (originalContent || documentContent || content || "")) {
379
- try {
380
- const { syncDiagramToTranslations } = await import(
381
- "../../utils/sync-diagram-to-translations.mjs"
382
- );
383
- const syncResult = await syncDiagramToTranslations(
384
- finalContent,
385
- finalDocPath,
386
- finalDocsDir,
387
- locale,
388
- "update", // Operation type: update - skip if main has 0 diagrams
389
- );
390
- if (syncResult.updated > 0) {
391
- debug(
392
- `✅ Synced diagram images to ${syncResult.updated} translation file(s)${syncResult.errors.length > 0 ? ` (${syncResult.errors.length} error(s))` : ""}`,
393
- );
394
- }
395
- } catch (error) {
396
- // Don't fail the whole operation if sync fails
397
- debug(`⚠️ Failed to sync diagram to translations: ${error.message}`);
398
- }
399
- }
400
-
401
- return { content: finalContent };
402
- }
403
-
404
- /**
405
- * Find all diagram locations in content
406
- * Returns array of { type, start, end } for each diagram found
407
- * Types: 'placeholder', 'image', 'd2', 'mermaid'
408
- */
409
- function findAllDiagramLocations(content) {
410
- const locations = [];
411
-
412
- // 1. Find DIAGRAM_PLACEHOLDER
413
- let placeholderIndex = content.indexOf(DIAGRAM_PLACEHOLDER);
414
- while (placeholderIndex !== -1) {
415
- locations.push({
416
- type: "placeholder",
417
- start: placeholderIndex,
418
- end: placeholderIndex + DIAGRAM_PLACEHOLDER.length,
419
- });
420
- placeholderIndex = content.indexOf(DIAGRAM_PLACEHOLDER, placeholderIndex + 1);
421
- }
422
-
423
- // 2. Find DIAGRAM_IMAGE_START markers
424
- // Format: <!-- DIAGRAM_IMAGE_START:type:aspectRatio -->...<!-- DIAGRAM_IMAGE_END -->
425
- // Note: aspectRatio can contain colon (e.g., "16:9"), so we need to match until -->
426
- const imageMatches = Array.from(content.matchAll(diagramImageBlockRegex));
427
- for (const match of imageMatches) {
428
- locations.push({
429
- type: "image",
430
- start: match.index,
431
- end: match.index + match[0].length,
432
- });
433
- }
434
-
435
- // 3. Find D2 code blocks
436
- // Note: .* matches title or other text after ```d2 (e.g., ```d2 Vault 驗證流程)
437
- const d2Matches = Array.from(content.matchAll(d2CodeBlockRegex));
438
- for (const match of d2Matches) {
439
- locations.push({
440
- type: "d2",
441
- start: match.index,
442
- end: match.index + match[0].length,
443
- });
444
- }
445
-
446
- // 4. Find Mermaid code blocks
447
- // Note: .* matches title or other text after ```mermaid (e.g., ```mermaid Flow Chart)
448
- const mermaidCodeBlockRegex = /```mermaid.*\n([\s\S]*?)```/g;
449
- const mermaidMatches = Array.from(content.matchAll(mermaidCodeBlockRegex));
450
- for (const match of mermaidMatches) {
451
- locations.push({
452
- type: "mermaid",
453
- start: match.index,
454
- end: match.index + match[0].length,
455
- });
456
- }
457
-
458
- // Sort by position in document (top to bottom)
459
- locations.sort((a, b) => a.start - b.start);
460
-
461
- return locations;
462
- }
463
-
464
- /**
465
- * Extract diagram index from feedback
466
- * Returns 0-based index, or null if not specified
467
- * Examples: "first diagram" -> 0, "second diagram" -> 1, "第2张图" -> 1
468
- */
469
- export function extractDiagramIndexFromFeedback(feedback) {
470
- if (!feedback) return null;
471
-
472
- const feedbackLower = feedback.toLowerCase();
473
-
474
- // Check Chinese patterns first (more specific)
475
- // Examples: "第一张图", "第二张图", "第2张图"
476
- const chinesePattern = /第([一二三四五六七八九十]|\d+)[张个]图/i;
477
- const chineseMatch = feedbackLower.match(chinesePattern);
478
- if (chineseMatch?.[1]) {
479
- const chineseNumbers = {
480
- 一: 1,
481
- 二: 2,
482
- 三: 3,
483
- 四: 4,
484
- 五: 5,
485
- 六: 6,
486
- 七: 7,
487
- 八: 8,
488
- 九: 9,
489
- 十: 10,
490
- };
491
- const numStr = chineseMatch[1];
492
- const num = chineseNumbers[numStr] || parseInt(numStr, 10);
493
- return num > 0 ? num - 1 : 0; // Convert to 0-based index
494
- }
495
-
496
- // Check number patterns (diagram #2, image 3, etc.)
497
- const numberPattern = /(?:diagram|image|picture|chart|graph)\s*#?(\d+)/i;
498
- const numberMatch = feedbackLower.match(numberPattern);
499
- if (numberMatch?.[1]) {
500
- const num = parseInt(numberMatch[1], 10);
501
- return num > 0 ? num - 1 : 0; // Convert to 0-based index
502
- }
503
-
504
- // Check ordinal patterns (first, second, third, etc.)
505
- const ordinalMap = {
506
- first: 0,
507
- "1st": 0,
508
- 1: 0,
509
- second: 1,
510
- "2nd": 1,
511
- 2: 1,
512
- third: 2,
513
- "3rd": 2,
514
- 3: 2,
515
- fourth: 3,
516
- "4th": 3,
517
- 4: 3,
518
- fifth: 4,
519
- "5th": 4,
520
- 5: 4,
521
- };
522
-
523
- for (const [ordinal, index] of Object.entries(ordinalMap)) {
524
- const ordinalPattern = new RegExp(
525
- `(?:${ordinal})\\s+(?:diagram|image|picture|chart|graph)`,
526
- "i",
527
- );
528
- if (ordinalPattern.test(feedbackLower)) {
529
- return index;
530
- }
531
- }
532
-
533
- return null;
534
- }
535
-
536
- /**
537
- * Extract alt text from document content
538
- */
539
- function extractAltText(documentContent) {
540
- if (!documentContent) return "Diagram";
541
-
542
- const lines = documentContent.split("\n").filter((line) => line.trim());
543
- if (lines.length > 0) {
544
- let altText = lines[0].trim();
545
- // Remove markdown headers
546
- altText = altText.replace(/^#+\s*/, "");
547
- if (altText.length > 100) {
548
- altText = `${altText.substring(0, 97)}...`;
549
- }
550
- return altText || "Diagram";
551
- }
552
- return "Diagram";
553
- }
554
-
555
- replaceD2WithImage.input_schema = {
556
- type: "object",
557
- properties: {
558
- images: {
559
- type: "array",
560
- description: "Images array from image generation agent",
561
- },
562
- imageResult: {
563
- type: "object",
564
- description: "The result from image generation agent (fallback)",
565
- },
566
- content: {
567
- type: "string",
568
- description: "The document content (may contain DIAGRAM_PLACEHOLDER)",
569
- },
570
- documentContent: {
571
- type: "string",
572
- description: "Original document content containing DIAGRAM_PLACEHOLDER",
573
- },
574
- diagramType: {
575
- type: "string",
576
- description: "The diagram type (for marking the image)",
577
- enum: ["architecture", "flowchart", "guide", "intro", "sequence", "network"],
578
- },
579
- aspectRatio: {
580
- type: "string",
581
- description: "The aspect ratio of the diagram (for marking the image)",
582
- enum: ["1:1", "5:4", "4:3", "3:2", "16:9", "21:9"],
583
- },
584
- diagramIndex: {
585
- type: "number",
586
- description:
587
- "Index of the diagram to replace (0-based). If not provided, will try to extract from feedback (e.g., 'first diagram' -> 0, 'second diagram' -> 1), otherwise defaults to 0.",
588
- },
589
- originalContent: {
590
- type: "string",
591
- description:
592
- "Original document content before any modifications. Used to find existing diagrams when updating.",
593
- },
594
- path: {
595
- type: "string",
596
- description:
597
- "Document path (e.g., 'guides/getting-started.md') used for generating image filename",
598
- },
599
- docsDir: {
600
- type: "string",
601
- description: "Documentation directory where assets will be saved (relative to project root)",
602
- },
603
- locale: {
604
- type: "string",
605
- description: "Main language locale (e.g., 'en', 'zh') for syncing to translations",
606
- default: "en",
607
- },
608
- feedback: {
609
- type: "string",
610
- description: "User feedback (for extracting diagram index)",
611
- },
612
- },
613
- required: ["documentContent"],
614
- };
615
-
616
- replaceD2WithImage.output_schema = {
617
- type: "object",
618
- properties: {
619
- content: {
620
- type: "string",
621
- description: "Document content with D2 code blocks replaced by image",
622
- },
623
- },
624
- required: ["content"],
625
- };
@@ -1,54 +0,0 @@
1
- type: team
2
- name: updateDocumentStructure
3
- description: Update documentation structure based on user feedback and intentions using structure modification tools
4
- skills:
5
- - url: ../utils/analyze-structure-feedback-intent.yaml
6
- - type: ai
7
- instructions:
8
- - role: system
9
- url: ../../prompts/structure/update/system-prompt.md
10
- - role: user
11
- url: ../../prompts/structure/update/user-prompt.md
12
- input_schema:
13
- type: object
14
- properties:
15
- documentStructure: ../schema/document-structure.yaml
16
- rules:
17
- type: string
18
- description: User configuration rules
19
- locale:
20
- type: string
21
- description: User language, e.g. zh, en
22
- dataSourceChunk:
23
- type: string
24
- description: Context for documentation structure
25
- glossary:
26
- type: string
27
- description: Glossary of terms
28
- feedback:
29
- type: string
30
- description: User feedback for structure modifications
31
- userPreferences:
32
- type: string
33
- description: Your saved preferences for structure and documentation style
34
- needDataSources:
35
- type: boolean
36
- description: Whether data sources are needed for content modifications
37
- required:
38
- - documentStructure
39
- - feedback
40
- output_key: message
41
- afs:
42
- modules:
43
- - module: system-fs
44
- options:
45
- name: sources
46
- localPath: .
47
- description: |
48
- Codebase of the project to be documented used as context for document generation,
49
- should search and read as needed while generating document content
50
- skills:
51
- - ./document-structure-tools/add-document.mjs
52
- - ./document-structure-tools/delete-document.mjs
53
- - ./document-structure-tools/update-document.mjs
54
- - ./document-structure-tools/move-document.mjs