@aigne/doc-smith 0.8.12-beta.8 → 0.8.12-beta.9

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 (264) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/agents/publish/index.yaml +4 -0
  3. package/agents/publish/publish-docs.mjs +77 -5
  4. package/agents/publish/translate-meta.mjs +103 -0
  5. package/agents/update/generate-document.yaml +30 -28
  6. package/agents/update/update-document-detail.yaml +3 -1
  7. package/agents/utils/update-branding.mjs +69 -0
  8. package/package.json +16 -2
  9. package/prompts/common/document/role-and-personality.md +3 -1
  10. package/prompts/detail/d2-diagram/guide.md +7 -1
  11. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  12. package/prompts/detail/generate/system-prompt.md +6 -7
  13. package/prompts/detail/generate/user-prompt.md +12 -3
  14. package/prompts/detail/update/user-prompt.md +0 -2
  15. package/prompts/structure/update/user-prompt.md +0 -4
  16. package/utils/file-utils.mjs +69 -24
  17. package/utils/markdown-checker.mjs +0 -20
  18. package/utils/request.mjs +7 -0
  19. package/utils/upload-files.mjs +231 -0
  20. package/utils/utils.mjs +11 -1
  21. package/.aigne/doc-smith/config.yaml +0 -77
  22. package/.aigne/doc-smith/history.yaml +0 -37
  23. package/.aigne/doc-smith/media-description.yaml +0 -91
  24. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  25. package/.aigne/doc-smith/preferences.yml +0 -97
  26. package/.aigne/doc-smith/upload-cache.yaml +0 -1830
  27. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  28. package/.github/workflows/ci.yml +0 -54
  29. package/.github/workflows/create-release-pr.yaml +0 -21
  30. package/.github/workflows/publish-docs.yml +0 -65
  31. package/.github/workflows/release.yml +0 -49
  32. package/.github/workflows/reviewer.yml +0 -54
  33. package/.release-please-manifest.json +0 -3
  34. package/RELEASE.md +0 -9
  35. package/assets/screenshots/doc-complete-setup.png +0 -0
  36. package/assets/screenshots/doc-generate-docs.png +0 -0
  37. package/assets/screenshots/doc-generate.png +0 -0
  38. package/assets/screenshots/doc-generated-successfully.png +0 -0
  39. package/assets/screenshots/doc-publish.png +0 -0
  40. package/assets/screenshots/doc-regenerate.png +0 -0
  41. package/assets/screenshots/doc-translate-langs.png +0 -0
  42. package/assets/screenshots/doc-translate.png +0 -0
  43. package/assets/screenshots/doc-update.png +0 -0
  44. package/biome.json +0 -73
  45. package/codecov.yml +0 -15
  46. package/docs/_sidebar.md +0 -15
  47. package/docs/configuration-initial-setup.ja.md +0 -179
  48. package/docs/configuration-initial-setup.md +0 -198
  49. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  50. package/docs/configuration-initial-setup.zh.md +0 -179
  51. package/docs/configuration-managing-preferences.ja.md +0 -100
  52. package/docs/configuration-managing-preferences.md +0 -100
  53. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  54. package/docs/configuration-managing-preferences.zh.md +0 -100
  55. package/docs/configuration.ja.md +0 -69
  56. package/docs/configuration.md +0 -69
  57. package/docs/configuration.zh-TW.md +0 -69
  58. package/docs/configuration.zh.md +0 -69
  59. package/docs/getting-started.ja.md +0 -107
  60. package/docs/getting-started.md +0 -107
  61. package/docs/getting-started.zh-TW.md +0 -107
  62. package/docs/getting-started.zh.md +0 -107
  63. package/docs/guides-cleaning-up.ja.md +0 -51
  64. package/docs/guides-cleaning-up.md +0 -52
  65. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  66. package/docs/guides-cleaning-up.zh.md +0 -51
  67. package/docs/guides-evaluating-documents.ja.md +0 -66
  68. package/docs/guides-evaluating-documents.md +0 -107
  69. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  70. package/docs/guides-evaluating-documents.zh.md +0 -66
  71. package/docs/guides-generating-documentation.ja.md +0 -151
  72. package/docs/guides-generating-documentation.md +0 -89
  73. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  74. package/docs/guides-generating-documentation.zh.md +0 -151
  75. package/docs/guides-interactive-chat.ja.md +0 -85
  76. package/docs/guides-interactive-chat.md +0 -93
  77. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  78. package/docs/guides-interactive-chat.zh.md +0 -85
  79. package/docs/guides-managing-history.ja.md +0 -48
  80. package/docs/guides-managing-history.md +0 -53
  81. package/docs/guides-managing-history.zh-TW.md +0 -48
  82. package/docs/guides-managing-history.zh.md +0 -48
  83. package/docs/guides-publishing-your-docs.ja.md +0 -78
  84. package/docs/guides-publishing-your-docs.md +0 -83
  85. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  86. package/docs/guides-publishing-your-docs.zh.md +0 -78
  87. package/docs/guides-translating-documentation.ja.md +0 -95
  88. package/docs/guides-translating-documentation.md +0 -100
  89. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  90. package/docs/guides-translating-documentation.zh.md +0 -95
  91. package/docs/guides-updating-documentation.ja.md +0 -77
  92. package/docs/guides-updating-documentation.md +0 -79
  93. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  94. package/docs/guides-updating-documentation.zh.md +0 -77
  95. package/docs/guides.ja.md +0 -32
  96. package/docs/guides.md +0 -32
  97. package/docs/guides.zh-TW.md +0 -32
  98. package/docs/guides.zh.md +0 -32
  99. package/docs/overview.ja.md +0 -61
  100. package/docs/overview.md +0 -61
  101. package/docs/overview.zh-TW.md +0 -61
  102. package/docs/overview.zh.md +0 -61
  103. package/docs/release-notes.ja.md +0 -255
  104. package/docs/release-notes.md +0 -288
  105. package/docs/release-notes.zh-TW.md +0 -255
  106. package/docs/release-notes.zh.md +0 -255
  107. package/prompts/common/afs/afs-tools-usage.md +0 -5
  108. package/prompts/common/afs/use-afs-instruction.md +0 -1
  109. package/release-please-config.json +0 -14
  110. package/tests/agents/chat/chat.test.mjs +0 -46
  111. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  112. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  113. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  114. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  115. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  116. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  117. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  118. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  119. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  120. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  121. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  122. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  123. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  124. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  125. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  126. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  127. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  128. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  129. package/tests/agents/history/view.test.mjs +0 -97
  130. package/tests/agents/init/init.test.mjs +0 -1657
  131. package/tests/agents/prefs/prefs.test.mjs +0 -431
  132. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  133. package/tests/agents/translate/choose-language.test.mjs +0 -311
  134. package/tests/agents/translate/translate-document.test.mjs +0 -51
  135. package/tests/agents/update/check-document.test.mjs +0 -463
  136. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  137. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  138. package/tests/agents/update/generate-document.test.mjs +0 -51
  139. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  140. package/tests/agents/update/user-review-document.test.mjs +0 -582
  141. package/tests/agents/utils/action-success.test.mjs +0 -54
  142. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  143. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  144. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  145. package/tests/agents/utils/exit.test.mjs +0 -70
  146. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  147. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  148. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  149. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  150. package/tests/agents/utils/fs.test.mjs +0 -267
  151. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  152. package/tests/agents/utils/save-docs.test.mjs +0 -109
  153. package/tests/agents/utils/save-output.test.mjs +0 -315
  154. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  155. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  156. package/tests/utils/auth-utils.test.mjs +0 -596
  157. package/tests/utils/blocklet.test.mjs +0 -336
  158. package/tests/utils/conflict-detector.test.mjs +0 -355
  159. package/tests/utils/constants.test.mjs +0 -295
  160. package/tests/utils/d2-utils.test.mjs +0 -437
  161. package/tests/utils/deploy.test.mjs +0 -399
  162. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  163. package/tests/utils/file-utils.test.mjs +0 -521
  164. package/tests/utils/history-utils.test.mjs +0 -206
  165. package/tests/utils/kroki-utils.test.mjs +0 -646
  166. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  167. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  168. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  169. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  170. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  171. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  172. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  173. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  174. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  175. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  176. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  177. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  178. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  179. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  180. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  181. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  182. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  183. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  184. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  185. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  186. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  187. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  188. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  189. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  190. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  191. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  192. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  193. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  194. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  195. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  196. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  197. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  198. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  199. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  200. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  201. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  202. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  203. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  204. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  205. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  206. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  207. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  208. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  209. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  210. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  211. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  212. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  213. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  214. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  215. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  216. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  217. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  218. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  219. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  220. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  221. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  222. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  223. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  224. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  225. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  226. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  227. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  228. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  229. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  230. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  231. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  232. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  233. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  234. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  235. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  236. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  237. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  238. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  239. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  240. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  241. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  242. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  243. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  244. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  245. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  246. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  247. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  248. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  249. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  250. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  251. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  252. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  253. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  254. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  255. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  256. package/tests/utils/linter/index.test.mjs +0 -440
  257. package/tests/utils/linter/scan-results.mjs +0 -42
  258. package/tests/utils/load-config.test.mjs +0 -141
  259. package/tests/utils/markdown/index.test.mjs +0 -478
  260. package/tests/utils/mermaid-validator.test.mjs +0 -541
  261. package/tests/utils/mock-chat-model.mjs +0 -12
  262. package/tests/utils/preferences-utils.test.mjs +0 -465
  263. package/tests/utils/save-value-to-config.test.mjs +0 -483
  264. package/tests/utils/utils.test.mjs +0 -941
