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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/CLAUDE.md +43 -0
  2. package/README.md +94 -250
  3. package/aigne.yaml +2 -149
  4. package/doc-smith/SKILL.md +117 -0
  5. package/doc-smith/references/changeset_schema.md +118 -0
  6. package/doc-smith/references/document_structure_schema.md +139 -0
  7. package/doc-smith/references/document_update_guide.md +193 -0
  8. package/doc-smith/references/structure_confirmation_guide.md +133 -0
  9. package/doc-smith/references/structure_planning_guide.md +146 -0
  10. package/doc-smith/references/user_intent_guide.md +172 -0
  11. package/doc-smith.yaml +114 -0
  12. package/main-system-prompt.md +56 -0
  13. package/package.json +3 -69
  14. package/scripts/README.md +90 -0
  15. package/scripts/install.sh +86 -0
  16. package/scripts/uninstall.sh +52 -0
  17. package/CHANGELOG.md +0 -994
  18. package/LICENSE +0 -93
  19. package/agentic-agents/common/base-info.md +0 -53
  20. package/agentic-agents/common/planner.md +0 -168
  21. package/agentic-agents/common/worker.md +0 -93
  22. package/agentic-agents/create/index.yaml +0 -118
  23. package/agentic-agents/create/objective.md +0 -44
  24. package/agentic-agents/create/set-custom-prompt.mjs +0 -27
  25. package/agentic-agents/detail/index.yaml +0 -95
  26. package/agentic-agents/detail/objective.md +0 -9
  27. package/agentic-agents/detail/set-custom-prompt.mjs +0 -88
  28. package/agentic-agents/predict-resources/index.yaml +0 -44
  29. package/agentic-agents/predict-resources/instructions.md +0 -61
  30. package/agentic-agents/structure/design-rules.md +0 -39
  31. package/agentic-agents/structure/index.yaml +0 -86
  32. package/agentic-agents/structure/objective.md +0 -14
  33. package/agentic-agents/structure/review-criteria.md +0 -55
  34. package/agentic-agents/structure/set-custom-prompt.mjs +0 -78
  35. package/agentic-agents/utils/init-workspace-cache.mjs +0 -171
  36. package/agentic-agents/utils/load-base-sources.mjs +0 -20
  37. package/agentic-agents/workspace-cache-sharing-design.md +0 -671
  38. package/agents/chat/chat-system.md +0 -38
  39. package/agents/chat/index.mjs +0 -59
  40. package/agents/chat/skills/generate-document.yaml +0 -15
  41. package/agents/chat/skills/list-documents.mjs +0 -15
  42. package/agents/chat/skills/update-document.yaml +0 -24
  43. package/agents/clear/choose-contents.mjs +0 -192
  44. package/agents/clear/clear-auth-tokens.mjs +0 -88
  45. package/agents/clear/clear-deployment-config.mjs +0 -49
  46. package/agents/clear/clear-document-config.mjs +0 -36
  47. package/agents/clear/clear-document-structure.mjs +0 -102
  48. package/agents/clear/clear-generated-docs.mjs +0 -142
  49. package/agents/clear/clear-media-description.mjs +0 -129
  50. package/agents/clear/index.yaml +0 -26
  51. package/agents/create/analyze-diagram-type-llm.yaml +0 -160
  52. package/agents/create/analyze-diagram-type.mjs +0 -297
  53. package/agents/create/check-document-structure.yaml +0 -30
  54. package/agents/create/check-need-generate-structure.mjs +0 -105
  55. package/agents/create/document-structure-tools/add-document.mjs +0 -85
  56. package/agents/create/document-structure-tools/delete-document.mjs +0 -116
  57. package/agents/create/document-structure-tools/move-document.mjs +0 -109
  58. package/agents/create/document-structure-tools/update-document.mjs +0 -84
  59. package/agents/create/generate-diagram-image.yaml +0 -60
  60. package/agents/create/generate-structure.yaml +0 -117
  61. package/agents/create/index.yaml +0 -49
  62. package/agents/create/refine-document-structure.yaml +0 -12
  63. package/agents/create/replace-d2-with-image.mjs +0 -625
  64. package/agents/create/update-document-structure.yaml +0 -54
  65. package/agents/create/user-add-document/add-documents-to-structure.mjs +0 -90
  66. package/agents/create/user-add-document/find-documents-to-add-links.yaml +0 -47
  67. package/agents/create/user-add-document/index.yaml +0 -46
  68. package/agents/create/user-add-document/prepare-documents-to-translate.mjs +0 -22
  69. package/agents/create/user-add-document/print-add-document-summary.mjs +0 -63
  70. package/agents/create/user-add-document/review-documents-with-new-links.mjs +0 -110
  71. package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +0 -78
  72. package/agents/create/user-remove-document/index.yaml +0 -40
  73. package/agents/create/user-remove-document/prepare-documents-to-translate.mjs +0 -22
  74. package/agents/create/user-remove-document/print-remove-document-summary.mjs +0 -53
  75. package/agents/create/user-remove-document/remove-documents-from-structure.mjs +0 -99
  76. package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +0 -115
  77. package/agents/create/user-review-document-structure.mjs +0 -140
  78. package/agents/create/utils/init-current-content.mjs +0 -34
  79. package/agents/create/utils/merge-document-structures.mjs +0 -30
  80. package/agents/evaluate/code-snippet.mjs +0 -97
  81. package/agents/evaluate/document-structure.yaml +0 -67
  82. package/agents/evaluate/document.yaml +0 -82
  83. package/agents/evaluate/generate-report.mjs +0 -85
  84. package/agents/evaluate/index.yaml +0 -46
  85. package/agents/history/index.yaml +0 -6
  86. package/agents/history/view.mjs +0 -78
  87. package/agents/init/check.mjs +0 -16
  88. package/agents/init/index.mjs +0 -275
  89. package/agents/init/validate.mjs +0 -16
  90. package/agents/localize/choose-language.mjs +0 -107
  91. package/agents/localize/index.yaml +0 -58
  92. package/agents/localize/record-translation-history.mjs +0 -23
  93. package/agents/localize/translate-document.yaml +0 -24
  94. package/agents/localize/translate-multilingual.yaml +0 -51
  95. package/agents/media/batch-generate-media-description.yaml +0 -46
  96. package/agents/media/generate-media-description.yaml +0 -50
  97. package/agents/media/load-media-description.mjs +0 -256
  98. package/agents/prefs/index.mjs +0 -203
  99. package/agents/publish/index.yaml +0 -26
  100. package/agents/publish/publish-docs.mjs +0 -356
  101. package/agents/publish/translate-meta.mjs +0 -103
  102. package/agents/schema/document-structure-item.yaml +0 -26
  103. package/agents/schema/document-structure-refine-item.yaml +0 -23
  104. package/agents/schema/document-structure.yaml +0 -29
  105. package/agents/update/batch-generate-document.yaml +0 -27
  106. package/agents/update/batch-update-document.yaml +0 -7
  107. package/agents/update/check-diagram-flag.mjs +0 -116
  108. package/agents/update/check-document.mjs +0 -162
  109. package/agents/update/check-generate-diagram.mjs +0 -106
  110. package/agents/update/check-sync-image-flag.mjs +0 -55
  111. package/agents/update/check-update-is-single.mjs +0 -53
  112. package/agents/update/document-tools/update-document-content.mjs +0 -303
  113. package/agents/update/generate-diagram.yaml +0 -63
  114. package/agents/update/generate-document.yaml +0 -70
  115. package/agents/update/handle-document-update.yaml +0 -103
  116. package/agents/update/index.yaml +0 -79
  117. package/agents/update/pre-check-generate-diagram.yaml +0 -44
  118. package/agents/update/save-and-translate-document.mjs +0 -76
  119. package/agents/update/sync-images-and-exit.mjs +0 -148
  120. package/agents/update/update-document-detail.yaml +0 -71
  121. package/agents/update/update-single/update-single-document-detail.mjs +0 -280
  122. package/agents/update/update-single-document.yaml +0 -7
  123. package/agents/update/user-review-document.mjs +0 -272
  124. package/agents/utils/action-success.mjs +0 -16
  125. package/agents/utils/analyze-document-feedback-intent.yaml +0 -32
  126. package/agents/utils/analyze-feedback-intent.mjs +0 -136
  127. package/agents/utils/analyze-structure-feedback-intent.yaml +0 -29
  128. package/agents/utils/check-detail-result.mjs +0 -38
  129. package/agents/utils/check-feedback-refiner.mjs +0 -81
  130. package/agents/utils/choose-docs.mjs +0 -293
  131. package/agents/utils/document-icon-generate.yaml +0 -52
  132. package/agents/utils/document-title-streamline.yaml +0 -48
  133. package/agents/utils/ensure-document-icons.mjs +0 -129
  134. package/agents/utils/exit.mjs +0 -6
  135. package/agents/utils/feedback-refiner.yaml +0 -50
  136. package/agents/utils/find-item-by-path.mjs +0 -114
  137. package/agents/utils/find-user-preferences-by-path.mjs +0 -37
  138. package/agents/utils/format-document-structure.mjs +0 -35
  139. package/agents/utils/generate-document-or-skip.mjs +0 -41
  140. package/agents/utils/handle-diagram-operations.mjs +0 -263
  141. package/agents/utils/load-all-document-content.mjs +0 -30
  142. package/agents/utils/load-document-all-content.mjs +0 -84
  143. package/agents/utils/load-sources.mjs +0 -405
  144. package/agents/utils/map-reasoning-effort-level.mjs +0 -15
  145. package/agents/utils/post-generate.mjs +0 -144
  146. package/agents/utils/read-current-document-content.mjs +0 -46
  147. package/agents/utils/save-doc-translation.mjs +0 -61
  148. package/agents/utils/save-doc.mjs +0 -88
  149. package/agents/utils/save-output.mjs +0 -26
  150. package/agents/utils/save-sidebar.mjs +0 -51
  151. package/agents/utils/skip-if-content-exists.mjs +0 -27
  152. package/agents/utils/streamline-document-titles-if-needed.mjs +0 -88
  153. package/agents/utils/transform-detail-data-sources.mjs +0 -45
  154. package/agents/utils/update-branding.mjs +0 -84
  155. package/assets/report-template/report.html +0 -198
  156. package/docs-mcp/analyze-content-relevance.yaml +0 -50
  157. package/docs-mcp/analyze-docs-relevance.yaml +0 -59
  158. package/docs-mcp/docs-search.yaml +0 -42
  159. package/docs-mcp/get-docs-detail.mjs +0 -41
  160. package/docs-mcp/get-docs-structure.mjs +0 -16
  161. package/docs-mcp/read-doc-content.mjs +0 -119
  162. package/prompts/common/document/content-rules-core.md +0 -20
  163. package/prompts/common/document/markdown-syntax-rules.md +0 -65
  164. package/prompts/common/document/media-file-list-usage-rules.md +0 -18
  165. package/prompts/common/document/openapi-usage-rules.md +0 -189
  166. package/prompts/common/document/role-and-personality.md +0 -16
  167. package/prompts/common/document/user-preferences.md +0 -9
  168. package/prompts/common/document-structure/conflict-resolution-guidance.md +0 -16
  169. package/prompts/common/document-structure/document-icon-generate.md +0 -116
  170. package/prompts/common/document-structure/document-structure-rules.md +0 -43
  171. package/prompts/common/document-structure/document-title-streamline.md +0 -86
  172. package/prompts/common/document-structure/glossary.md +0 -7
  173. package/prompts/common/document-structure/intj-traits.md +0 -5
  174. package/prompts/common/document-structure/openapi-usage-rules.md +0 -28
  175. package/prompts/common/document-structure/output-constraints.md +0 -18
  176. package/prompts/common/document-structure/user-locale-rules.md +0 -10
  177. package/prompts/common/document-structure/user-preferences.md +0 -9
  178. package/prompts/detail/custom/admonition-usage-rules.md +0 -94
  179. package/prompts/detail/custom/code-block-usage-rules.md +0 -163
  180. package/prompts/detail/custom/custom-components/x-card-usage-rules.md +0 -63
  181. package/prompts/detail/custom/custom-components/x-cards-usage-rules.md +0 -83
  182. package/prompts/detail/custom/custom-components/x-field-desc-usage-rules.md +0 -120
  183. package/prompts/detail/custom/custom-components/x-field-group-usage-rules.md +0 -80
  184. package/prompts/detail/custom/custom-components/x-field-usage-rules.md +0 -189
  185. package/prompts/detail/custom/custom-components-usage-rules.md +0 -18
  186. package/prompts/detail/diagram/generate-image-system.md +0 -135
  187. package/prompts/detail/diagram/generate-image-user.md +0 -32
  188. package/prompts/detail/diagram/guide.md +0 -29
  189. package/prompts/detail/diagram/official-examples.md +0 -712
  190. package/prompts/detail/diagram/pre-check.md +0 -23
  191. package/prompts/detail/diagram/role-and-personality.md +0 -2
  192. package/prompts/detail/diagram/rules.md +0 -46
  193. package/prompts/detail/diagram/system-prompt.md +0 -1139
  194. package/prompts/detail/diagram/user-prompt.md +0 -43
  195. package/prompts/detail/generate/detail-example.md +0 -457
  196. package/prompts/detail/generate/document-rules.md +0 -45
  197. package/prompts/detail/generate/system-prompt.md +0 -61
  198. package/prompts/detail/generate/user-prompt.md +0 -99
  199. package/prompts/detail/jsx/rules.md +0 -6
  200. package/prompts/detail/update/system-prompt.md +0 -121
  201. package/prompts/detail/update/user-prompt.md +0 -41
  202. package/prompts/evaluate/document-structure.md +0 -93
  203. package/prompts/evaluate/document.md +0 -149
  204. package/prompts/media/media-description/system-prompt.md +0 -43
  205. package/prompts/media/media-description/user-prompt.md +0 -17
  206. package/prompts/structure/check-document-structure.md +0 -93
  207. package/prompts/structure/document-rules.md +0 -21
  208. package/prompts/structure/find-documents-to-add-links.md +0 -52
  209. package/prompts/structure/generate/system-prompt.md +0 -13
  210. package/prompts/structure/generate/user-prompt.md +0 -137
  211. package/prompts/structure/review/structure-review-system.md +0 -81
  212. package/prompts/structure/structure-example.md +0 -89
  213. package/prompts/structure/structure-getting-started.md +0 -10
  214. package/prompts/structure/update/system-prompt.md +0 -93
  215. package/prompts/structure/update/user-prompt.md +0 -43
  216. package/prompts/translate/admonition.md +0 -20
  217. package/prompts/translate/code-block.md +0 -33
  218. package/prompts/translate/glossary.md +0 -6
  219. package/prompts/translate/translate-document.md +0 -305
  220. package/prompts/utils/analyze-document-feedback-intent.md +0 -54
  221. package/prompts/utils/analyze-structure-feedback-intent.md +0 -43
  222. package/prompts/utils/feedback-refiner.md +0 -105
  223. package/types/document-schema.mjs +0 -55
  224. package/types/document-structure-schema.mjs +0 -261
  225. package/utils/auth-utils.mjs +0 -275
  226. package/utils/blocklet.mjs +0 -104
  227. package/utils/check-document-has-diagram.mjs +0 -95
  228. package/utils/conflict-detector.mjs +0 -149
  229. package/utils/constants/index.mjs +0 -620
  230. package/utils/constants/linter.mjs +0 -102
  231. package/utils/d2-utils.mjs +0 -198
  232. package/utils/debug.mjs +0 -3
  233. package/utils/delete-diagram-images.mjs +0 -99
  234. package/utils/deploy.mjs +0 -86
  235. package/utils/docs-finder-utils.mjs +0 -623
  236. package/utils/evaluate/report-utils.mjs +0 -132
  237. package/utils/extract-api.mjs +0 -32
  238. package/utils/file-utils.mjs +0 -960
  239. package/utils/history-utils.mjs +0 -203
  240. package/utils/icon-map.mjs +0 -26
  241. package/utils/image-compress.mjs +0 -75
  242. package/utils/kroki-utils.mjs +0 -173
  243. package/utils/linter/index.mjs +0 -50
  244. package/utils/load-config.mjs +0 -107
  245. package/utils/markdown/index.mjs +0 -26
  246. package/utils/markdown-checker.mjs +0 -694
  247. package/utils/mermaid-validator.mjs +0 -140
  248. package/utils/mermaid-worker-pool.mjs +0 -250
  249. package/utils/mermaid-worker.mjs +0 -233
  250. package/utils/openapi/index.mjs +0 -28
  251. package/utils/preferences-utils.mjs +0 -175
  252. package/utils/request.mjs +0 -10
  253. package/utils/store/index.mjs +0 -45
  254. package/utils/sync-diagram-to-translations.mjs +0 -262
  255. package/utils/upload-files.mjs +0 -231
  256. 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
- }