@aigne/doc-smith 0.8.5 → 0.8.7

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 (126) hide show
  1. package/.aigne/doc-smith/output/structure-plan.json +1 -5
  2. package/CHANGELOG.md +25 -0
  3. package/README.md +3 -3
  4. package/agents/{chat.yaml → chat/index.yaml} +7 -7
  5. package/agents/generate/check-document-structure.yaml +30 -0
  6. package/agents/{check-structure-plan.mjs → generate/check-need-generate-structure.mjs} +21 -21
  7. package/agents/generate/generate-structure.yaml +58 -0
  8. package/agents/{docs-generator.yaml → generate/index.yaml} +15 -16
  9. package/agents/generate/refine-document-structure.yaml +12 -0
  10. package/agents/{input-generator.mjs → init/index.mjs} +34 -27
  11. package/agents/{manage-prefs.mjs → prefs/index.mjs} +16 -16
  12. package/agents/publish/index.yaml +17 -0
  13. package/agents/{publish-docs.mjs → publish/publish-docs.mjs} +15 -16
  14. package/agents/schema/{structure-plan-result.yaml → document-execution-structure.yaml} +3 -3
  15. package/agents/schema/document-structure.yaml +26 -0
  16. package/agents/{language-selector.mjs → translate/choose-language.mjs} +5 -5
  17. package/agents/{retranslate.yaml → translate/index.yaml} +17 -18
  18. package/agents/translate/translate-document.yaml +32 -0
  19. package/agents/{batch-translate.yaml → translate/translate-multilingual.yaml} +5 -5
  20. package/agents/update/batch-generate-document.yaml +19 -0
  21. package/agents/{check-detail.mjs → update/check-document.mjs} +16 -16
  22. package/agents/{detail-generator-and-translate.yaml → update/generate-and-translate-document.yaml} +23 -23
  23. package/agents/update/generate-document.yaml +50 -0
  24. package/agents/{detail-regenerator.yaml → update/index.yaml} +16 -17
  25. package/agents/{action-success.mjs → utils/action-success.mjs} +2 -2
  26. package/agents/{check-detail-result.mjs → utils/check-detail-result.mjs} +3 -3
  27. package/agents/{check-feedback-refiner.mjs → utils/check-feedback-refiner.mjs} +6 -6
  28. package/agents/{find-items-by-paths.mjs → utils/choose-docs.mjs} +25 -10
  29. package/agents/{docs-fs.yaml → utils/docs-fs-actor.yaml} +3 -1
  30. package/agents/utils/feedback-refiner.yaml +50 -0
  31. package/agents/{find-item-by-path.mjs → utils/find-item-by-path.mjs} +17 -7
  32. package/agents/{find-user-preferences-by-path.mjs → utils/find-user-preferences-by-path.mjs} +1 -1
  33. package/agents/utils/format-document-structure.mjs +25 -0
  34. package/agents/{load-sources.mjs → utils/load-sources.mjs} +41 -28
  35. package/agents/{save-docs.mjs → utils/save-docs.mjs} +16 -16
  36. package/agents/{save-single-doc.mjs → utils/save-single-doc.mjs} +2 -2
  37. package/agents/{transform-detail-datasources.mjs → utils/transform-detail-datasources.mjs} +1 -1
  38. package/aigne.yaml +35 -35
  39. package/docs/cli-reference.md +1 -1
  40. package/docs/features-generate-documentation.md +1 -1
  41. package/docs/features-update-and-refine.md +2 -2
  42. package/docs-mcp/analyze-docs-relevance.yaml +10 -10
  43. package/docs-mcp/docs-search.yaml +5 -3
  44. package/package.json +10 -8
  45. package/prompts/{document → detail/custom}/custom-code-block.md +6 -6
  46. package/prompts/detail/custom/custom-components.md +172 -0
  47. package/prompts/{document → detail}/d2-chart/rules.md +95 -1
  48. package/prompts/{document → detail}/detail-example.md +80 -61
  49. package/prompts/{document/detail-generator.md → detail/document-rules.md} +4 -8
  50. package/prompts/{content-detail-generator.md → detail/generate-document.md} +48 -25
  51. package/prompts/{check-structure-planning-result.md → structure/check-document-structure.md} +23 -17
  52. package/prompts/{document/structure-planning.md → structure/document-rules.md} +0 -2
  53. package/prompts/{structure-planning.md → structure/generate-structure.md} +51 -30
  54. package/prompts/{document → structure}/structure-example.md +2 -2
  55. package/prompts/{document → structure}/structure-getting-started.md +2 -2
  56. package/prompts/translate/glossary.md +6 -0
  57. package/prompts/{translator.md → translate/translate-document.md} +29 -10
  58. package/prompts/{feedback-refiner.md → utils/feedback-refiner.md} +8 -8
  59. package/tests/agents/chat/chat.test.mjs +46 -0
  60. package/tests/agents/generate/check-document-structure.test.mjs +51 -0
  61. package/tests/agents/generate/check-need-generate-structure.test.mjs +292 -0
  62. package/tests/agents/generate/generate-structure.test.mjs +51 -0
  63. package/tests/{input-generator.test.mjs → agents/init/init.test.mjs} +19 -17
  64. package/tests/agents/prefs/prefs.test.mjs +431 -0
  65. package/tests/agents/publish/publish-docs.test.mjs +642 -0
  66. package/tests/agents/translate/choose-language.test.mjs +311 -0
  67. package/tests/agents/translate/translate-document.test.mjs +51 -0
  68. package/tests/agents/update/check-document.test.mjs +523 -0
  69. package/tests/agents/update/generate-document.test.mjs +51 -0
  70. package/tests/agents/utils/action-success.test.mjs +54 -0
  71. package/tests/{check-detail-result.test.mjs → agents/utils/check-detail-result.test.mjs} +98 -98
  72. package/tests/agents/utils/check-feedback-refiner.test.mjs +478 -0
  73. package/tests/agents/utils/choose-docs.test.mjs +417 -0
  74. package/tests/agents/utils/exit.test.mjs +70 -0
  75. package/tests/agents/utils/feedback-refiner.test.mjs +51 -0
  76. package/tests/agents/utils/find-item-by-path.test.mjs +526 -0
  77. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +382 -0
  78. package/tests/agents/utils/format-document-structure.test.mjs +264 -0
  79. package/tests/agents/utils/fs.test.mjs +267 -0
  80. package/tests/{load-sources.test.mjs → agents/utils/load-sources.test.mjs} +153 -25
  81. package/tests/{save-docs.test.mjs → agents/utils/save-docs.test.mjs} +11 -5
  82. package/tests/agents/utils/save-output.test.mjs +315 -0
  83. package/tests/agents/utils/save-single-doc.test.mjs +364 -0
  84. package/tests/agents/utils/transform-detail-datasources.test.mjs +363 -0
  85. package/tests/utils/auth-utils.test.mjs +358 -0
  86. package/tests/utils/blocklet.test.mjs +334 -0
  87. package/tests/{conflict-resolution.test.mjs → utils/conflict-detector.test.mjs} +3 -3
  88. package/tests/utils/constants.test.mjs +295 -0
  89. package/tests/utils/d2-utils.test.mjs +423 -0
  90. package/tests/utils/deploy.test.mjs +365 -0
  91. package/tests/utils/docs-finder-utils.test.mjs +625 -0
  92. package/tests/utils/file-utils.test.mjs +213 -0
  93. package/tests/{kroki-utils.test.mjs → utils/kroki-utils.test.mjs} +2 -2
  94. package/tests/utils/load-config.test.mjs +141 -0
  95. package/tests/{mermaid-validation.test.mjs → utils/mermaid-validator.test.mjs} +2 -2
  96. package/tests/utils/mock-chat-model.mjs +12 -0
  97. package/tests/{preferences-utils.test.mjs → utils/preferences-utils.test.mjs} +1 -1
  98. package/tests/{save-value-to-config.test.mjs → utils/save-value-to-config.test.mjs} +61 -4
  99. package/tests/utils/utils.test.mjs +939 -0
  100. package/utils/auth-utils.mjs +1 -1
  101. package/utils/conflict-detector.mjs +1 -1
  102. package/utils/constants.mjs +5 -3
  103. package/utils/d2-utils.mjs +194 -0
  104. package/utils/deploy.mjs +3 -3
  105. package/utils/docs-finder-utils.mjs +26 -26
  106. package/utils/icon-map.mjs +26 -0
  107. package/{agents → utils}/load-config.mjs +2 -18
  108. package/utils/markdown-checker.mjs +5 -5
  109. package/agents/batch-docs-detail-generator.yaml +0 -19
  110. package/agents/check-structure-planning-result.yaml +0 -30
  111. package/agents/content-detail-generator.yaml +0 -50
  112. package/agents/feedback-refiner.yaml +0 -52
  113. package/agents/format-structure-plan.mjs +0 -25
  114. package/agents/reflective-structure-planner.yaml +0 -12
  115. package/agents/schema/structure-plan.yaml +0 -26
  116. package/agents/structure-planning.yaml +0 -58
  117. package/agents/team-publish-docs.yaml +0 -18
  118. package/agents/translate.yaml +0 -31
  119. package/prompts/document/custom-components.md +0 -104
  120. package/tests/README.md +0 -93
  121. package/tests/utils.test.mjs +0 -2067
  122. /package/agents/{exit.mjs → utils/exit.mjs} +0 -0
  123. /package/agents/{fs.mjs → utils/fs.mjs} +0 -0
  124. /package/agents/{save-output.mjs → utils/save-output.mjs} +0 -0
  125. /package/prompts/{document → detail}/d2-chart/official-examples.md +0 -0
  126. /package/prompts/{document → detail}/jsx/rules.md +0 -0