@@ -559,36 +559,81 @@ export function getStructurePlanPath(workDir) {
559
559
  return path.join(cwd, ".aigne", "doc-smith", "output", "structure-plan.json");
560
560
  }
561
561
 
562
+ // Shared extension → MIME type mapping table
563
+ const EXT_TO_MIME = {
564
+ ".jpg": "image/jpeg",
565
+ ".jpeg": "image/jpeg",
566
+ ".png": "image/png",
567
+ ".gif": "image/gif",
568
+ ".bmp": "image/bmp",
569
+ ".webp": "image/webp",
570
+ ".svg": "image/svg+xml",
571
+ ".heic": "image/heic",
572
+ ".heif": "image/heif",
573
+ ".mp4": "video/mp4",
574
+ ".mpeg": "video/mpeg",
575
+ ".mpg": "video/mpg",
576
+ ".mov": "video/mov",
577
+ ".avi": "video/avi",
578
+ ".flv": "video/x-flv",
579
+ ".mkv": "video/x-matroska",
580
+ ".webm": "video/webm",
581
+ ".wmv": "video/wmv",
582
+ ".m4v": "video/x-m4v",
583
+ ".3gpp": "video/3gpp",
584
+ ".mp3": "audio/mpeg",
585
+ ".wav": "audio/wav",
586
+ ".pdf": "application/pdf",
587
+ ".doc": "application/msword",
588
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
589
+ ".xls": "application/vnd.ms-excel",
590
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
591
+ ".ppt": "application/vnd.ms-powerpoint",
592
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
593
+ ".txt": "text/plain",
594
+ ".json": "application/json",
595
+ ".xml": "application/xml",
596
+ ".html": "text/html",
597
+ ".css": "text/css",
598
+ ".js": "application/javascript",
599
+ ".zip": "application/zip",
600
+ ".rar": "application/x-rar-compressed",
601
+ ".7z": "application/x-7z-compressed",
602
+ };
603
+
604
+ // Build reverse mapping: MIME → extensions
605
+ const MIME_TO_EXTS = Object.entries(EXT_TO_MIME).reduce((acc, [ext, mime]) => {
606
+ const key = mime.toLowerCase();
607
+ if (!acc[key]) {
608
+ acc[key] = [];
609
+ }
610
+ acc[key].push(ext);
611
+ return acc;
612
+ }, {});
613
+
562
614
  /**
563
615
  * Get MIME type from file path based on extension
564
616
  * @param {string} filePath - File path
565
617
  * @returns {string} MIME type
566
618
  */
