@aigne/doc-smith 0.9.10 → 0.9.11-beta

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 (308) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +189 -219
  3. package/README.zh.md +270 -0
  4. package/agents/bash-executor/index.mjs +347 -0
  5. package/agents/clear/ai/intent.md +142 -0
  6. package/agents/clear/choose-contents.mjs +13 -65
  7. package/agents/clear/clear-auth-tokens.mjs +17 -21
  8. package/agents/clear/clear-deployment-config.mjs +33 -24
  9. package/agents/clear/index.yaml +1 -9
  10. package/agents/content-checker/ai/intent.md +209 -0
  11. package/agents/content-checker/clean-invalid-docs.mjs +254 -0
  12. package/agents/content-checker/index.mjs +191 -0
  13. package/agents/content-checker/validate-content.mjs +983 -0
  14. package/agents/generate-images/generate-image.yaml +75 -0
  15. package/agents/generate-images/generate-summary.mjs +213 -0
  16. package/agents/generate-images/index.yaml +39 -0
  17. package/agents/generate-images/prepare-generation.mjs +286 -0
  18. package/agents/generate-images/prepare-image-generation.mjs +130 -0
  19. package/{prompts/detail/diagram/generate-image-system.md → agents/generate-images/prompts/system.md} +22 -56
  20. package/agents/generate-images/prompts/user.md +85 -0
  21. package/agents/generate-images/save-image-result.mjs +247 -0
  22. package/agents/generate-images/scan-image-slots.mjs +247 -0
  23. package/agents/localize/index.yaml +19 -42
  24. package/{prompts/translate → agents/localize/prompts}/translate-document.md +0 -139
  25. package/agents/localize/translate-documents/generate-summary.mjs +163 -0
  26. package/agents/localize/translate-documents/load-glossary.mjs +52 -0
  27. package/agents/localize/translate-documents/prepare-translation.mjs +249 -0
  28. package/agents/localize/translate-documents/save-translation.mjs +171 -0
  29. package/agents/localize/translate-documents/translate-document-to-language.mjs +209 -0
  30. package/agents/localize/translate-documents/translate-document.yaml +23 -0
  31. package/agents/localize/translate-documents/translate-to-languages.yaml +10 -0
  32. package/agents/localize/translate-images/check-image-translation.mjs +225 -0
  33. package/agents/localize/translate-images/detect-text/detect-and-update-shared.mjs +148 -0
  34. package/agents/localize/translate-images/detect-text/detect-image-text.yaml +44 -0
  35. package/agents/localize/translate-images/detect-text/detect-images-text.yaml +21 -0
  36. package/agents/localize/translate-images/detect-text/prompts/detect-image-text-system.md +43 -0
  37. package/agents/localize/translate-images/detect-text/prompts/detect-image-text-user.md +14 -0
  38. package/agents/localize/translate-images/detect-text/save-text-detection.mjs +105 -0
  39. package/agents/localize/translate-images/prepare-image-input.mjs +124 -0
  40. package/agents/localize/translate-images/save-image-translation.mjs +172 -0
  41. package/agents/localize/translate-images/scan-doc-images.mjs +165 -0
  42. package/agents/localize/translate-images/translate-doc-images.yaml +24 -0
  43. package/agents/localize/{translate-diagram.yaml → translate-images/translate-image.yaml} +25 -14
  44. package/agents/publish/ai/intent.md +182 -0
  45. package/agents/publish/check.mjs +107 -0
  46. package/agents/publish/index.yaml +9 -14
  47. package/agents/publish/publish-docs.mjs +81 -61
  48. package/agents/publish/translate-meta.mjs +79 -58
  49. package/agents/save-document/index.mjs +260 -0
  50. package/agents/structure-checker/index.mjs +307 -0
  51. package/agents/structure-checker/validate-structure.mjs +477 -0
  52. package/agents/update-image/analyze-feedback.yaml +37 -0
  53. package/agents/update-image/index.yaml +78 -0
  54. package/agents/update-image/load-existing-image.mjs +211 -0
  55. package/agents/update-image/prompts/analyze-feedback-system.md +43 -0
  56. package/agents/update-image/prompts/analyze-feedback-user.md +15 -0
  57. package/aigne.yaml +26 -139
  58. package/package.json +16 -48
  59. package/scripts/README.md +90 -0
  60. package/scripts/install.sh +86 -0
  61. package/scripts/uninstall.sh +52 -0
  62. package/skills/doc-smith/SKILL.md +285 -0
  63. package/skills/doc-smith/ai/intent/sources-improve.md +290 -0
  64. package/skills/doc-smith/references/changeset-guide.md +171 -0
  65. package/skills/doc-smith/references/document-content-guide.md +214 -0
  66. package/skills/doc-smith/references/document-structure-schema.md +138 -0
  67. package/skills/doc-smith/references/patch-guide.md +96 -0
  68. package/skills/doc-smith/references/structure-confirmation-guide.md +133 -0
  69. package/skills/doc-smith/references/structure-planning-guide.md +149 -0
  70. package/skills/doc-smith/references/update-workflow.md +108 -0
  71. package/skills/doc-smith/references/user-intent-guide.md +175 -0
  72. package/skills/doc-smith/references/workspace-initialization.md +376 -0
  73. package/skills/doc-smith-docs-detail/SKILL.md +356 -0
  74. package/skills/doc-smith-docs-detail/ai/intent.md +271 -0
  75. package/skills-entry/doc-smith/ai/intent.md +260 -0
  76. package/skills-entry/doc-smith/index.mjs +66 -0
  77. package/skills-entry/doc-smith/prompt.md +57 -0
  78. package/skills-entry/doc-smith/utils.mjs +27 -0
  79. package/skills-entry/doc-smith-docs-detail/batch.yaml +56 -0
  80. package/skills-entry/doc-smith-docs-detail/index.mjs +95 -0
  81. package/skills-entry/doc-smith-docs-detail/prompt.md +64 -0
  82. package/utils/afs-factory.mjs +183 -0
  83. package/utils/agent-constants.mjs +97 -0
  84. package/utils/{auth-utils.mjs → auth.mjs} +6 -9
  85. package/{agents/utils/update-branding.mjs → utils/branding.mjs} +3 -4
  86. package/utils/config.mjs +261 -0
  87. package/utils/constants.mjs +32 -0
  88. package/utils/deploy.mjs +3 -3
  89. package/utils/docs-converter.mjs +454 -0
  90. package/utils/docs.mjs +212 -0
  91. package/utils/document-paths.mjs +172 -0
  92. package/utils/files.mjs +74 -0
  93. package/utils/git.mjs +65 -0
  94. package/utils/{blocklet.mjs → http.mjs} +18 -0
  95. package/utils/image-slots.mjs +57 -0
  96. package/utils/image-utils.mjs +114 -0
  97. package/utils/project.mjs +95 -0
  98. package/utils/sources-path-resolver.mjs +76 -0
  99. package/utils/{upload-files.mjs → upload.mjs} +3 -3
  100. package/utils/workspace.mjs +371 -0
  101. package/agents/chat/chat-system.md +0 -38
  102. package/agents/chat/index.mjs +0 -59
  103. package/agents/chat/skills/generate-document.yaml +0 -15
  104. package/agents/chat/skills/list-documents.mjs +0 -15
  105. package/agents/chat/skills/update-document.yaml +0 -24
  106. package/agents/clear/clear-document-config.mjs +0 -36
  107. package/agents/clear/clear-document-structure.mjs +0 -102
  108. package/agents/clear/clear-generated-docs.mjs +0 -142
  109. package/agents/clear/clear-media-description.mjs +0 -129
  110. package/agents/create/aggregate-document-structure.mjs +0 -21
  111. package/agents/create/analyze-diagram-type-llm.yaml +0 -159
  112. package/agents/create/analyze-diagram-type.mjs +0 -455
  113. package/agents/create/check-document-structure.yaml +0 -30
  114. package/agents/create/check-need-generate-structure.mjs +0 -138
  115. package/agents/create/document-structure-tools/add-document.mjs +0 -85
  116. package/agents/create/document-structure-tools/delete-document.mjs +0 -116
  117. package/agents/create/document-structure-tools/move-document.mjs +0 -109
  118. package/agents/create/document-structure-tools/update-document.mjs +0 -84
  119. package/agents/create/generate-diagram-image.yaml +0 -91
  120. package/agents/create/generate-structure.yaml +0 -106
  121. package/agents/create/index.yaml +0 -45
  122. package/agents/create/refine-document-structure.yaml +0 -12
  123. package/agents/create/replace-d2-with-image.mjs +0 -610
  124. package/agents/create/update-document-structure.yaml +0 -54
  125. package/agents/create/user-add-document/add-documents-to-structure.mjs +0 -90
  126. package/agents/create/user-add-document/find-documents-to-add-links.yaml +0 -47
  127. package/agents/create/user-add-document/index.yaml +0 -46
  128. package/agents/create/user-add-document/prepare-documents-to-translate.mjs +0 -22
  129. package/agents/create/user-add-document/print-add-document-summary.mjs +0 -63
  130. package/agents/create/user-add-document/review-documents-with-new-links.mjs +0 -110
  131. package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +0 -78
  132. package/agents/create/user-remove-document/index.yaml +0 -40
  133. package/agents/create/user-remove-document/prepare-documents-to-translate.mjs +0 -22
  134. package/agents/create/user-remove-document/print-remove-document-summary.mjs +0 -53
  135. package/agents/create/user-remove-document/remove-documents-from-structure.mjs +0 -99
  136. package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +0 -115
  137. package/agents/create/user-review-document-structure.mjs +0 -139
  138. package/agents/create/utils/init-current-content.mjs +0 -34
  139. package/agents/create/utils/merge-document-structures.mjs +0 -36
  140. package/agents/evaluate/code-snippet.mjs +0 -97
  141. package/agents/evaluate/document-structure.yaml +0 -67
  142. package/agents/evaluate/document.yaml +0 -82
  143. package/agents/evaluate/generate-report.mjs +0 -85
  144. package/agents/evaluate/index.yaml +0 -46
  145. package/agents/history/index.yaml +0 -6
  146. package/agents/history/view.mjs +0 -78
  147. package/agents/init/check.mjs +0 -16
  148. package/agents/init/index.mjs +0 -643
  149. package/agents/init/validate.mjs +0 -16
  150. package/agents/localize/choose-language.mjs +0 -107
  151. package/agents/localize/record-translation-history.mjs +0 -23
  152. package/agents/localize/save-doc-translation-or-skip.mjs +0 -18
  153. package/agents/localize/set-review-content.mjs +0 -58
  154. package/agents/localize/translate-document-wrapper.mjs +0 -34
  155. package/agents/localize/translate-document.yaml +0 -24
  156. package/agents/localize/translate-multilingual.yaml +0 -57
  157. package/agents/localize/translate-or-skip-diagram.mjs +0 -52
  158. package/agents/media/batch-generate-media-description.yaml +0 -46
  159. package/agents/media/generate-media-description.yaml +0 -50
  160. package/agents/media/load-media-description.mjs +0 -454
  161. package/agents/prefs/index.mjs +0 -203
  162. package/agents/schema/document-structure-item.yaml +0 -26
  163. package/agents/schema/document-structure-refine-item.yaml +0 -23
  164. package/agents/schema/document-structure.yaml +0 -29
  165. package/agents/update/batch-generate-document.yaml +0 -27
  166. package/agents/update/batch-update-document.yaml +0 -7
  167. package/agents/update/check-diagram-flag.mjs +0 -116
  168. package/agents/update/check-document.mjs +0 -162
  169. package/agents/update/check-generate-diagram.mjs +0 -106
  170. package/agents/update/check-update-is-single.mjs +0 -53
  171. package/agents/update/document-tools/update-document-content.mjs +0 -303
  172. package/agents/update/generate-diagram.yaml +0 -80
  173. package/agents/update/generate-document.yaml +0 -70
  174. package/agents/update/handle-document-update.yaml +0 -103
  175. package/agents/update/index.yaml +0 -69
  176. package/agents/update/pre-check-generate-diagram.yaml +0 -44
  177. package/agents/update/save-and-translate-document.mjs +0 -80
  178. package/agents/update/update-document-detail.yaml +0 -71
  179. package/agents/update/update-single/update-single-document-detail.mjs +0 -322
  180. package/agents/update/update-single-document.yaml +0 -7
  181. package/agents/update/user-review-document.mjs +0 -272
  182. package/agents/utils/action-success.mjs +0 -16
  183. package/agents/utils/analyze-document-feedback-intent.yaml +0 -32
  184. package/agents/utils/analyze-feedback-intent.mjs +0 -253
  185. package/agents/utils/analyze-structure-feedback-intent.yaml +0 -29
  186. package/agents/utils/check-detail-result.mjs +0 -51
  187. package/agents/utils/check-feedback-refiner.mjs +0 -81
  188. package/agents/utils/choose-docs.mjs +0 -251
  189. package/agents/utils/document-icon-generate.yaml +0 -52
  190. package/agents/utils/document-title-streamline.yaml +0 -48
  191. package/agents/utils/ensure-document-icons.mjs +0 -129
  192. package/agents/utils/exit.mjs +0 -6
  193. package/agents/utils/feedback-refiner.yaml +0 -50
  194. package/agents/utils/find-item-by-path.mjs +0 -114
  195. package/agents/utils/find-user-preferences-by-path.mjs +0 -37
  196. package/agents/utils/format-document-structure.mjs +0 -35
  197. package/agents/utils/generate-document-or-skip.mjs +0 -41
  198. package/agents/utils/handle-diagram-operations.mjs +0 -263
  199. package/agents/utils/load-all-document-content.mjs +0 -30
  200. package/agents/utils/load-document-all-content.mjs +0 -96
  201. package/agents/utils/load-sources.mjs +0 -405
  202. package/agents/utils/map-reasoning-effort-level.mjs +0 -15
  203. package/agents/utils/post-generate.mjs +0 -133
  204. package/agents/utils/read-current-document-content.mjs +0 -46
  205. package/agents/utils/save-doc-translation.mjs +0 -30
  206. package/agents/utils/save-doc.mjs +0 -54
  207. package/agents/utils/save-output.mjs +0 -26
  208. package/agents/utils/save-sidebar.mjs +0 -38
  209. package/agents/utils/skip-if-content-exists.mjs +0 -27
  210. package/agents/utils/streamline-document-titles-if-needed.mjs +0 -88
  211. package/agents/utils/transform-detail-data-sources.mjs +0 -45
  212. package/assets/report-template/report.html +0 -198
  213. package/docs-mcp/analyze-content-relevance.yaml +0 -50
  214. package/docs-mcp/analyze-docs-relevance.yaml +0 -59
  215. package/docs-mcp/docs-search.yaml +0 -42
  216. package/docs-mcp/get-docs-detail.mjs +0 -41
  217. package/docs-mcp/get-docs-structure.mjs +0 -16
  218. package/docs-mcp/read-doc-content.mjs +0 -119
  219. package/prompts/common/document/content-rules-core.md +0 -20
  220. package/prompts/common/document/markdown-syntax-rules.md +0 -65
  221. package/prompts/common/document/media-file-list-usage-rules.md +0 -18
  222. package/prompts/common/document/openapi-usage-rules.md +0 -189
  223. package/prompts/common/document/role-and-personality.md +0 -16
  224. package/prompts/common/document/user-preferences.md +0 -9
  225. package/prompts/common/document-structure/conflict-resolution-guidance.md +0 -16
  226. package/prompts/common/document-structure/document-icon-generate.md +0 -116
  227. package/prompts/common/document-structure/document-structure-rules.md +0 -43
  228. package/prompts/common/document-structure/document-title-streamline.md +0 -86
  229. package/prompts/common/document-structure/glossary.md +0 -7
  230. package/prompts/common/document-structure/intj-traits.md +0 -5
  231. package/prompts/common/document-structure/openapi-usage-rules.md +0 -28
  232. package/prompts/common/document-structure/output-constraints.md +0 -18
  233. package/prompts/common/document-structure/user-locale-rules.md +0 -10
  234. package/prompts/common/document-structure/user-preferences.md +0 -9
  235. package/prompts/detail/custom/admonition-usage-rules.md +0 -94
  236. package/prompts/detail/custom/code-block-usage-rules.md +0 -163
  237. package/prompts/detail/custom/custom-components/x-card-usage-rules.md +0 -63
  238. package/prompts/detail/custom/custom-components/x-cards-usage-rules.md +0 -83
  239. package/prompts/detail/custom/custom-components/x-field-desc-usage-rules.md +0 -120
  240. package/prompts/detail/custom/custom-components/x-field-group-usage-rules.md +0 -80
  241. package/prompts/detail/custom/custom-components/x-field-usage-rules.md +0 -189
  242. package/prompts/detail/custom/custom-components-usage-rules.md +0 -18
  243. package/prompts/detail/diagram/generate-image-user.md +0 -81
  244. package/prompts/detail/diagram/guide.md +0 -29
  245. package/prompts/detail/diagram/official-examples.md +0 -712
  246. package/prompts/detail/diagram/pre-check.md +0 -23
  247. package/prompts/detail/diagram/role-and-personality.md +0 -2
  248. package/prompts/detail/diagram/rules.md +0 -46
  249. package/prompts/detail/diagram/system-prompt.md +0 -1139
  250. package/prompts/detail/diagram/user-prompt.md +0 -43
  251. package/prompts/detail/generate/detail-example.md +0 -457
  252. package/prompts/detail/generate/document-rules.md +0 -45
  253. package/prompts/detail/generate/system-prompt.md +0 -61
  254. package/prompts/detail/generate/user-prompt.md +0 -99
  255. package/prompts/detail/jsx/rules.md +0 -6
  256. package/prompts/detail/update/system-prompt.md +0 -121
  257. package/prompts/detail/update/user-prompt.md +0 -41
  258. package/prompts/evaluate/document-structure.md +0 -93
  259. package/prompts/evaluate/document.md +0 -149
  260. package/prompts/media/media-description/system-prompt.md +0 -43
  261. package/prompts/media/media-description/user-prompt.md +0 -17
  262. package/prompts/structure/check-document-structure.md +0 -93
  263. package/prompts/structure/document-rules.md +0 -21
  264. package/prompts/structure/find-documents-to-add-links.md +0 -52
  265. package/prompts/structure/generate/system-prompt.md +0 -13
  266. package/prompts/structure/generate/user-prompt.md +0 -137
  267. package/prompts/structure/review/structure-review-system.md +0 -81
  268. package/prompts/structure/structure-example.md +0 -89
  269. package/prompts/structure/structure-getting-started.md +0 -10
  270. package/prompts/structure/update/system-prompt.md +0 -93
  271. package/prompts/structure/update/user-prompt.md +0 -43
  272. package/prompts/translate/admonition.md +0 -20
  273. package/prompts/translate/code-block.md +0 -33
  274. package/prompts/utils/analyze-document-feedback-intent.md +0 -54
  275. package/prompts/utils/analyze-structure-feedback-intent.md +0 -43
  276. package/prompts/utils/feedback-refiner.md +0 -105
  277. package/types/document-schema.mjs +0 -55
  278. package/types/document-structure-schema.mjs +0 -261
  279. package/utils/check-document-has-diagram.mjs +0 -95
  280. package/utils/conflict-detector.mjs +0 -149
  281. package/utils/constants/index.mjs +0 -620
  282. package/utils/constants/linter.mjs +0 -102
  283. package/utils/d2-utils.mjs +0 -205
  284. package/utils/debug.mjs +0 -3
  285. package/utils/delete-diagram-images.mjs +0 -99
  286. package/utils/diagram-version-utils.mjs +0 -14
  287. package/utils/docs-finder-utils.mjs +0 -548
  288. package/utils/evaluate/report-utils.mjs +0 -132
  289. package/utils/extract-api.mjs +0 -32
  290. package/utils/file-utils.mjs +0 -960
  291. package/utils/history-utils.mjs +0 -203
  292. package/utils/icon-map.mjs +0 -26
  293. package/utils/image-compress.mjs +0 -154
  294. package/utils/kroki-utils.mjs +0 -173
  295. package/utils/linter/index.mjs +0 -50
  296. package/utils/load-config.mjs +0 -78
  297. package/utils/markdown/index.mjs +0 -26
  298. package/utils/markdown-checker.mjs +0 -694
  299. package/utils/mermaid-validator.mjs +0 -140
  300. package/utils/mermaid-worker-pool.mjs +0 -250
  301. package/utils/mermaid-worker.mjs +0 -233
  302. package/utils/openapi/index.mjs +0 -28
  303. package/utils/preferences-utils.mjs +0 -175
  304. package/utils/request.mjs +0 -10
  305. package/utils/sync-diagram-to-translations.mjs +0 -272
  306. package/utils/translate-diagram-images.mjs +0 -807
  307. package/utils/utils.mjs +0 -1354
  308. /package/{prompts/translate → agents/localize/prompts}/glossary.md +0 -0