@@ -2,21 +2,20 @@ type: team
2
2
  name: update
3
3
  alias:
4
4
  - up
5
- description: Optimize and regenerate individual document content and translations
5
+ description: Update specific documents and their translations
6
6
  skills:
7
- - url: ./input-generator.mjs
7
+ - url: ../init/index.mjs
8
8
  default_input:
9
9
  skipIfExists: true
10
- - ./load-config.mjs
11
- - ./load-sources.mjs
10
+ - ../utils/load-sources.mjs
12
11
  - type: transform
13
12
  task_render_mode: hide
14
13
  jsonata: |
15
14
  $merge([
16
15
  $,
17
16
  {
18
- 'structurePlan': originalStructurePlan,
19
- 'structurePlanResult': $map(originalStructurePlan, function($item) {
17
+ 'documentStructure': originalDocumentStructure,
18
+ 'documentExecutionStructure': $map(originalDocumentStructure, function($item) {
20
19
  $merge([
21
20
  $item,
22
21
  {
@@ -26,37 +25,37 @@ skills:
26
25
  })
27
26
  }
28
27
  ])
29
- - ./find-items-by-paths.mjs
30
- - ./format-structure-plan.mjs
28
+ - ../utils/choose-docs.mjs
29
+ - ../utils/format-document-structure.mjs
31
30
  - type: team
32
- name: batchDocsUpdate
31
+ name: batchUpdateDocument
33
32
  skills:
34
- - ./detail-generator-and-translate.yaml
33
+ - ../update/generate-and-translate-document.yaml
35
34
  iterate_on: selectedDocs
36
35
  concurrency: 3
37
- - url: ./check-feedback-refiner.mjs
36
+ - url: ../utils/check-feedback-refiner.mjs
38
37
  default_input:
39
38
  stage: document_refine
40
- - url: ./action-success.mjs
39
+ - url: ../utils/action-success.mjs
41
40
  default_input:
42
- action: "Document updated"
41
+ action: " Documents updated successfully"
43
42
  input_schema:
44
43
  type: object
45
44
  properties:
46
45
  glossary:
47
46
  type: string
48
- description: Glossary of terms for consistent terminology, use @<file> to read from a file
47
+ description: Glossary file for consistent terminology (use @filename.md)
49
48
  docs:
50
49
  type: array
51
50
  items:
52
51
  type: string
53
- description: Document paths to translate
52
+ description: Documents to update
54
53
  feedback:
55
54
  type: string
56
- description: Feedback for content improvement
55
+ description: Tell us what to change in this content
57
56
  reset:
58
57
  type: boolean
59
- description: Ignore previous results and regenerate content from scratch
58
+ description: Start fresh - ignore previous versions
60
59
  output_schema:
61
60
  type: object
62
61
  properties:
@@ -1,4 +1,4 @@
1
- import { shutdownMermaidWorkerPool } from "../utils/mermaid-worker-pool.mjs";
1
+ import { shutdownMermaidWorkerPool } from "../../utils/mermaid-worker-pool.mjs";
2
2
 
3
3
  export default async function actionSuccess({ action }) {
4
4
  // Shutdown mermaid worker pool to ensure clean exit
@@ -9,7 +9,7 @@ export default async function actionSuccess({ action }) {
9
9
  }
10
10
 
11
11
  return {
12
- message: `✅ ${action} successfully`,
12
+ message: `${action}`,
13
13
  };
14
14
  }
15
15
 
@@ -1,6 +1,6 @@
1
- import { checkMarkdown } from "../utils/markdown-checker.mjs";
1
+ import { checkMarkdown } from "../../utils/markdown-checker.mjs";
2
2
 
3
- export default async function checkDetailResult({ structurePlan, reviewContent, docsDir }) {
3
+ export default async function checkDetailResult({ documentStructure, reviewContent, docsDir }) {
4
4
  if (!reviewContent || reviewContent.trim() === "") {
5
5
  return {
6
6
  isApproved: false,
@@ -13,7 +13,7 @@ export default async function checkDetailResult({ structurePlan, reviewContent,
13
13
 
14
14
  // Create a set of allowed links, including both original paths and processed .md paths
15
15
  const allowedLinks = new Set();
16
- structurePlan.forEach((item) => {
16
+ documentStructure.forEach((item) => {
17
17
  // Add original path
18
18
  allowedLinks.add(item.path);
19
19
 
@@ -1,12 +1,12 @@
1
1
  import { stringify } from "yaml";
2
- import { addPreferenceRule, readPreferences } from "../utils/preferences-utils.mjs";
2
+ import { addPreferenceRule, readPreferences } from "../../utils/preferences-utils.mjs";
3
3
 
4
4
  export default async function checkFeedbackRefiner(
5
- { feedback, stage, selectedPaths, structurePlanFeedback },
5
+ { feedback, stage, selectedPaths, documentStructureFeedback },
6
6
  options,
7
7
  ) {
8
8
  // If feedback is empty, no need to save user preferences
9
- if (!feedback && !structurePlanFeedback) {
9
+ if (!feedback && !documentStructureFeedback) {
10
10
  return {};
11
11
  }
12
12
 
@@ -18,7 +18,7 @@ export default async function checkFeedbackRefiner(
18
18
  const activePreferencesYaml =
19
19
  activePreferences.length > 0 ? stringify({ rules: activePreferences }, { indent: 2 }) : "";
20
20
 
21
- const feedbackToUse = feedback || structurePlanFeedback;
21
+ const feedbackToUse = feedback || documentStructureFeedback;
22
22
  const result = await options.context.invoke(options.context.agents["feedbackRefiner"], {
23
23
  feedback: feedbackToUse,
24
24
  stage,
@@ -60,9 +60,9 @@ checkFeedbackRefiner.input_schema = {
60
60
  type: "string",
61
61
  description: "User feedback to refine",
62
62
  },
63
- structurePlanFeedback: {
63
+ documentStructureFeedback: {
64
64
  type: "string",
65
- description: "Feedback from structure planning stage",
65
+ description: "Feedback from document structure stage",
66
66
  },
67
67
  stage: {
68
68
  type: "string",
@@ -4,10 +4,19 @@ import {
4
4
  getActionText,
5
5
  getMainLanguageFiles,
6
6
  processSelectedFiles,
7
- } from "../utils/docs-finder-utils.mjs";
8
-
9
- export default async function selectedDocs(
10
- { docs, structurePlanResult, boardId, docsDir, isTranslate, feedback, locale, reset = false },
7
+ } from "../../utils/docs-finder-utils.mjs";
8
+
9
+ export default async function chooseDocs(
10
+ {
11
+ docs,
12
+ documentExecutionStructure,
13
+ boardId,
14
+ docsDir,
15
+ isTranslate,
16
+ feedback,
17
+ locale,
18
+ reset = false,
19
+ },
11
20
  options,
12
21
  ) {
13
22
  let foundItems = [];
@@ -17,7 +26,11 @@ export default async function selectedDocs(
17
26
  if (!docs || docs.length === 0) {
18
27
  try {
19
28
  // Get all main language .md files in docsDir
20
- const mainLanguageFiles = await getMainLanguageFiles(docsDir, locale, structurePlanResult);
29
+ const mainLanguageFiles = await getMainLanguageFiles(
30
+ docsDir,
31
+ locale,
32
+ documentExecutionStructure,
33
+ );
21
34
 
22
35
  if (mainLanguageFiles.length === 0) {
23
36
  throw new Error("No documents found in the docs directory");
@@ -49,7 +62,7 @@ export default async function selectedDocs(
49
62
  }
50
63
 
51
64
  // Process selected files and convert to found items
52
- foundItems = await processSelectedFiles(selectedFiles, structurePlanResult, docsDir);
65
+ foundItems = await processSelectedFiles(selectedFiles, documentExecutionStructure, docsDir);
53
66
  } catch (error) {
54
67
  console.error(error);
55
68
  throw new Error(
@@ -63,7 +76,7 @@ export default async function selectedDocs(
63
76
  // Process the provided docs array
64
77
  for (const docPath of docs) {
65
78
  const foundItem = await findItemByPath(
66
- structurePlanResult,
79
+ documentExecutionStructure,
67
80
  docPath,
68
81
  boardId,
69
82
  docsDir,
@@ -71,7 +84,7 @@ export default async function selectedDocs(
71
84
  );
72
85
 
73
86
  if (!foundItem) {
74
- console.warn(`⚠️ Item with path "${docPath}" not found in structurePlanResult`);
87
+ console.warn(`⚠️ Item with path "${docPath}" not found in documentExecutionStructure`);
75
88
  continue;
76
89
  }
77
90
 
@@ -81,7 +94,9 @@ export default async function selectedDocs(
81
94
  }
82
95
 
83
96
  if (foundItems.length === 0) {
84
- throw new Error("None of the specified document paths were found in structurePlanResult");
97
+ throw new Error(
98
+ "None of the specified document paths were found in documentExecutionStructure",
99
+ );
85
100
  }
86
101
  }
87
102
 
@@ -90,7 +105,7 @@ export default async function selectedDocs(
90
105
  if (!userFeedback) {
91
106
  const feedbackMessage = getActionText(
92
107
  isTranslate,
93
- "Please provide feedback for the {action} (press Enter to skip):",
108
+ "How should we improve this {action}? (press Enter to skip):",
94
109
  );
95
110
 
96
111
  userFeedback = await options.prompts.input({
@@ -2,7 +2,9 @@ type: team
2
2
  name: docs_fs_actor
3
3
  description: File system operations for documentation management
4
4
  skills:
5
- - ./load-config.mjs
5
+ - url: ../init/index.mjs
6
+ default_input:
7
+ skipIfExists: true
6
8
  - url: ./fs.mjs
7
9
  default_input:
8
10
  rootDir:
@@ -0,0 +1,50 @@
1
+ name: feedbackRefiner
2
+ description: Learn from your feedback to improve future documentation
3
+ instructions:
4
+ url: ../../prompts/utils/feedback-refiner.md
5
+
6
+ input_schema:
7
+ type: object
8
+ properties:
9
+ feedback:
10
+ type: string
11
+ description: Tell us what you think about the documentation
12
+ stage:
13
+ type: string
14
+ description: Which part of the process this feedback is about (document_structure, document_refine, translation_refine)
15
+ paths:
16
+ type: array
17
+ items:
18
+ type: string
19
+ description: Specific documents this feedback applies to (optional)
20
+ existingPreferences:
21
+ type: string
22
+ description: Your existing preferences to avoid duplicates (optional)
23
+ required:
24
+ - feedback
25
+ - stage
26
+
27
+ output_schema:
28
+ type: object
29
+ properties:
30
+ rule:
31
+ type: string
32
+ description: General rule created from your feedback
33
+ scope:
34
+ type: string
35
+ description: Where this rule applies (global, structure, document, translation)
36
+ save:
37
+ type: boolean
38
+ description: Should we remember this preference for next time?
39
+ limitToInputPaths:
40
+ type: boolean
41
+ description: Apply only to the specific documents mentioned?
42
+ reason:
43
+ type: string
44
+ description: Why we made this decision and how the rule was created
45
+ required:
46
+ - rule
47
+ - scope
48
+ - save
49
+ - limitToInputPaths
50
+ - reason
@@ -5,10 +5,10 @@ import {
5
5
  getActionText,
6
6
  getMainLanguageFiles,
7
7
  readFileContent,
8
- } from "../utils/docs-finder-utils.mjs";
8
+ } from "../../utils/docs-finder-utils.mjs";
9
9
 
10
10
  export default async function findItemByPath(
11
- { doc, structurePlanResult, boardId, docsDir, isTranslate, feedback, locale },
11
+ { doc, documentExecutionStructure, boardId, docsDir, isTranslate, feedback, locale },
12
12
  options,
13
13
  ) {
14
14
  let foundItem = null;
@@ -19,7 +19,11 @@ export default async function findItemByPath(
19
19
  if (!docPath) {
20
20
  try {
21
21
  // Get all main language .md files in docsDir
22
- const mainLanguageFiles = await getMainLanguageFiles(docsDir, locale, structurePlanResult);
22
+ const mainLanguageFiles = await getMainLanguageFiles(
23
+ docsDir,
24
+ locale,
25
+ documentExecutionStructure,
26
+ );
23
27
 
24
28
  if (mainLanguageFiles.length === 0) {
25
29
  throw new Error("No documents found in the docs directory");
@@ -59,7 +63,7 @@ export default async function findItemByPath(
59
63
  const flatName = fileNameToFlatPath(selectedFile);
60
64
 
61
65
  // Try to find matching item by comparing flattened paths
62
- const foundItemByFile = findItemByFlatName(structurePlanResult, flatName);
66
+ const foundItemByFile = findItemByFlatName(documentExecutionStructure, flatName);
63
67
 
64
68
  if (!foundItemByFile) {
65
69
  throw new Error("No document found");
@@ -78,10 +82,16 @@ export default async function findItemByPath(
78
82
  }
79
83
 
80
84
  // Use the utility function to find item and read content
81
- foundItem = await findItemByPathUtil(structurePlanResult, docPath, boardId, docsDir, locale);
85
+ foundItem = await findItemByPathUtil(
86
+ documentExecutionStructure,
87
+ docPath,
88
+ boardId,
89
+ docsDir,
90
+ locale,
91
+ );
82
92
 
83
93
  if (!foundItem) {
84
- throw new Error(`Item with path "${docPath}" not found in structurePlanResult`);
94
+ throw new Error(`Item with path "${docPath}" not found in documentExecutionStructure`);
85
95
  }
86
96
 
87
97
  // Prompt for feedback if not provided
@@ -89,7 +99,7 @@ export default async function findItemByPath(
89
99
  if (!userFeedback) {
90
100
  const feedbackMessage = getActionText(
91
101
  isTranslate,
92
- "Please provide feedback for the {action} (press Enter to skip):",
102
+ "How should we improve this {action}? (press Enter to skip):",
93
103
  );
94
104
 
95
105
  userFeedback = await options.prompts.input({
@@ -1,4 +1,4 @@
1
- import { getActiveRulesForScope } from "../utils/preferences-utils.mjs";
1
+ import { getActiveRulesForScope } from "../../utils/preferences-utils.mjs";
2
2
 
3
3
  export default async function findUserPreferencesByPath({ path, scope }) {
4
4
  // Get global rules (always applicable)
@@ -0,0 +1,25 @@
1
+ import { stringify } from "yaml";
2
+
3
+ export default async function formatDocumentStructure({ documentStructure }) {
4
+ // Extract required fields from each item in documentStructure
5
+ const formattedData = documentStructure.map((item) => ({
6
+ title: item.title,
7
+ path: item.path,
8
+ parentId: item.parentId,
9
+ description: item.description,
10
+ }));
11
+
12
+ // Convert to YAML string
13
+ const yamlString = stringify(formattedData, {
14
+ indent: 2,
15
+ lineWidth: 120,
16
+ minContentWidth: 20,
17
+ });
18
+
19
+ return {
20
+ documentStructureYaml: yamlString,
21
+ documentStructure,
22
+ };
23
+ }
24
+
25
+ formatDocumentStructure.task_render_mode = "hide";
@@ -1,12 +1,12 @@
1
- import { access, readFile, stat } from "node:fs/promises";
1
+ import { readFile, stat } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { DEFAULT_EXCLUDE_PATTERNS, DEFAULT_INCLUDE_PATTERNS } from "../utils/constants.mjs";
4
- import { getFilesWithGlob, loadGitignore } from "../utils/file-utils.mjs";
3
+ import { DEFAULT_EXCLUDE_PATTERNS, DEFAULT_INCLUDE_PATTERNS } from "../../utils/constants.mjs";
4
+ import { getFilesWithGlob, loadGitignore } from "../../utils/file-utils.mjs";
5
5
  import {
6
6
  getCurrentGitHead,
7
7
  getModifiedFilesBetweenCommits,
8
8
  isGlobPattern,
9
- } from "../utils/utils.mjs";
9
+ } from "../../utils/utils.mjs";
10
10
 
11
11
  export default async function loadSources({
12
12
  sources = [],
@@ -172,48 +172,61 @@ export default async function loadSources({
172
172
  }),
173
173
  );
174
174
 
175
- // Get the last structure plan result
176
- let originalStructurePlan;
177
- const structurePlanPath = path.join(outputDir, "structure-plan.json");
178
- try {
179
- await access(structurePlanPath);
180
- const structurePlanResult = await readFile(structurePlanPath, "utf8");
181
- if (structurePlanResult) {
182
- try {
183
- originalStructurePlan = JSON.parse(structurePlanResult);
184
- } catch (err) {
185
- console.error(`Failed to parse structure-plan.json: ${err.message}`);
175
+ // Get the last document structure
176
+ let originalDocumentStructure;
177
+ if (outputDir) {
178
+ const documentStructurePath = path.join(outputDir, "structure-plan.json");
179
+ try {
180
+ const documentExecutionStructure = await readFile(documentStructurePath, "utf8");
181
+ if (documentExecutionStructure?.trim()) {
182
+ try {
183
+ // Validate that the content looks like JSON before parsing
184
+ const trimmedContent = documentExecutionStructure.trim();
185
+ if (trimmedContent.startsWith("{") || trimmedContent.startsWith("[")) {
186
+ originalDocumentStructure = JSON.parse(documentExecutionStructure);
187
+ } else {
188
+ console.warn(`structure-plan.json contains non-JSON content, skipping parse`);
189
+ }
190
+ } catch (err) {
191
+ console.error(`Failed to parse structure-plan.json: ${err.message}`);
192
+ }
193
+ }
194
+ } catch (err) {
195
+ if (err.code !== "ENOENT") {
196
+ console.warn(`Error reading structure-plan.json: ${err.message}`);
186
197
  }
198
+ // The file does not exist or is not readable, originalDocumentStructure remains undefined
187
199
  }
188
- } catch {
189
- // The file does not exist, originalStructurePlan remains undefined
190
200
  }
191
201
 
192
202
  // Get the last output result of the specified path
193
203
  let content;
194
- if (docPath && !reset) {
195
- let fileFullName;
196
-
204
+ if (docPath && !reset && docsDir) {
197
205
  // First try direct path matching (original format)
198
206
  const flatName = docPath.replace(/^\//, "").replace(/\//g, "-");
199
- fileFullName = `${flatName}.md`;
207
+ const fileFullName = `${flatName}.md`;
200
208
  let filePath = path.join(docsDir, fileFullName);
201
209
 
202
210
  try {
203
- await access(filePath);
204
211
  content = await readFile(filePath, "utf8");
205
- } catch {
212
+ } catch (err) {
213
+ if (err.code !== "ENOENT") {
214
+ console.warn(`Error reading document file ${filePath}: ${err.message}`);
215
+ }
216
+
206
217
  // If not found and boardId is provided, try boardId-flattenedPath format
207
218
  if (boardId && docPath.startsWith(`${boardId}-`)) {
208
219
  // Extract the flattened path part after boardId-
209
220
  const flattenedPath = docPath.substring(boardId.length + 1);
210
- fileFullName = `${flattenedPath}.md`;
211
- filePath = path.join(docsDir, fileFullName);
221
+ const boardIdFileFullName = `${flattenedPath}.md`;
222
+ filePath = path.join(docsDir, boardIdFileFullName);
212
223
 
213
224
  try {
214
- await access(filePath);
215
225
  content = await readFile(filePath, "utf8");
216
- } catch {
226
+ } catch (boardIdErr) {
227
+ if (boardIdErr.code !== "ENOENT") {
228
+ console.warn(`Error reading document file ${filePath}: ${boardIdErr.message}`);
229
+ }
217
230
  // The file does not exist, content remains undefined
218
231
  }
219
232
  }
@@ -286,7 +299,7 @@ export default async function loadSources({
286
299
  datasourcesList: sourceFiles,
287
300
  datasources: allSources,
288
301
  content,
289
- originalStructurePlan,
302
+ originalDocumentStructure,
290
303
  files,
291
304
  modifiedFiles,
292
305
  totalWords,
@@ -1,17 +1,17 @@
1
1
  import { readdir, unlink, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { shutdownMermaidWorkerPool } from "../utils/mermaid-worker-pool.mjs";
4
- import { getCurrentGitHead, saveGitHeadToConfig } from "../utils/utils.mjs";
3
+ import { shutdownMermaidWorkerPool } from "../../utils/mermaid-worker-pool.mjs";
4
+ import { getCurrentGitHead, saveGitHeadToConfig } from "../../utils/utils.mjs";
5
5
 
6
6
  /**
7
7
  * @param {Object} params
8
- * @param {Array<{path: string, content: string, title: string}>} params.structurePlan
8
+ * @param {Array<{path: string, content: string, title: string}>} params.documentStructure
9
9
  * @param {string} params.docsDir
10
10
  * @param {Array<string>} [params.translateLanguages] - Translation languages
11
11
  * @returns {Promise<Array<{ path: string, success: boolean, error?: string }>>}
12
12
  */
13
13
  export default async function saveDocs({
14
- structurePlanResult: structurePlan,
14
+ documentExecutionStructure: documentStructure,
15
15
  docsDir,
16
16
  translateLanguages = [],
17
17
  locale,
@@ -28,23 +28,23 @@ export default async function saveDocs({
28
28
 
29
29
  // Generate _sidebar.md
30
30
  try {
31
- const sidebar = generateSidebar(structurePlan);
31
+ const sidebar = generateSidebar(documentStructure);
32
32
  const sidebarPath = join(docsDir, "_sidebar.md");
33
33
  await writeFile(sidebarPath, sidebar, "utf8");
34
34
  } catch (err) {
35
35
  console.error("Failed to save _sidebar.md:", err.message);
36
36
  }
37
37
 
38
- // Clean up invalid .md files that are no longer in the structure plan
38
+ // Clean up invalid .md files that are no longer in the document structure
39
39
  try {
40
- await cleanupInvalidFiles(structurePlan, docsDir, translateLanguages, locale);
40
+ await cleanupInvalidFiles(documentStructure, docsDir, translateLanguages, locale);
41
41
  } catch (err) {
42
42
  console.error("Failed to cleanup invalid .md files:", err.message);
43
43
  }
44
44
 
45
45
  const message = `## ✅ Documentation Generated Successfully!
46
46
 
47
- Successfully generated **${structurePlan.length}** documents and saved to:
47
+ Successfully generated **${documentStructure.length}** documents and saved to:
48
48
  \`${docsDir}\`
49
49
  ${projectInfoMessage || ""}
50
50
  ### 🚀 Next Steps
@@ -100,14 +100,14 @@ function generateFileName(flatName, language) {
100
100
  }
101
101
 
102
102
  /**
103
- * Clean up .md files that are no longer in the structure plan
104
- * @param {Array<{path: string, title: string}>} structurePlan
103
+ * Clean up .md files that are no longer in the document structure
104
+ * @param {Array<{path: string, title: string}>} documentStructure
105
105
  * @param {string} docsDir
106
106
  * @param {Array<string>} translateLanguages
107
107
  * @param {string} locale - Main language locale (e.g., 'en', 'zh', 'fr')
108
108
  * @returns {Promise<Array<{ path: string, success: boolean, error?: string }>>}
109
109
  */
110
- async function cleanupInvalidFiles(structurePlan, docsDir, translateLanguages, locale) {
110
+ async function cleanupInvalidFiles(documentStructure, docsDir, translateLanguages, locale) {
111
111
  const results = [];
112
112
 
113
113
  try {
@@ -115,11 +115,11 @@ async function cleanupInvalidFiles(structurePlan, docsDir, translateLanguages, l
115
115
  const files = await readdir(docsDir);
116
116
  const mdFiles = files.filter((file) => file.endsWith(".md"));
117
117
 
118
- // Generate expected file names from structure plan
118
+ // Generate expected file names from document structure
119
119
  const expectedFiles = new Set();
120
120
 
121
121
  // Add main document files
122
- for (const { path } of structurePlan) {
122
+ for (const { path } of documentStructure) {
123
123
  const flatName = path.replace(/^\//, "").replace(/\//g, "-");
124
124
 
125
125
  // Main language file
@@ -166,11 +166,11 @@ async function cleanupInvalidFiles(structurePlan, docsDir, translateLanguages, l
166
166
  return results;
167
167
  }
168
168
 
169
- // Generate sidebar content, support nested structure, and the order is consistent with structurePlan
170
- function generateSidebar(structurePlan) {
169
+ // Generate sidebar content, support nested structure, and the order is consistent with documentStructure
170
+ function generateSidebar(documentStructure) {
171
171
  // Build tree structure
172
172
  const root = {};
173
- for (const { path, title, parentId } of structurePlan) {
173
+ for (const { path, title, parentId } of documentStructure) {
174
174
  const relPath = path.replace(/^\//, "");
175
175
  const segments = relPath.split("/");
176
176
  let node = root;
@@ -1,5 +1,5 @@
1
- import { shutdownMermaidWorkerPool } from "../utils/mermaid-worker-pool.mjs";
2
- import { saveDocWithTranslations } from "../utils/utils.mjs";
1
+ import { shutdownMermaidWorkerPool } from "../../utils/mermaid-worker-pool.mjs";
2
+ import { saveDocWithTranslations } from "../../utils/utils.mjs";
3
3
 
4
4
  export default async function saveSingleDoc({
5
5
  path,
@@ -1,4 +1,4 @@
1
- import { normalizePath, toRelativePath } from "../utils/utils.mjs";
1
+ import { normalizePath, toRelativePath } from "../../utils/utils.mjs";
2
2
 
3
3
  export default function transformDetailDatasources({ sourceIds, datasourcesList }) {
4
4
  // Build a map for fast lookup, with path normalization for compatibility