567
619
  export function getMimeType(filePath) {
568
- const ext = path.extname(filePath).toLowerCase();
569
- const mimeTypes = {
570
- ".jpg": "image/jpeg",
571
- ".jpeg": "image/jpeg",
572
- ".png": "image/png",
573
- ".gif": "image/gif",
574
- ".bmp": "image/bmp",
575
- ".webp": "image/webp",
576
- ".svg": "image/svg+xml",
577
- ".heic": "image/heic",
578
- ".heif": "image/heif",
579
- ".mp4": "video/mp4",
580
- ".mpeg": "video/mpeg",
581
- ".mpg": "video/mpg",
582
- ".mov": "video/mov",
583
- ".avi": "video/avi",
584
- ".flv": "video/x-flv",
585
- ".mkv": "video/x-matroska",
586
- ".webm": "video/webm",
587
- ".wmv": "video/wmv",
588
- ".m4v": "video/x-m4v",
589
- ".3gpp": "video/3gpp",
590
- };
591
- return mimeTypes[ext] || "application/octet-stream";
620
+ const ext = path.extname(filePath || "").toLowerCase();
621
+ return EXT_TO_MIME[ext] || "application/octet-stream";
622
+ }
623
+
624
+ /**
625
+ * Get file extension (without dot) from content type
626
+ * Handles content types with parameters (e.g., "image/jpeg; charset=utf-8")
627
+ * @param {string} contentType - Content type string
628
+ * @returns {string} File extension without dot
629
+ */
630
+ export function getExtnameFromContentType(contentType) {
631
+ if (!contentType) return "";
632
+ const base = String(contentType).split(";")[0].trim().toLowerCase();
633
+ const exts = MIME_TO_EXTS[base];
634
+ if (exts?.length) return exts[0].slice(1); // Remove leading dot
635
+ const parts = base.split("/");
636
+ return parts[1] || "";
592
637
  }
593
638
 
