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

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 +5 -146
  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,623 +0,0 @@
1
- import { access, readdir, readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import chalk from "chalk";
4
- import pLimit from "p-limit";
5
- import yaml from "yaml";
6
- import { pathExists } from "./file-utils.mjs";
7
-
8
- /**
9
- * Get action-specific text based on isTranslate flag
10
- * @param {string} baseText - Base text template with {action} placeholder
11
- * @param {string} action - doc action type
12
- * @returns {string} Text with action replaced
13
- */
14
- export function getActionText(baseText, action) {
15
- return baseText.replace("{action}", action);
16
- }
17
-
18
- /**
19
- * Convert path to flattened name format
20
- * @param {string} path - Document path (e.g., "/api/users")
21
- * @returns {string} Flattened name (e.g., "api-users")
22
- */
23
- export function pathToFlatName(path) {
24
- return path.replace(/^\//, "").replace(/\//g, "-");
25
- }
26
-
27
- /**
28
- * Generate filename based on flattened path and locale
29
- * @param {string} flatName - Flattened path name
30
- * @param {string} locale - Main language locale (e.g., 'en', 'zh', 'fr')
31
- * @returns {string} Generated filename
32
- */
33
- export function generateFileName(flatName, locale) {
34
- const isEnglish = locale === "en";
35
- return isEnglish ? `${flatName}.md` : `${flatName}.${locale}.md`;
36
- }
37
-
38
- /**
39
- * Find a single item by path in documentation structure result and read its content
40
- * @param {Array} documentStructure - Array of documentation structure items
41
- * @param {string} docPath - Document path to find (supports .md filenames)
42
- * @param {string} boardId - Board ID for fallback matching
43
- * @param {string} docsDir - Docs directory path for reading content
44
- * @param {string} locale - Main language locale (e.g., 'en', 'zh', 'fr')
45
- * @returns {Promise<Object|null>} Found item with content or null
46
- */
47
- export async function findItemByPath(documentStructure, docPath, boardId, docsDir, locale = "en") {
48
- let foundItem = null;
49
- let fileName = null;
50
-
51
- // Check if docPath is a .md filename
52
- if (docPath.endsWith(".md")) {
53
- fileName = docPath;
54
- const flatName = fileNameToFlatPath(docPath);
55
- foundItem = findItemByFlatName(documentStructure, flatName);
56
- } else {
57
- // First try direct path matching
58
- foundItem = documentStructure.find((item) => item.path === docPath);
59
-
60
- // If not found and boardId is provided, try boardId-flattenedPath format matching
61
- if (!foundItem && boardId) {
62
- // Check if path starts with boardId followed by a dash
63
- if (docPath.startsWith(`${boardId}-`)) {
64
- // Extract the flattened path part after boardId-
65
- const flattenedPath = docPath.substring(boardId.length + 1);
66
-
67
- // Find item by comparing flattened paths
68
- foundItem = documentStructure.find((item) => {
69
- // Convert item.path to flattened format (replace / with -)
70
- const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
71
- return itemFlattenedPath === flattenedPath;
72
- });
73
- }
74
- }
75
-
76
- // Generate filename from found item path
77
- if (foundItem) {
78
- const itemFlattenedPath = foundItem.path.replace(/^\//, "").replace(/\//g, "-");
79
- fileName = generateFileName(itemFlattenedPath, locale);
80
- }
81
- }
82
-
83
- if (!foundItem) {
84
- return null;
85
- }
86
-
87
- // Read file content if docsDir is provided
88
- let content = null;
89
- if (docsDir && fileName) {
90
- content = await readFileContent(docsDir, fileName);
91
- }
92
-
93
- // Return item with content
94
- const result = {
95
- ...foundItem,
96
- };
97
-
98
- if (content !== null) {
99
- result.content = content;
100
- }
101
-
102
- return result;
103
- }
104
-
105
- /**
106
- * Read file content from docs directory
107
- * @param {string} docsDir - Docs directory path
108
- * @param {string} fileName - File name to read
109
- * @returns {Promise<string|null>} File content or null if failed
110
- */
111
- /**
112
- * Remove base64 encoded images from markdown content
113
- * This prevents large binary data from being included in document content
114
- * Base64 images are completely removed (not replaced with placeholders) because:
115
- * 1. They significantly increase token usage without providing useful information to LLM
116
- * 2. Normal image references (file paths) are preserved and should be used instead
117
- * 3. Base64 images are typically temporary or erroneous entries
118
- * @param {string} content - Markdown content that may contain base64 images
119
- * @returns {string} - Content with base64 images completely removed
120
- */
121
- function removeBase64Images(content) {
122
- if (!content || typeof content !== "string") {
123
- return content;
124
- }
125
-
126
- // Match markdown image syntax with data URLs: ![alt](data:image/...;base64,...)
127
- // This regex matches:
128
- // - ![alt text](data:image/type;base64,base64data...)
129
- // - ![alt](data:image/type;base64,base64data...)
130
- // - [![alt](data:image/type;base64,base64data...)](link)
131
- const base64ImageRegex = /!\[([^\]]*)\]\(data:image\/[^)]+\)/g;
132
-
133
- // Completely remove base64 images (including the entire markdown image syntax)
134
- // This maximizes token reduction while preserving normal image references
135
- const cleanedContent = content.replace(base64ImageRegex, "");
136
-
137
- return cleanedContent;
138
- }
139
-
140
- export async function readFileContent(docsDir, fileName) {
141
- try {
142
- const filePath = join(docsDir, fileName);
143
- const content = await readFile(filePath, "utf-8");
144
-
145
- // Remove base64 encoded images to reduce token usage
146
- // Base64 image data is not useful for LLM processing and significantly increases token count
147
- return removeBase64Images(content);
148
- } catch (readError) {
149
- console.warn(`⚠️ Could not read content from ${fileName}:`, readError.message);
150
- return null;
151
- }
152
- }
153
-
154
- /**
155
- * Get main language markdown files from docs directory
156
- * @param {string} docsDir - Docs directory path
157
- * @param {string} locale - Main language locale (e.g., 'en', 'zh', 'fr')
158
- * @param {Array} documentStructure - Array of documentation structure items to determine file order
159
- * @returns {Promise<string[]>} Array of main language .md files ordered by documentStructure
160
- */
161
- export async function getMainLanguageFiles(docsDir, locale, documentStructure = null) {
162
- // Check if docsDir exists
163
- try {
164
- await access(docsDir);
165
- } catch (error) {
166
- if (error.code === "ENOENT") {
167
- return [];
168
- }
169
-
170
- throw error;
171
- }
172
-
173
- const files = await readdir(docsDir);
174
-
175
- // Filter for main language .md files (exclude _sidebar.md)
176
- const filteredFiles = files.filter((file) => {
177
- // Skip non-markdown files and _sidebar.md
178
- if (!file.endsWith(".md") || file === "_sidebar.md") {
179
- return false;
180
- }
181
-
182
- // If main language is English, return files without language suffix
183
- // FIXME: 临时修改为 zh,后续需要优化
184
- if (locale === "zh") {
185
- // Return files that don't have language suffixes (e.g., overview.md, not overview.zh.md)
186
- return !file.match(/\.\w+(-\w+)?\.md$/);
187
- } else {
188
- // For non-English main language, return files with the exact locale suffix
189
- const localePattern = new RegExp(`\\.${locale}\\.md$`);
190
- return localePattern.test(file);
191
- }
192
- });
193
-
194
- // If documentStructure is provided, sort files according to the order in documentStructure
195
- if (documentStructure && Array.isArray(documentStructure)) {
196
- // Create a map from flat file name to documentation structure order
197
- const orderMap = new Map();
198
- documentStructure.forEach((item, index) => {
199
- const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
200
- const expectedFileName = generateFileName(itemFlattenedPath, locale);
201
- orderMap.set(expectedFileName, index);
202
- });
203
-
204
- // Sort filtered files based on their order in documentStructure
205
- return filteredFiles.sort((a, b) => {
206
- const orderA = orderMap.get(a);
207
- const orderB = orderMap.get(b);
208
-
209
- // If both files are in the documentation structure, sort by order
210
- if (orderA !== undefined && orderB !== undefined) {
211
- return orderA - orderB;
212
- }
213
-
214
- // If only one file is in the documentation structure, it comes first
215
- if (orderA !== undefined) return -1;
216
- if (orderB !== undefined) return 1;
217
-
218
- // If neither file is in the documentation structure, maintain alphabetical order
219
- return a.localeCompare(b);
220
- });
221
- }
222
-
223
- // If no documentStructure provided, return files in alphabetical order
224
- return filteredFiles.sort();
225
- }
226
-
227
- /**
228
- * Convert filename to flattened path format
229
- * @param {string} fileName - File name to convert
230
- * @returns {string} Flattened path without .md extension and language suffix
231
- */
232
- export function fileNameToFlatPath(fileName) {
233
- // Remove .md extension first
234
- let flatName = fileName.replace(/\.md$/, "");
235
-
236
- // Remove language suffix if present (e.g., .zh, .zh-CN, .fr, etc.)
237
- flatName = flatName.replace(/\.\w+(-\w+)?$/, "");
238
-
239
- return flatName;
240
- }
241
-
242
- /**
243
- * Find documentation structure item by flattened file name
244
- * @param {Array} documentStructure - Array of documentation structure items
245
- * @param {string} flatName - Flattened file name
246
- * @returns {Object|null} Found item or null
247
- */
248
- export function findItemByFlatName(documentStructure, flatName) {
249
- return documentStructure.find((item) => {
250
- const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
251
- return itemFlattenedPath === flatName;
252
- });
253
- }
254
-
255
- /**
256
- * Process selected files and convert to found items with content
257
- * @param {string[]} selectedFiles - Array of selected file names
258
- * @param {Array} documentStructure - Array of documentation structure items
259
- * @param {string} docsDir - Docs directory path
260
- * @returns {Promise<Object[]>} Array of found items with content
261
- */
262
- export async function processSelectedFiles(selectedFiles, documentStructure, docsDir) {
263
- const foundItems = [];
264
-
265
- for (const selectedFile of selectedFiles) {
266
- // Read the selected .md file content
267
- const selectedFileContent = await readFileContent(docsDir, selectedFile);
268
-
269
- // Convert filename back to path
270
- const flatName = fileNameToFlatPath(selectedFile);
271
-
272
- // Try to find matching item by comparing flattened paths
273
- const foundItemByFile = findItemByFlatName(documentStructure, flatName);
274
-
275
- if (foundItemByFile) {
276
- const result = {
277
- ...foundItemByFile,
278
- };
279
-
280
- // Add content if we read it from user selection
281
- if (selectedFileContent !== null) {
282
- result.content = selectedFileContent;
283
- }
284
-
285
- foundItems.push(result);
286
- } else {
287
- console.warn(`⚠️ No documentation structure item found for file: ${selectedFile}`);
288
- }
289
- }
290
-
291
- return foundItems;
292
- }
293
-
294
- /**
295
- * Add feedback to all items in the array
296
- * @param {Object[]} items - Array of items to add feedback to
297
- * @param {string} feedback - Feedback text to add
298
- * @returns {Object[]} Items with feedback added
299
- */
300
- export function addFeedbackToItems(items, feedback) {
301
- if (!feedback?.trim()) {
302
- return items;
303
- }
304
-
305
- return items.map((item) => ({
306
- ...item,
307
- feedback: feedback.trim(),
308
- }));
309
- }
310
-
311
- /**
312
- * Convert YAML document structure to flat array format
313
- * @param {Object} yamlData - Parsed YAML data with documents array
314
- * @returns {Array} Flat array of document structure items
315
- */
316
- function convertYamlToStructure(yamlData) {
317
- const result = [];
318
-
319
- function flattenDocuments(documents, parentId = null) {
320
- if (!Array.isArray(documents)) {
321
- return;
322
- }
323
-
324
- for (const doc of documents) {
325
- if (!doc.path || !doc.title) {
326
- continue;
327
- }
328
-
329
- // Create structure item
330
- const item = {
331
- title: doc.title,
332
- description: doc.description || "",
333
- path: doc.path,
334
- };
335
-
336
- if (parentId) {
337
- item.parentId = parentId;
338
- }
339
-
340
- if (doc.icon) {
341
- item.icon = doc.icon;
342
- }
343
-
344
- if (doc.sourcePaths) {
345
- item.sourcePaths = doc.sourcePaths;
346
- }
347
-
348
- result.push(item);
349
-
350
- // Recursively process children
351
- if (doc.children && Array.isArray(doc.children)) {
352
- flattenDocuments(doc.children, doc.path);
353
- }
354
- }
355
- }
356
-
357
- flattenDocuments(yamlData.documents);
358
- return result;
359
- }
360
-
361
- /**
362
- * Load document execution structure from structure-plan.json or document_structure.yaml
363
- * @param {string} outputDir - Output directory containing structure files
364
- * @returns {Promise<Array|null>} Document execution structure array or null if not found/failed
365
- */
366
- export async function loadDocumentStructure(outputDir) {
367
- if (!outputDir) {
368
- return null;
369
- }
370
-
371
- // Try loading structure-plan.json first
372
- try {
373
- const structurePlanPath = join(outputDir, "structure-plan.json");
374
- const structureExists = await pathExists(structurePlanPath);
375
-
376
- if (structureExists) {
377
- const structureContent = await readFile(structurePlanPath, "utf8");
378
- if (structureContent?.trim()) {
379
- try {
380
- // Validate that the content looks like JSON before parsing
381
- const trimmedContent = structureContent.trim();
382
- if (trimmedContent.startsWith("[") || trimmedContent.startsWith("{")) {
383
- const parsed = JSON.parse(structureContent);
384
- // Return array if it's an array, otherwise return null
385
- if (Array.isArray(parsed)) {
386
- return parsed;
387
- }
388
- } else {
389
- console.warn("structure-plan.json contains non-JSON content, skipping parse");
390
- }
391
- } catch (parseError) {
392
- console.error(`Failed to parse structure-plan.json: ${parseError.message}`);
393
- }
394
- }
395
- }
396
- } catch (readError) {
397
- // Only warn if it's not a "file not found" error
398
- if (readError.code !== "ENOENT") {
399
- console.warn(`Error reading structure-plan.json: ${readError.message}`);
400
- }
401
- }
402
-
403
- // Try loading document_structure.yaml as fallback
404
- try {
405
- const yamlPath = join(outputDir, "document_structure.yaml");
406
- const yamlExists = await pathExists(yamlPath);
407
-
408
- if (yamlExists) {
409
- const yamlContent = await readFile(yamlPath, "utf8");
410
- if (yamlContent?.trim()) {
411
- try {
412
- const parsed = yaml.parse(yamlContent);
413
- if (parsed && parsed.documents) {
414
- return convertYamlToStructure(parsed);
415
- }
416
- } catch (parseError) {
417
- console.error(`Failed to parse document_structure.yaml: ${parseError.message}`);
418
- }
419
- }
420
- }
421
- } catch (readError) {
422
- // Only warn if it's not a "file not found" error
423
- if (readError.code !== "ENOENT") {
424
- console.warn(`Error reading document_structure.yaml: ${readError.message}`);
425
- }
426
- }
427
-
428
- return null;
429
- }
430
-
431
- /**
432
- * Build allowed links set from document structure
433
- * Includes both original paths and processed .md paths for link validation
434
- * @param {Array} documentStructure - Array of documentation structure items with path property
435
- * @returns {Set<string>} Set of allowed link paths
436
- */
437
- export function buildAllowedLinksFromStructure(documentStructure) {
438
- const allowedLinks = new Set();
439
-
440
- if (!Array.isArray(documentStructure)) {
441
- return allowedLinks;
442
- }
443
-
444
- documentStructure.forEach((item) => {
445
- if (!item?.path) {
446
- return;
447
- }
448
-
449
- // Add original path
450
- allowedLinks.add(item.path);
451
-
452
- // Add processed .md path (same logic as processContent in utils.mjs)
453
- let processedPath = item.path;
454
- if (processedPath.startsWith(".")) {
455
- processedPath = processedPath.replace(/^\./, "");
456
- }
457
- let flatPath = processedPath.replace(/^\//, "").replace(/\//g, "-");
458
- flatPath = `./${flatPath}.md`;
459
- allowedLinks.add(flatPath);
460
- });
461
-
462
- return allowedLinks;
463
- }
464
-
465
- /**
466
- * Build a tree structure from a flat document structure array using parentId
467
- * @param {Array} documentStructure - Flat array of document structure items with path and parentId
468
- * @returns {Object} Object containing rootNodes (array of root nodes) and nodeMap (Map for lookups)
469
- */
470
- export function buildDocumentTree(documentStructure) {
471
- // Create a map of nodes for easy lookup
472
- const nodeMap = new Map();
473
- const rootNodes = [];
474
-
475
- // First pass: create node map
476
- documentStructure.forEach((node) => {
477
- nodeMap.set(node.path, {
478
- ...node,
479
- children: [],
480
- });
481
- });
482
-
483
- // Build the tree structure using parentId
484
- documentStructure.forEach((node) => {
485
- if (node.parentId) {
486
- const parent = nodeMap.get(node.parentId);
487
- if (parent) {
488
- parent.children.push(nodeMap.get(node.path));
489
- } else {
490
- rootNodes.push(nodeMap.get(node.path));
491
- }
492
- } else {
493
- rootNodes.push(nodeMap.get(node.path));
494
- }
495
- });
496
-
497
- return { rootNodes, nodeMap };
498
- }
499
-
500
- /**
501
- * Build checkbox choices from tree structure with visual hierarchy
502
- * @param {Array} nodes - Array of tree nodes
503
- * @param {string} prefix - Current prefix for indentation
504
- * @param {number} depth - Current depth level (0 for root)
505
- * @param {Object} context - Context object containing locale, docsDir, etc.
506
- * @param {string} context.locale - Main language locale (e.g., 'en', 'zh', 'fr')
507
- * @param {string} [context.docsDir] - Docs directory path for file existence check
508
- * @returns {Promise<Array>} Array of choice objects
509
- */
510
- export async function buildChoicesFromTree(nodes, prefix = "", depth = 0, context = {}) {
511
- const { locale = "en", docsDir } = context;
512
- const choices = [];
513
-
514
- // Limit concurrent file checks to 50 per level to avoid overwhelming the file system
515
- const limit = pLimit(50);
516
-
517
- // Process nodes with controlled concurrency while maintaining order
518
- const nodePromises = nodes.map((node, i) =>
519
- limit(async () => {
520
- const isLastSibling = i === nodes.length - 1;
521
- const hasChildren = node.children && node.children.length > 0;
522
-
523
- // Build the tree prefix - top level nodes don't have ├─ or └─
524
- const treePrefix = depth === 0 ? "" : prefix + (isLastSibling ? "└─ " : "├─ ");
525
- const flatName = pathToFlatName(node.path);
526
- const filename = generateFileName(flatName, locale);
527
-
528
- // Check file existence if docsDir is provided
529
- let fileExists = true;
530
- let missingFileText = "";
531
- if (docsDir) {
532
- const filePath = join(docsDir, filename);
533
- fileExists = await pathExists(filePath);
534
- if (!fileExists) {
535
- missingFileText = chalk.red(" - file not found");
536
- }
537
- }
538
-
539
- // warningText only shows when file exists, missingFileText has higher priority
540
- const warningText =
541
- fileExists && hasChildren ? chalk.yellow(" - will cascade delete all child documents") : "";
542
-
543
- const displayName = `${treePrefix}${node.title} (${filename})${warningText}${missingFileText}`;
544
-
545
- const choice = {
546
- name: displayName,
547
- value: node.path,
548
- short: node.title,
549
- disabled: !fileExists,
550
- };
551
-
552
- // Recursively process children
553
- let childChoices = [];
554
- if (hasChildren) {
555
- const childPrefix = depth === 0 ? "" : prefix + (isLastSibling ? " " : "│ ");
556
- childChoices = await buildChoicesFromTree(node.children, childPrefix, depth + 1, context);
557
- }
558
-
559
- return { choice, childChoices };
560
- }),
561
- );
562
-
563
- // Wait for all nodes at this level to complete, maintaining order
564
- const results = await Promise.all(nodePromises);
565
-
566
- // Build choices array in order
567
- for (const { choice, childChoices } of results) {
568
- choices.push(choice);
569
- if (childChoices.length > 0) {
570
- choices.push(...childChoices);
571
- }
572
- }
573
-
574
- return choices;
575
- }
576
-
577
- /**
578
- * Format document structure for printing
579
- * @param {Array} structure - Document structure array
580
- * @returns {Object} Object containing rootNodes and printNode function
581
- */
582
- function formatDocumentStructure(structure) {
583
- const { rootNodes } = buildDocumentTree(structure);
584
-
585
- function printNode(node, depth = 0) {
586
- const INDENT_SPACES = " ";
587
- const FOLDER_ICON = " 📁";
588
- const FILE_ICON = " 📄";
589
- const indent = INDENT_SPACES.repeat(depth);
590
- const prefix = depth === 0 ? FOLDER_ICON : FILE_ICON;
591
-
592
- console.log(`${indent}${prefix} ${node.title}`);
593
-
594
- if (node.children && node.children.length > 0) {
595
- node.children.forEach((child) => {
596
- printNode(child, depth + 1);
597
- });
598
- }
599
- }
600
-
601
- return { rootNodes, printNode };
602
- }
603
-
604
- /**
605
- * Print document structure in a user-friendly format
606
- * @param {Array} structure - Document structure array
607
- */
608
- export function printDocumentStructure(structure) {
609
- console.log(`\n ${"-".repeat(50)}`);
610
- console.log(" Current Documentation Structure");
611
- console.log(` ${"-".repeat(50)}`);
612
-
613
- const { rootNodes, printNode } = formatDocumentStructure(structure);
614
-
615
- if (rootNodes.length === 0) {
616
- console.log(" No documentation structure found.");
617
- } else {
618
- rootNodes.forEach((node) => {
619
- printNode(node);
620
- });
621
- }
622
- console.log();
623
- }