@@ -1,454 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { existsSync } from "node:fs";
3
- import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
4
- import path from "node:path";
5
- import { parse, stringify } from "yaml";
6
- import { getMediaDescriptionCachePath } from "../../utils/file-utils.mjs";
7
- import { compressImage } from "../../utils/image-compress.mjs";
8
- import sharp from "sharp";
9
- import { debug } from "../../utils/debug.mjs";
10
- import { DOC_SMITH_DIR, TMP_DIR } from "../../utils/constants/index.mjs";
11
- import { ensureTmpDir } from "../../utils/d2-utils.mjs";
12
- import pMap from "p-map";
13
-
14
- const SIZE_THRESHOLD = 10 * 1024 * 1024; // 10MB
15
- const SVG_SIZE_THRESHOLD = 50 * 1024; // 50KB for SVG files
16
- const MAX_IMAGE_SIZE = 1 * 1024 * 1024; // 1MB
17
- const MAX_IMAGE_RESOLUTION = 2048; // 2K
18
-
19
- // Supported MIME types for Gemini AI
20
- const SUPPORTED_IMAGE_TYPES = new Set([
21
- "image/png",
22
- "image/jpeg",
23
- "image/webp",
24
- "image/heic",
25
- "image/heif",
26
- ]);
27
-
28
- const SUPPORTED_SVG_TYPES = new Set(["image/svg+xml"]);
29
-
30
- const SUPPORTED_VIDEO_TYPES = new Set([
31
- "video/mp4",
32
- "video/mpeg",
33
- "video/mov",
34
- "video/avi",
35
- "video/x-flv",
36
- "video/mpg",
37
- "video/webm",
38
- "video/wmv",
39
- "video/3gpp",
40
- ]);
41
-
42
- /**
43
- * Calculate hash for a media file
44
- * For files < 10MB: use file content
45
- * For files >= 10MB: use path + size + mtime to avoid memory issues
46
- * @param {string} absolutePath - The absolute path to the media file
47
- * @returns {Promise<string>} - The hash of the file
48
- */
49
- async function calculateMediaHash(absolutePath) {
50
- const stats = await stat(absolutePath);
51
-
52
- if (stats.size < SIZE_THRESHOLD) {
53
- // Small file: use full content
54
- const content = await readFile(absolutePath);
55
- return createHash("sha256").update(content).digest("hex");
56
- }
57
-
58
- // Large file: use path + size + mtime
59
- const hashInput = `${absolutePath}:${stats.size}:${stats.mtimeMs}`;
60
- return createHash("sha256").update(hashInput).digest("hex");
61
- }
62
-
63
- /**
64
- * Load media descriptions from cache and generate new ones if needed
65
- * @param {Object} input - Input parameters
66
- * @param {Array} input.mediaFiles - Array of media file objects from load-sources
67
- * @param {string} input.docsDir - Base directory for documentation
68
- * @param {Object} options - Agent options
69
- * @returns {Promise<Object>} - Updated assetsContent with media descriptions
70
- */
71
- export default async function loadMediaDescription(input, options) {
72
- const { mediaFiles = [], docsDir } = input;
73
-
74
- // Filter to get image, video and svg files with supported MIME types
75
- const mediaFilesToProcess = mediaFiles.filter((file) => {
76
- if (file.type === "image") {
77
- return SUPPORTED_IMAGE_TYPES.has(file.mimeType) || SUPPORTED_SVG_TYPES.has(file.mimeType);
78
- }
79
- if (file.type === "video") {
80
- return SUPPORTED_VIDEO_TYPES.has(file.mimeType);
81
- }
82
- return false;
83
- });
84
-
85
- // Path to media description cache file
86
- const cacheFilePath = getMediaDescriptionCachePath();
87
-
88
- // Load existing cache
89
- let cache = {};
90
- if (existsSync(cacheFilePath)) {
91
- try {
92
- const cacheContent = await readFile(cacheFilePath, "utf8");
93
- const parsedCache = parse(cacheContent);
94
- cache = parsedCache?.descriptions || {};
95
- } catch (error) {
96
- console.warn("Failed to read media description cache:", error.message);
97
- }
98
- }
99
-
100
- // Find media files without descriptions
101
- const mediaToDescribe = [];
102
- const mediaHashMap = new Map();
103
-
104
- const absoluteDocsDir = path.resolve(process.cwd(), docsDir);
105
-
106
- // Only process media files that need AI description
107
- for (const mediaFile of mediaFilesToProcess) {
108
- // Convert relative path to absolute path for consistent hashing
109
- // mediaFiles.path is relative to docsDir
110
- const absolutePath = path.join(absoluteDocsDir, mediaFile.path);
111
- const mediaHash = await calculateMediaHash(absolutePath);
112
- mediaHashMap.set(mediaFile.path, mediaHash);
113
-
114
- if (!cache[mediaHash]) {
115
- const isSvg = SUPPORTED_SVG_TYPES.has(mediaFile.mimeType);
116
-
117
- if (isSvg) {
118
- // For SVG files, check size and read content
119
- try {
120
- const stats = await stat(absolutePath);
121
- if (stats.size > SVG_SIZE_THRESHOLD) {
122
- console.warn(
123
- `SVG file ${mediaFile.path} exceeds ${SVG_SIZE_THRESHOLD / 1024}KB limit, skipping`,
124
- );
125
- continue;
126
- }
127
-
128
- const svgContent = await readFile(absolutePath, "utf8");
129
- mediaToDescribe.push({
130
- ...mediaFile,
131
- hash: mediaHash,
132
- path: mediaFile.path,
133
- svgContent,
134
- });
135
- } catch (error) {
136
- console.warn(`Failed to read SVG file ${mediaFile.path}:`, error.message);
137
- }
138
- } else {
139
- // For non-SVG media files, check if compression is needed
140
- let finalImagePath = absolutePath;
141
- let shouldCompress = false;
142
-
143
- try {
144
- // Check file size and dimensions
145
- const fileStats = await stat(absolutePath);
146
- const fileSize = fileStats.size;
147
-
148
- // Get image dimensions
149
- const metadata = await sharp(absolutePath).metadata();
150
- const { width, height } = metadata;
151
-
152
- // Determine if compression is needed
153
- // Compression rules:
154
- // 1. Only compress files larger than 1MB
155
- // 2. Compressed file must have resolution <= 2K and size < 1MB
156
- // 3. Files <= 1MB are never compressed, regardless of resolution
157
- const exceedsSize = fileSize > MAX_IMAGE_SIZE;
158
-
159
- // Only compress if file size > 1MB
160
- // For files <= 1MB, skip compression regardless of resolution
161
- if (exceedsSize) {
162
- // Create temporary compressed file path in temp directory with same relative structure
163
- // Example: docs/assets/images/photo.jpg -> .aigne/doc-smith/.tmp/docs/assets/images/photo.compressed.jpg
164
- await ensureTmpDir();
165
- const tmpBaseDir = path.join(process.cwd(), DOC_SMITH_DIR, TMP_DIR);
166
-
167
- // Get relative path from docsDir to maintain structure
168
- // mediaFile.path is already relative to docsDir (e.g., "assets/images/photo.jpg")
169
- const relativePath = mediaFile.path;
170
- const relativeDir = path.dirname(relativePath);
171
- const fileName = path.basename(relativePath, path.extname(relativePath));
172
- const fileExt = path.extname(relativePath);
173
-
174
- // Normalize docsDir to handle both relative and absolute paths
175
- // If docsDir is absolute, extract the relative part from cwd
176
- let normalizedDocsDir = docsDir;
177
- if (path.isAbsolute(docsDir)) {
178
- const cwd = process.cwd();
179
- if (docsDir.startsWith(cwd)) {
180
- normalizedDocsDir = path.relative(cwd, docsDir);
181
- } else {
182
- // If docsDir is outside cwd, use just the basename
183
- normalizedDocsDir = path.basename(docsDir);
184
- }
185
- }
186
-
187
- // Create temp directory structure matching the relative path
188
- // Structure: .aigne/doc-smith/.tmp/{docsDir}/{relativeDir}
189
- const tempDir = path.join(tmpBaseDir, normalizedDocsDir, relativeDir);
190
- await mkdir(tempDir, { recursive: true });
191
-
192
- // Create compressed file path
193
- const tempFileName = `${fileName}.compressed${fileExt}`;
194
- const tempPath = path.join(tempDir, tempFileName);
195
-
196
- // Check if compressed file already exists in cache directory
197
- if (existsSync(tempPath)) {
198
- debug(`Compressed file already exists for ${mediaFile.path}, skipping compression`);
199
- finalImagePath = tempPath;
200
- shouldCompress = true;
201
- } else {
202
- shouldCompress = true;
203
- debug(
204
- `Compressing image ${mediaFile.path} (size: ${(fileSize / 1024 / 1024).toFixed(2)}MB, resolution: ${width}x${height})`,
205
- );
206
-
207
- // Compress image with constraints
208
- // For files > 1MB: compress to resolution <= 2K and size < 1MB
209
- finalImagePath = await compressImage(absolutePath, {
210
- maxWidth: MAX_IMAGE_RESOLUTION, // Always limit to 2K
211
- maxHeight: MAX_IMAGE_RESOLUTION, // Always limit to 2K
212
- maxSizeBytes: MAX_IMAGE_SIZE, // Always limit to 1MB
213
- outputPath: tempPath,
214
- quality: 70, // Start with good quality
215
- });
216
-
217
- // Verify compressed file size
218
- const compressedStats = await stat(finalImagePath);
219
- if (compressedStats.size > MAX_IMAGE_SIZE) {
220
- console.warn(
221
- `Compressed image ${mediaFile.path} still exceeds ${MAX_IMAGE_SIZE / 1024 / 1024}MB (${(compressedStats.size / 1024 / 1024).toFixed(2)}MB), using compressed version anyway`,
222
- );
223
- } else {
224
- debug(
225
- `✅ Image compressed: ${mediaFile.path} -> ${(compressedStats.size / 1024 / 1024).toFixed(2)}MB`,
226
- );
227
- }
228
- }
229
- } else {
230
- debug(
231
- `Image ${mediaFile.path} is <= 1MB (size: ${(fileSize / 1024 / 1024).toFixed(2)}MB, resolution: ${width}x${height}), skipping compression`,
232
- );
233
- }
234
- } catch (error) {
235
- console.warn(`Failed to compress image ${mediaFile.path}:`, error.message);
236
- // Use original path if compression fails
237
- finalImagePath = absolutePath;
238
- }
239
-
240
- // For non-SVG media files, use mediaFile field
241
- mediaToDescribe.push({
242
- ...mediaFile,
243
- hash: mediaHash,
244
- path: mediaFile.path,
245
- mediaFile: [
246
- {
247
- type: "local",
248
- path: finalImagePath,
249
- filename: mediaFile.name,
250
- mimeType: mediaFile.mimeType,
251
- },
252
- ],
253
- _compressed: shouldCompress, // Track if compression was applied for cleanup
254
- _originalPath: shouldCompress ? absolutePath : undefined, // Store original path for cleanup
255
- });
256
- }
257
- }
258
- }
259
-
260
- // Generate descriptions for media files without cache - batch processing with incremental save
261
- const newDescriptions = {};
262
- const results = []; // Track all results for accurate counting
263
-
264
- if (mediaToDescribe.length > 0) {
265
- // Ensure cache directory exists
266
- await mkdir(path.dirname(cacheFilePath), { recursive: true });
267
-
268
- // Create a write lock queue to ensure thread-safe cache updates
269
- let writeQueue = Promise.resolve();
270
- // Keep in-memory cache in sync to avoid unnecessary file reads
271
- const inMemoryCache = { ...cache };
272
-
273
- // Helper function to save cache with lock
274
- // Optimized: Use in-memory cache to reduce file I/O
275
- const saveCacheWithLock = async (newEntry) => {
276
- // Add to write queue to ensure sequential writes
277
- writeQueue = writeQueue
278
- .then(async () => {
279
- try {
280
- // Merge new entry into in-memory cache
281
- Object.assign(inMemoryCache, newEntry);
282
-
283
- // Save to disk
284
- const cacheYaml = stringify({
285
- descriptions: inMemoryCache,
286
- lastUpdated: new Date().toISOString(),
287
- });
288
- await writeFile(cacheFilePath, cacheYaml, "utf8");
289
- // Only update in-memory cache after successful write
290
- return true;
291
- } catch (error) {
292
- // Rollback: remove the entry from in-memory cache if write failed
293
- for (const key of Object.keys(newEntry)) {
294
- delete inMemoryCache[key];
295
- }
296
- console.error(`Failed to save cache: ${error.message}`);
297
- throw error;
298
- }
299
- })
300
- .catch(() => {
301
- // Don't let one write failure break the queue
302
- // Error is already logged above
303
- return false;
304
- });
305
- await writeQueue;
306
- };
307
-
308
- // Process media files concurrently with incremental save
309
- // Use pMap for concurrent processing with controlled concurrency
310
- const CONCURRENCY = 5; // Process 5 files concurrently
311
-
312
- await pMap(
313
- mediaToDescribe,
314
- async (mediaItem, index) => {
315
- const result = { success: false, path: mediaItem.path, error: null };
316
-
317
- try {
318
- // Generate description for single media file
319
- // Note: If compression was applied, mediaItem.mediaFile[0].path points to compressed file
320
- // This compressed file is used for upload, but cache uses original file hash and path
321
- const agentResult = await options.context.invoke(
322
- options.context.agents["generateMediaDescription"],
323
- mediaItem,
324
- );
325
-
326
- // Check if description was generated successfully
327
- // Note: agentResult.hash and agentResult.path come from the agent, but we need to ensure
328
- // we use the original file path and hash for caching, not the compressed file path
329
- if (agentResult?.hash && agentResult?.description) {
330
- // Use original file path and hash for cache entry
331
- // The compressed file is only used for upload, but cache should reference original file
332
- const originalPath = mediaItem.path;
333
- const originalHash = mediaItem.hash;
334
-
335
- const descriptionEntry = {
336
- path: originalPath, // Use original file path, not compressed file path
337
- description: agentResult.description,
338
- generatedAt: new Date().toISOString(),
339
- };
340
-
341
- // Immediately save to cache using lock mechanism
342
- await saveCacheWithLock({ [originalHash]: descriptionEntry });
343
-
344
- // Track in memory for summary
345
- newDescriptions[originalHash] = descriptionEntry;
346
- result.success = true;
347
-
348
- debug(
349
- `✅ Generated and saved description for ${mediaItem.path} (${index + 1}/${mediaToDescribe.length})`,
350
- );
351
- } else {
352
- result.error = "No description in result";
353
- console.warn(
354
- `Failed to generate description for ${mediaItem.path}: No description in result`,
355
- );
356
- }
357
- } catch (error) {
358
- result.error = error.message;
359
- console.error(`Failed to generate description for ${mediaItem.path}:`, error.message);
360
- // Continue processing other files even if one fails
361
- }
362
-
363
- results.push(result);
364
- return result;
365
- },
366
- { concurrency: CONCURRENCY },
367
- );
368
-
369
- // Calculate accurate counts from results
370
- const successCount = results.filter((r) => r.success).length;
371
- const errorCount = results.filter((r) => !r.success).length;
372
-
373
- // Update cache reference to in-memory cache
374
- Object.assign(cache, inMemoryCache);
375
-
376
- // Log summary
377
- if (successCount > 0) {
378
- console.log(
379
- `Generated descriptions for ${successCount} media files (${errorCount} errors, ${mediaToDescribe.length - successCount - errorCount} skipped)`,
380
- );
381
- }
382
- if (errorCount > 0) {
383
- console.warn(
384
- `⚠️ Failed to generate descriptions for ${errorCount} media files. Completed descriptions have been saved.`,
385
- );
386
- }
387
- }
388
-
389
- // Build enhanced assetsContent with descriptions
390
- let enhancedAssetsContent;
391
-
392
- if (mediaFiles.length > 0) {
393
- enhancedAssetsContent = "# Available Media Assets for Documentation\n\n";
394
- const assets = mediaFiles.map((x) => {
395
- const mediaHash = mediaHashMap.get(x.path);
396
- const description = cache[mediaHash]?.description;
397
- const result = {
398
- name: x.name,
399
- path: x.path,
400
- };
401
- if (description) {
402
- result.description = description;
403
- }
404
- return result;
405
- });
406
- enhancedAssetsContent += stringify(assets);
407
- }
408
-
409
- return {
410
- ...input,
411
- assetsContent: enhancedAssetsContent,
412
- mediaFiles,
413
- };
414
- }
415
-
416
- loadMediaDescription.input_schema = {
417
- type: "object",
418
- properties: {
419
- mediaFiles: {
420
- type: "array",
421
- items: {
422
- type: "object",
423
- properties: {
424
- name: { type: "string" },
425
- path: { type: "string" },
426
- type: { type: "string" },
427
- width: { type: "number" },
428
- height: { type: "number" },
429
- mimeType: { type: "string" },
430
- },
431
- },
432
- description: "Array of media file objects (images/videos)",
433
- },
434
- docsDir: {
435
- type: "string",
436
- description: "Base directory for documentation",
437
- },
438
- },
439
- required: ["mediaFiles", "docsDir"],
440
- };
441
-
442
- loadMediaDescription.output_schema = {
443
- type: "object",
444
- properties: {
445
- assetsContent: {
446
- type: "string",
447
- description: "Enhanced assets content with media descriptions",
448
- },
449
- mediaFiles: {
450
- type: "array",
451
- description: "Array of media file objects",
452
- },
453
- },
454
- };
@@ -1,203 +0,0 @@
1
- import { readPreferences, removeRule, writePreferences } from "../../utils/preferences-utils.mjs";
2
-
3
- /**
4
- * List all user preferences with formatted display
5
- * @returns {Object} Result with formatted message
6
- */
7
- function listPreferences() {
8
- const preferences = readPreferences();
9
-
10
- if (preferences.rules.length === 0) {
11
- return { message: "No saved preferences found." };
12
- }
13
-
14
- let message = "# User Preferences\n\n";
15
-
16
- // Add format explanation
17
- message += "**Format explanation:**\n";
18
- message += "- 🟢 = Active preference, ⚪ = Inactive preference\n";
19
- message += "- [scope] = Preference scope (global, structure, document, translation)\n";
20
- message += "- ID = Unique preference identifier\n";
21
- message += "- Paths = Specific file paths (if applicable)\n\n";
22
-
23
- preferences.rules.forEach((rule) => {
24
- const status = rule.active ? "🟢" : "⚪";
25
- const pathsInfo = rule.paths ? ` | Paths: ${rule.paths.join(", ")}` : "";
26
-
27
- // First line: status, scope, ID and paths info
28
- message += `${status} [${rule.scope}] ${rule.id}${pathsInfo}\n`;
29
-
30
- // Second line: rule content (truncated if too long)
31
- const maxRuleLength = 120;
32
- const ruleText =
33
- rule.rule.length > maxRuleLength ? `${rule.rule.substring(0, maxRuleLength)}...` : rule.rule;
34
- message += ` ${ruleText}\n `;
35
-
36
- // Add blank line after each record
37
- message += `\n`;
38
- });
39
-
40
- return { message };
41
- }
42
-
43
- /**
44
- * Remove preferences by IDs or interactive selection
45
- * @param {string[]} id - Array of preference IDs to remove
46
- * @param {Object} options - Options with prompts interface
47
- * @returns {Object} Result with success message
48
- */
49
- async function removePreferences(id, options) {
50
- const preferences = readPreferences();
51
- let targetIds = id;
52
-
53
- if (!targetIds || targetIds.length === 0) {
54
- // Interactive selection
55
- if (preferences.rules.length === 0) {
56
- return { message: "No preferences available to remove." };
57
- }
58
-
59
- const choices = preferences.rules.map((rule) => ({
60
- name: `${rule.active ? "🟢" : "⚪"} [${rule.scope}] ${rule.rule.substring(0, 60)}${rule.rule.length > 60 ? "..." : ""}`,
61
- value: rule.id,
62
- description: `ID: ${rule.id}`,
63
- }));
64
-
65
- targetIds = await options.prompts.checkbox({
66
- message: "Choose preferences to delete:",
67
- choices,
68
- validate: (answer) => {
69
- if (answer.length === 0) {
70
- return "Please choose at least one preference to delete";
71
- }
72
- return true;
73
- },
74
- });
75
-
76
- if (!targetIds || targetIds.length === 0) {
77
- return { message: "No preferences selected for deletion." };
78
- }
79
- }
80
-
81
- // Process the target IDs
82
- const results = [];
83
- for (const ruleId of targetIds) {
84
- const success = removeRule(ruleId);
85
- results.push({ id: ruleId, success });
86
- }
87
-
88
- const successCount = results.filter((r) => r.success).length;
89
- const failedCount = targetIds.length - successCount;
90
- const message =
91
- failedCount > 0
92
- ? `Successfully removed ${successCount} preferences, ${failedCount} failed.`
93
- : `Successfully removed ${successCount} preferences.`;
94
-
95
- return { message };
96
- }
97
-
98
- /**
99
- * Toggle preferences active status by IDs or interactive selection
100
- * @param {string[]} id - Array of preference IDs to toggle
101
- * @param {Object} options - Options with prompts interface
102
- * @returns {Object} Result with success message
103
- */
104
- async function togglePreferences(id, options) {
105
- const preferences = readPreferences();
106
- let targetIds = id;
107
-
108
- if (!targetIds || targetIds.length === 0) {
109
- // Interactive selection
110
- if (preferences.rules.length === 0) {
111
- return { message: "No preferences available to toggle." };
112
- }
113
-
114
- const choices = preferences.rules.map((rule) => ({
115
- name: `${rule.active ? "🟢" : "⚪"} [${rule.scope}] ${rule.rule.substring(0, 60)}${rule.rule.length > 60 ? "..." : ""}`,
116
- value: rule.id,
117
- description: `ID: ${rule.id}`,
118
- }));
119
-
120
- targetIds = await options.prompts.checkbox({
121
- message: "Choose preferences to enable/disable:",
122
- choices,
123
- validate: (answer) => {
124
- if (answer.length === 0) {
125
- return "Please choose at least one preference to toggle";
126
- }
127
- return true;
128
- },
129
- });
130
-
131
- if (!targetIds || targetIds.length === 0) {
132
- return { message: "No preferences selected to toggle." };
133
- }
134
- }
135
-
136
- // Process the target IDs
137
- const results = [];
138
- const prefs = readPreferences();
139
-
140
- for (const ruleId of targetIds) {
141
- const rule = prefs.rules.find((r) => r.id === ruleId);
142
- if (rule) {
143
- rule.active = !rule.active;
144
- results.push({ id: ruleId, success: true, newStatus: rule.active });
145
- } else {
146
- results.push({ id: ruleId, success: false, error: "Rule not found" });
147
- }
148
- }
149
-
150
- writePreferences(prefs);
151
-
152
- const successCount = results.filter((r) => r.success).length;
153
- const failedCount = targetIds.length - successCount;
154
- const message =
155
- failedCount > 0
156
- ? `Successfully toggled ${successCount} preferences, ${failedCount} failed.`
157
- : `Successfully toggled ${successCount} preferences.`;
158
-
159
- return { message };
160
- }
161
-
162
- export default async function prefs({ list, remove, toggle, id }, options) {
163
- if (list) {
164
- return listPreferences();
165
- }
166
-
167
- if (remove) {
168
- return await removePreferences(id, options);
169
- }
170
-
171
- if (toggle) {
172
- return await togglePreferences(id, options);
173
- }
174
-
175
- return { message: "Please choose an action: --list, --remove, or --toggle." };
176
- }
177
-
178
- prefs.input_schema = {
179
- type: "object",
180
- properties: {
181
- list: {
182
- type: "boolean",
183
- description: "Show all saved preferences",
184
- },
185
- remove: {
186
- type: "boolean",
187
- description: "Delete saved preferences",
188
- },
189
- toggle: {
190
- type: "boolean",
191
- description: "Enable/disable preferences",
192
- },
193
- id: {
194
- type: "array",
195
- items: {
196
- type: "string",
197
- },
198
- description: "Specific preference IDs to work with",
199
- },
200
- },
201
- };
202
-
203
- prefs.description = "Manage your saved documentation preferences";
@@ -1,26 +0,0 @@
1
- type: object
2
- description: Document structure item representing a node in the document hierarchy
3
- properties:
4
- title:
5
- type: string
6
- description:
7
- type: string
8
- path:
9
- type: string
10
- description: Path in URL format, cannot be empty, cannot contain spaces or special characters, must start with /, no need to include language level, e.g., /zh/about should return /about
11
- parentPath:
12
- type: string
13
- description: Parent node path, if null indicates it is a top-level node
14
- sourceIds:
15
- type: array
16
- description: Associated sourceId from `<data_sources>` for subsequent translation and content generation, must come from sourceId in `<data_sources>`, cannot have fake ids, **cannot be empty**
17
- items:
18
- type: string
19
- icon:
20
- type: string
21
- description: Lucide icon name for root-level documents (just support lucide:icon-name, not support other icon collections)
22
- required:
23
- - title
24
- - description
25
- - path
26
- - sourceIds