594
639
  /**
@@ -1,14 +1,11 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import pMap from "p-map";
4
3
  import remarkGfm from "remark-gfm";
5
4
  import remarkLint from "remark-lint";
6
5
  import remarkParse from "remark-parse";
7
6
  import { unified } from "unified";
8
7
  import { visit } from "unist-util-visit";
9
8
  import { VFile } from "vfile";
10
- import { KROKI_CONCURRENCY } from "./constants/index.mjs";
11
- import { checkContent, isValidCode } from "./d2-utils.mjs";
12
9
  import { validateMermaidSyntax } from "./mermaid-validator.mjs";
13
10
 
14
11
  /**
@@ -378,7 +375,6 @@ export async function checkMarkdown(markdown, source = "content", options = {})
378
375
 
379
376
  // Check mermaid code blocks and other custom validations
380
377
  const mermaidChecks = [];
381
- const d2ChecksList = [];
382
378
  visit(ast, "code", (node) => {
383
379
  if (node.lang) {
384
380
  const line = node.position?.start?.line || "unknown";
@@ -467,12 +463,6 @@ export async function checkMarkdown(markdown, source = "content", options = {})
467
463
  specialCharMatch = nodeWithSpecialCharsRegex.exec(mermaidContent);
468
464
  }
469
465
  }
470
- if (isValidCode(node.lang)) {
471
- d2ChecksList.push({
472
- content: node.value,
473
- line,
474
- });
475
- }
476
466
  }
477
467
  });
478
468
 
@@ -524,16 +514,6 @@ export async function checkMarkdown(markdown, source = "content", options = {})
524
514
  // Wait for all mermaid checks to complete
525
515
  await Promise.all(mermaidChecks);
526
516
 
527
- await pMap(
528
- d2ChecksList,
529
- async ({ content, line }) =>
530
- checkContent({ content }).catch((err) => {
531
- const errorMessage = err?.message || String(err) || "Unknown d2 syntax error";
532
- errorMessages.push(`Found D2 syntax error in ${source} at line ${line}: ${errorMessage}`);
533
- }),
534
- { concurrency: KROKI_CONCURRENCY },
535
- );
536
-
537
517
  // Run markdown linting rules
538
518
  await processor.run(ast, file);
539
519
 
@@ -0,0 +1,7 @@
1
+ export async function requestWithAuthToken(url, options, authToken) {
2
+ const response = await fetch(url, {
3
+ ...options,
4
+ headers: { ...options.headers, Authorization: `Bearer ${authToken}` },
5
+ });
6
+ return response.json();
7
+ }
@@ -0,0 +1,231 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+
5
+ import pLimit from "p-limit";
6
+ import pRetry from "p-retry";
7
+
8
+ import { getComponentMountPoint } from "./blocklet.mjs";
9
+ import { DISCUSS_KIT_DID } from "./constants/index.mjs";
10
+ import { getMimeType } from "./file-utils.mjs";
11
+
12
+ /**
13
+ * Perform single file upload
14
+ */
15
+ async function performSingleUpload(filePath, fileHash, uploadEndpoint, accessToken, url) {
16
+ const baseFilename = path.basename(filePath, path.extname(filePath));
17
+ const fileBuffer = fs.readFileSync(filePath);
18
+ const stats = fs.statSync(filePath);
19
+ const fileSize = stats.size;
20
+ const fileExt = path.extname(filePath).substring(1);
21
+ const mimeType = getMimeType(filePath);
22
+
23
+ const hashBasedFilename = `${fileHash.substring(0, 16)}.${fileExt}`;
24
+
25
+ const uploaderId = "Uploader";
26
+ const fileId = `${uploaderId}-${baseFilename.toLowerCase().replace(/[^a-z0-9]/g, "")}-${fileHash.substring(0, 16)}`;
27
+
28
+ const tusMetadata = {
29
+ uploaderId,
30
+ relativePath: hashBasedFilename,
31
+ name: hashBasedFilename,
32
+ type: mimeType,
33
+ filetype: mimeType,
34
+ filename: hashBasedFilename,
35
+ };
36
+
37
+ const encodedMetadata = Object.entries(tusMetadata)
38
+ .map(([key, value]) => `${key} ${Buffer.from(value).toString("base64")}`)
39
+ .join(",");
40
+
41
+ const uploadEndpointUrl = new URL(uploadEndpoint);
42
+ const endpointPath = uploadEndpointUrl.pathname;
43
+
44
+ // Create upload
45
+ const createResponse = await fetch(uploadEndpoint, {
46
+ method: "POST",
47
+ headers: {
48
+ "Tus-Resumable": "1.0.0",
49
+ "Upload-Length": fileSize.toString(),
50
+ "Upload-Metadata": encodedMetadata,
51
+ Cookie: `login_token=${accessToken}`,
52
+ "x-uploader-file-name": hashBasedFilename,
53
+ "x-uploader-file-id": fileId,
54
+ "x-uploader-file-ext": fileExt,
55
+ "x-uploader-base-url": endpointPath,
56
+ "x-uploader-endpoint-url": uploadEndpoint,
57
+ "x-uploader-metadata": JSON.stringify({
58
+ uploaderId,
59
+ relativePath: hashBasedFilename,
60
+ name: hashBasedFilename,
61
+ type: mimeType,
62
+ }),
63
+ "x-component-did": DISCUSS_KIT_DID,
64
+ },
65
+ });
66
+
67
+ if (!createResponse.ok) {
68
+ const errorText = await createResponse.text();
69
+ throw new Error(
70
+ `Failed to create upload: ${createResponse.status} ${createResponse.statusText}\n${errorText}`,
71
+ );
72
+ }
73
+
74
+ const uploadUrl = createResponse.headers.get("Location");
75
+ if (!uploadUrl) {
76
+ throw new Error("No upload URL received from server");
77
+ }
78
+
79
+ // Upload file content
80
+ const uploadResponse = await fetch(`${url.origin}${uploadUrl}`, {
81
+ method: "PATCH",
82
+ headers: {
83
+ "Tus-Resumable": "1.0.0",
84
+ "Upload-Offset": "0",
85
+ "Content-Type": "application/offset+octet-stream",
86
+ Cookie: `login_token=${accessToken}`,
87
+ "x-uploader-file-name": hashBasedFilename,
88
+ "x-uploader-file-id": fileId,
89
+ "x-uploader-file-ext": fileExt,
90
+ "x-uploader-base-url": endpointPath,
91
+ "x-uploader-endpoint-url": uploadEndpoint,
92
+ "x-uploader-metadata": JSON.stringify({
93
+ uploaderId,
94
+ relativePath: hashBasedFilename,
95
+ name: hashBasedFilename,
96
+ type: mimeType,
97
+ }),
98
+ "x-component-did": DISCUSS_KIT_DID,
99
+ "x-uploader-file-exist": "true",
100
+ },
101
+ body: fileBuffer,
102
+ });
103
+
104
+ if (!uploadResponse.ok) {
105
+ const errorText = await uploadResponse.text();
106
+ throw new Error(
107
+ `Failed to upload file: ${uploadResponse.status} ${uploadResponse.statusText}\n${errorText}`,
108
+ );
109
+ }
110
+
111
+ const uploadResult = await uploadResponse.json();
112
+
113
+ let uploadedFileUrl = uploadResult.url;
114
+ if (!uploadedFileUrl && uploadResult?.size) {
115
+ uploadedFileUrl = uploadResponse.url;
116
+ }
117
+
118
+ if (!uploadedFileUrl) {
119
+ throw new Error("No URL found in the upload response");
120
+ }
121
+
122
+ return {
123
+ filePath,
124
+ url: uploadedFileUrl,
125
+ };
126
+ }
127
+
128
+ /**
129
+ * Upload multiple files with concurrency control
130
+ * @param {Object} options - Upload options
131
+ * @param {string} options.appUrl - Application URL
132
+ * @param {string[]} options.filePaths - Array of file paths to upload
133
+ * @param {string} options.accessToken - Access token for authentication
134
+ * @param {number} [options.concurrency=3] - Number of concurrent uploads
135
+ * @param {string} [options.endpoint] - Custom upload endpoint
136
+ * @returns {Promise<{results: Array<{filePath: string, url: string}>}>}
137
+ */
138
+ export async function uploadFiles(options) {
139
+ const { appUrl, filePaths, endpoint, concurrency = 3, accessToken } = options;
140
+
141
+ if (filePaths.length === 0) {
142
+ return { results: [] };
143
+ }
144
+
145
+ const url = new URL(appUrl);
146
+ const mountPoint = await getComponentMountPoint(appUrl, DISCUSS_KIT_DID);
147
+
148
+ // Use custom endpoint or default to discuss kit media endpoint
149
+ const uploadEndpoint = endpoint || `${url.origin}${mountPoint}/api/uploads`;
150
+
151
+ const limit = pLimit(concurrency);
152
+ const ongoingUploads = new Map();
153
+
154
+ const uploadPromises = filePaths.map((filePath) =>
155
+ limit(async () => {
156
+ const filename = path.basename(filePath);
157
+
158
+ try {
159
+ const fileBuffer = fs.readFileSync(filePath);
160
+ const fileHash = crypto.createHash("sha256").update(fileBuffer).digest("hex");
161
+
162
+ // Check if this file is already being uploaded
163
+ const existingUpload = ongoingUploads.get(fileHash);
164
+ if (existingUpload) {
165
+ const result = await existingUpload;
166
+ return {
167
+ filePath,
168
+ url: result.url,
169
+ };
170
+ }
171
+
172
+ // Create upload promise and cache it
173
+ const uploadPromise = (async () => {
174
+ try {
175
+ const result = await pRetry(
176
+ () => performSingleUpload(filePath, fileHash, uploadEndpoint, accessToken, url),
177
+ {
178
+ retries: 3,
179
+ onFailedAttempt: (error) => {
180
+ console.warn(
181
+ `File upload attempt ${error.attemptNumber} failed for "${filename}". Remaining retries: ${error.retriesLeft}`,
182
+ );
183
+ if (error.retriesLeft === 0) {
184
+ console.error(
185
+ `File upload failed - all retry attempts exhausted for "${filename}"`,
186
+ );
187
+ }
188
+ },
189
+ },
190
+ );
191
+
192
+ return result;
193
+ } catch (error) {
194
+ console.error(
195
+ `File upload failed - error uploading "${filename}" after all retries:`,
196
+ error,
197
+ );
198
+ return {
199
+ filePath,
200
+ url: "",
201
+ };
202
+ }
203
+ })();
204
+
205
+ // Cache the upload promise
206
+ ongoingUploads.set(fileHash, uploadPromise);
207
+
208
+ try {
209
+ const result = await uploadPromise;
210
+ return {
211
+ filePath,
212
+ url: result.url,
213
+ };
214
+ } finally {
215
+ // Clean up the ongoing upload tracking
216
+ ongoingUploads.delete(fileHash);
217
+ }
218
+ } catch (error) {
219
+ console.error(`Error processing ${filename}:`, error);
220
+ return {
221
+ filePath,
222
+ url: "",
223
+ };
224
+ }
225
+ }),
226
+ );
227
+
228
+ const uploadResults = await Promise.all(uploadPromises);
229
+
230
+ return { results: uploadResults };
231
+ }
package/utils/utils.mjs CHANGED
@@ -47,6 +47,16 @@ export function isGlobPattern(pattern) {
47
47
  return /[*?[\]]|(\*\*)/.test(pattern);
48
48
  }
49
49
 
50
+ /**
51
+ * Check if a string is an HTTP/HTTPS URL
52
+ * @param {string} url - The string to check
53
+ * @returns {boolean} - True if the string starts with http:// or https://
54
+ */
55
+ export function isHttp(url) {
56
+ if (typeof url !== "string") return false;
57
+ return url.startsWith("http://") || url.startsWith("https://");
58
+ }
59
+
50
60
  export function processContent({ content }) {
51
61
  // Match markdown regular links [text](link), exclude images ![text](link)
52
62
  return content.replace(/(?<!!)\[([^\]]+)\]\(([^)]+)\)/g, (match, text, link) => {
@@ -1112,7 +1122,7 @@ export async function resolveFileReferences(obj, basePath = process.cwd()) {
1112
1122
  * @param {string} basePath - Base path for resolving relative paths
1113
1123
  * @returns {Promise<any>} - The loaded content or original path if loading fails
1114
1124
  */
1115
- async function loadFileContent(filePath, basePath) {
1125
+ export async function loadFileContent(filePath, basePath) {
1116
1126
  try {
1117
1127
  // Resolve path - if absolute, use as is; if relative, resolve from basePath
1118
1128
  const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(basePath, filePath);
@@ -1,77 +0,0 @@
1
- # Project information for documentation publishing
2
- projectName: AIGNE DocSmith
3
- projectDesc: AIGNE DocSmith is a powerful, AI-driven documentation generation tool built on the AIGNE Framework. It automates the creation of detailed, structured, and multi-language documentation directly from your source code.
4
- projectLogo: https://docsmith.aigne.io/image-bin/uploads/9645caf64b4232699982c4d940b03b90.svg
5
-
6
- # =============================================================================
7
- # Documentation Configuration
8
- # =============================================================================
9
-
10
- # Purpose: What's the main outcome you want readers to achieve?
11
- # Available options (uncomment and modify as needed):
12
- # getStarted - Get started quickly: Help new users go from zero to working in <30 minutes
13
- # completeTasks - Complete specific tasks: Guide users through common workflows and use cases
14
- # findAnswers - Find answers fast: Provide searchable reference for all features and APIs
15
- # understandSystem - Understand the system: Explain how it works, why design decisions were made
16
- # solveProblems - Solve problems: Help users troubleshoot and fix issues
17
- # mixedPurpose - Mix of above: Comprehensive documentation covering multiple needs
18
- documentPurpose:
19
- - getStarted
20
- - completeTasks
21
-
22
- # Target Audience: Who will be reading this most often?
23
- # Available options (uncomment and modify as needed):
24
- # endUsers - End users (non-technical): People who use the product but don't code
25
- # developers - Developers integrating: Engineers adding this to their projects
26
- # devops - DevOps/Infrastructure: Teams deploying, monitoring, maintaining systems
27
- # decisionMakers - Technical decision makers: Architects, leads evaluating or planning implementation
28
- # supportTeams - Support teams: People helping others use the product
29
- # mixedTechnical - Mixed technical audience: Developers, DevOps, and technical users
30
- targetAudienceTypes:
31
- - endUsers
32
-
33
- # Reader Knowledge Level: What do readers typically know when they arrive?
34
- # Available options (uncomment and modify as needed):
35
- # completeBeginners - Complete beginners: New to this domain/technology entirely
36
- # domainFamiliar - Domain-familiar, tool-new: Know the problem space, new to this specific solution
37
- # experiencedUsers - Experienced users: Regular users needing reference/advanced topics
38
- # emergencyTroubleshooting - Emergency/troubleshooting: Something's broken, need to fix it quickly
39
- # exploringEvaluating - Exploring/evaluating: Trying to understand if this fits their needs
40
- readerKnowledgeLevel: completeBeginners
41
-
42
- # Documentation Depth: How comprehensive should the documentation be?
43
- # Available options (uncomment and modify as needed):
44
- # essentialOnly - Essential only: Cover the 80% use cases, keep it concise
45
- # balancedCoverage - Balanced coverage: Good depth with practical examples [RECOMMENDED]
46
- # comprehensive - Comprehensive: Cover all features, edge cases, and advanced scenarios
47
- # aiDecide - Let AI decide: Analyze code complexity and suggest appropriate depth
48
- documentationDepth: comprehensive
49
-
50
- # Custom Rules: Define specific documentation generation rules and requirements
51
- rules: |
52
- Avoid using vague or empty words that don't provide measurable or specific details, such as 'intelligently', 'seamlessly', 'comprehensive', or 'high-quality'. Focus on concrete, verifiable facts and information.
53
- Focus on concrete, verifiable facts and information.
54
- Must cover all subcommands of DocSmith
55
-
56
- # Target Audience: Describe your specific target audience and their characteristics
57
- targetAudience: |
58
-
59
- locale: en
60
- translateLanguages:
61
- - zh
62
- - zh-TW
63
- - ja
64
- docsDir: ./docs # Directory to save generated documentation
65
- sourcesPath: # Source code paths to analyze
66
- - ./README.md
67
- - ./CHANGELOG.md
68
- - ./aigne.yaml
69
- - ./agents
70
- - ./.aigne/doc-smith/config.yaml
71
- - ./assets/screenshots
72
- lastGitHead: f0db74dffd0876dab4cc3ad628523abd359c9430
73
- # ⚠️ Warning: boardId is auto-generated by system, please do not edit manually
74
- boardId: "docsmith"
75
- appUrl: https://docsmith.aigne.io
76
- # Checkout ID for document deployment service
77
- checkoutId: ""
@@ -1,37 +0,0 @@
1
- entries:
2
- - timestamp: 2025-10-11T13:21:51.992Z
3
- operation: translation_update
4
- feedback: Do not translate the Target column in the Cleanup Targets table.
5
- documentPath: /guides/cleaning-up
6
- - timestamp: 2025-10-11T13:20:30.314Z
7
- operation: document_update
8
- feedback: The targets in Cleanup Targets are incomplete and need to be supplemented. The corresponding descriptions also require updating. Additionally, the target values should use the original enumeration values, such as 'generatedDocs'.
9
- documentPath: /guides/cleaning-up
10
- - timestamp: 2025-10-11T13:03:20.327Z
11
- operation: document_update
12
- feedback: The two aliases for the 'history' command in Viewing Update History can be combined into a single code block. The Short Hash in Understanding the History Output now consists of 8 characters. Additionally, operation types are separated by underscores, such as 'document_update'.
13
- documentPath: /guides/managing-history
14
- - timestamp: 2025-10-11T12:56:23.107Z
15
- operation: document_update
16
- feedback: In interactive mode, translated files are saved with a suffix appended to their original filenames within the same directory, rather than in dedicated language directories.
17
- documentPath: /guides/translating-documentation
18
- - timestamp: 2025-10-11T12:50:25.563Z
19
- operation: document_update
20
- feedback: The value of the 'docs' parameter in the demo should be a path separated by '-' rather than '/', and '.md' should be preserved.
21
- documentPath: /guides/updating-documentation
22
- - timestamp: 2025-10-11T12:46:37.507Z
23
- operation: document_update
24
- feedback: The value of the 'docs' parameter in the demo should be a path separated by '-' rather than '/'.
25
- documentPath: /guides/updating-documentation
26
- - timestamp: 2025-10-11T12:39:53.222Z
27
- operation: document_update
28
- feedback: The prompts in Review the Documentation Structure are outdated and need updating. Command Parameters also require updating.
29
- documentPath: /guides/generating-documentation
30
- - timestamp: 2025-10-11T12:26:24.598Z
31
- operation: translation_update
32
- feedback: AIGNE Framework is a proper noun and has its own link; no translation is required.
33
- documentPath: /overview
34
- - timestamp: 2025-10-11T12:24:05.477Z
35
- operation: document_update
36
- feedback: Add a link to the AIGNE Framework 'https://www.aigne.io/framework'.
37
- documentPath: /overview
@@ -1,91 +0,0 @@
1
- descriptions:
2
- 5838723847ec201191b002ef7d44937d92386a82755ca7a66374acff6b91325e:
3
- path: ../assets/screenshots/doc-translate.png
4
- description: This screenshot illustrates a user interface for document
5
- translation. It displays options for selecting the source and target
6
- languages, along with an area for document input or upload. The image
7
- demonstrates the initial steps for translating a document within a
8
- software application or web service.
9
- generatedAt: 2025-10-13T10:16:56.300Z
10
- ac51399fcd5ba2e36d7c84264dd28624acd10c57aa82f7d006da6f8434cb24de:
11
- path: ../assets/screenshots/doc-regenerate.png
12
- description: This screenshot displays a user interface element for a
13
- 'Regenerate' function, likely within an application or content management
14
- system. It visually demonstrates how users can trigger the re-rendering or
15
- updating of content, often showing a button or control and potentially the
16
- immediate output or status of the regeneration process.
17
- generatedAt: 2025-10-13T10:16:56.301Z
18
- 9871bff567cc5f1b73e99b84c03781bffc7f531635b9bd40f23a2aee5f9885e5:
19
- path: ../assets/screenshots/doc-update.png
20
- description: This image is a screenshot depicting a user interface for updating
21
- documentation content. It showcases a main text editing area, likely with
22
- rich text formatting capabilities, accompanied by buttons for actions such
23
- as saving, previewing, or publishing changes. The layout suggests a
24
- content management system or a wiki-style editing environment.
25
- generatedAt: 2025-10-13T10:16:56.301Z
26
- 31353781ba6d1572359823faa399af9f5deca7b994f24939cb5f5143fcc96b14:
27
- path: ../assets/screenshots/doc-translate-langs.png
28
- description: This screenshot depicts a user interface element focused on
29
- language selection for documentation translation. It displays a list or
30
- menu of languages, allowing users to choose or configure the target
31
- languages for translating documentation content. The image highlights the
32
- functionality for managing multilingual documentation.
33
- generatedAt: 2025-10-13T10:16:56.301Z
34
- a42903e87ae020dcb81991e672b2a2990b94eb0e92d6c1cc87f3bf6223355344:
35
- path: ../assets/screenshots/doc-publish.png
36
- description: This is a screenshot of a "Publish Documentation" dialog box from a
37
- user interface. It presents options for selecting documentation to publish
38
- and configuring various publication settings, including checkboxes for
39
- search indexing and versioning. The dialog features "Cancel" and "Publish"
40
- action buttons at the bottom right.
41
- generatedAt: 2025-10-13T10:16:56.301Z
42
- c055a80de6c1120765757fd3ef91ef05718f77beb7d6dfdac41d8e234361a68a:
43
- path: ../assets/screenshots/doc-generated-successfully.png
44
- description: This is a screenshot of a success notification banner,
45
- characterized by its wide and short dimensions. It displays a positive
46
- message such as "Document generated successfully," likely accompanied by a
47
- green checkmark or other visual cues indicating a successful operation.
48
- This image is suitable for illustrating UI feedback when a document
49
- generation process is completed.
50
- generatedAt: 2025-10-13T10:16:56.301Z
51
- f786c36289e0e5bfea866c9384edc7d44996c42adfad0cb6f613f46e27f0f2be:
52
- path: ../assets/screenshots/doc-generate.png
53
- description: This screenshot displays a "Generate Documentation" dialog,
54
- presenting various options for outputting documentation files. Users can
55
- specify an output path, choose to include example content, overwrite
56
- existing files, and generate the documentation in dark mode, before
57
- confirming with "Generate" or "Cancel."
58
- generatedAt: 2025-10-13T10:16:56.301Z
59
- 2b41c70c6a61942727984b2d99010cbe7e1d9b4c75686f65af8b5a245e9b800d:
60
- path: ../assets/screenshots/doc-generate-docs.png
61
- description: This image is a screenshot illustrating a user interface for a
62
- documentation generation process. It depicts a dialog or panel with
63
- various configuration options and controls, likely including output format
64
- selections and a prominent "Generate" button to initiate the creation of
65
- documentation.
66
- generatedAt: 2025-10-13T10:16:56.301Z
67
- 44cb2fc222a3dd15fa82f1088d9113b0bb1bfc8b29a0e568a2273d80e8f50a7d:
68
- path: ../assets/screenshots/doc-complete-setup.png
69
- description: This screenshot depicts the "Setup Complete" screen from a user
70
- interface, indicating the successful conclusion of an installation or
71
- configuration process. It features a prominent confirmation message, such
72
- as "Setup Complete!", often accompanied by a success icon and an
73
- actionable button like "Continue" or "Go to Dashboard" to proceed.
74
- generatedAt: 2025-10-13T10:16:56.301Z
75
- 13a9073d16762909e189af4e53ceb004abe1c55681d12726fceb262205fbf180:
76
- path: ../assets/screenshots/doc-generate.png
77
- description: This screenshot displays a user interface for generating
78
- documentation. It features various input fields and controls, likely for
79
- configuring options such as output format, target location, and content
80
- selection. The image serves to illustrate the steps or settings involved
81
- in the documentation generation process.
82
- generatedAt: 2025-10-13T14:07:35.096Z
83
- 90c0daa8347df01c8154b6a5b30879b691c4a94b49c970b0480435591603bf55:
84
- path: ../assets/screenshots/doc-complete-setup.png
85
- description: This image is a screenshot displaying a "Setup Complete" success
86
- message within a user interface. It shows a clear green checkmark icon, a
87
- bold headline confirming the setup is finished, and additional descriptive
88
- text below. A prominent "Done" button is visible at the bottom of the
89
- interface, indicating the next action for the user.
90
- generatedAt: 2025-10-13T14:07:35.097Z
91
- lastUpdated: 2025-10-13T14:07:35.098Z