@aigne/doc-smith 0.9.6-beta → 0.9.6-beta.1

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 (36) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/agents/create/document-structure-tools/delete-document.mjs +32 -9
  3. package/agents/create/update-document-structure.yaml +1 -1
  4. package/agents/create/user-add-document/add-documents-to-structure.mjs +96 -0
  5. package/agents/create/user-add-document/find-documents-to-add-links.yaml +47 -0
  6. package/agents/create/user-add-document/index.yaml +46 -0
  7. package/agents/create/user-add-document/prepare-documents-to-translate.mjs +22 -0
  8. package/agents/create/user-add-document/print-add-document-summary.mjs +56 -0
  9. package/agents/create/user-add-document/review-documents-with-new-links.mjs +73 -0
  10. package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +67 -0
  11. package/agents/create/user-remove-document/index.yaml +41 -0
  12. package/agents/create/user-remove-document/prepare-documents-to-translate.mjs +22 -0
  13. package/agents/create/user-remove-document/print-remove-document-summary.mjs +56 -0
  14. package/agents/create/user-remove-document/remove-documents-from-structure.mjs +96 -0
  15. package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +116 -0
  16. package/agents/create/user-review-document-structure.mjs +1 -40
  17. package/agents/create/utils/init-current-content.mjs +38 -0
  18. package/agents/update/document-tools/update-document-content.mjs +12 -12
  19. package/agents/update/update-document-detail.yaml +5 -1
  20. package/agents/update/update-single/update-single-document-detail.mjs +21 -6
  21. package/agents/update/user-review-document.mjs +10 -13
  22. package/agents/utils/add-translates-to-structure.mjs +29 -0
  23. package/agents/utils/{analyze-feedback-intent.yaml → analyze-document-feedback-intent.yaml} +5 -2
  24. package/agents/utils/analyze-structure-feedback-intent.yaml +29 -0
  25. package/agents/utils/check-detail-result.mjs +2 -14
  26. package/aigne.yaml +10 -1
  27. package/package.json +1 -1
  28. package/prompts/structure/find-documents-to-add-links.md +52 -0
  29. package/prompts/utils/analyze-document-feedback-intent.md +54 -0
  30. package/prompts/utils/analyze-structure-feedback-intent.md +43 -0
  31. package/types/document-schema.mjs +2 -0
  32. package/types/document-structure-schema.mjs +6 -2
  33. package/utils/docs-finder-utils.mjs +82 -0
  34. package/utils/markdown-checker.mjs +50 -5
  35. package/utils/utils.mjs +103 -0
  36. package/prompts/utils/analyze-feedback-intent.md +0 -55
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.6-beta.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.6-beta...v0.9.6-beta.1) (2025-11-19)
4
+
5
+
6
+ ### Features
7
+
8
+ * support for add document and remove document ([#323](https://github.com/AIGNE-io/aigne-doc-smith/issues/323)) ([2672942](https://github.com/AIGNE-io/aigne-doc-smith/commit/26729424ca820eb962e79b4746c069887dd5a649))
9
+
3
10
  ## [0.9.6-beta](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.5...v0.9.6-beta) (2025-11-18)
4
11
 
5
12
 
@@ -16,7 +16,7 @@ export default async function deleteDocument(input, options) {
16
16
  };
17
17
  }
18
18
 
19
- const { path } = validation.data;
19
+ const { path, recursive = false } = validation.data;
20
20
  let documentStructure = options?.context?.userContext?.currentStructure;
21
21
 
22
22
  if (!documentStructure) {
@@ -36,10 +36,27 @@ export default async function deleteDocument(input, options) {
36
36
 
37
37
  const documentToDelete = documentStructure[documentIndex];
38
38
 
39
- // Check if any other documents have this document as parent
40
- const childDocuments = documentStructure.filter((item) => item.parentId === path);
41
- if (childDocuments.length > 0) {
42
- const errorMessage = `Cannot delete document: Document '${path}' has ${childDocuments.length} child document(s): ${childDocuments.map((p) => p.path).join(", ")}. Please first move or delete these child documents.`;
39
+ // Find all child documents (direct and indirect)
40
+ const findAllChildren = (parentPath, structure) => {
41
+ const children = structure.filter((item) => item.parentId === parentPath);
42
+ const allChildren = [...children];
43
+ for (const child of children) {
44
+ allChildren.push(...findAllChildren(child.path, structure));
45
+ }
46
+ return allChildren;
47
+ };
48
+
49
+ const childDocuments = findAllChildren(path, documentStructure);
50
+
51
+ // If recursive is false and there are child documents, return error
52
+ if (!recursive && childDocuments.length > 0) {
53
+ const errorMessage = `Cannot delete document: Document '${path}' has ${
54
+ childDocuments.length
55
+ } child document(s): ${childDocuments
56
+ .map((p) => p.path)
57
+ .join(
58
+ ", ",
59
+ )}. Please first move or delete these child documents, or set recursive=true to delete them all.`;
43
60
  console.log(`⚠️ ${errorMessage}`);
44
61
  return {
45
62
  documentStructure,
@@ -47,11 +64,17 @@ export default async function deleteDocument(input, options) {
47
64
  };
48
65
  }
49
66
 
50
- // Remove the document from the structure
51
- const updatedStructure = documentStructure.filter((_, index) => index !== documentIndex);
67
+ // Collect all documents to delete (children first, then parent)
68
+ const documentsToDelete = recursive ? [...childDocuments, documentToDelete] : [documentToDelete];
69
+ const pathsToDelete = new Set(documentsToDelete.map((doc) => doc.path));
70
+ const deletedCount = pathsToDelete.size - 1;
71
+
72
+ // Remove all documents from the structure
73
+ const updatedStructure = documentStructure.filter((item) => !pathsToDelete.has(item.path));
52
74
 
75
+ // Build success message
53
76
  const successMessage = `deleteDocument executed successfully.
54
- Successfully deleted document '${documentToDelete.title}' with path '${path}'.
77
+ Successfully deleted document '${documentToDelete.title}' with path '${path}'${recursive && deletedCount > 0 ? ` along with ${deletedCount} child document(s)` : ""}.
55
78
  Check if the latest version of documentStructure meets user feedback, if so, just return 'success'.`;
56
79
 
57
80
  // update shared document structure
@@ -62,7 +85,7 @@ export default async function deleteDocument(input, options) {
62
85
  return {
63
86
  documentStructure: updatedStructure,
64
87
  message: successMessage,
65
- deletedDocument: documentToDelete,
88
+ deletedDocuments: documentsToDelete,
66
89
  };
67
90
  }
68
91
 
@@ -2,7 +2,7 @@ type: team
2
2
  name: updateDocumentStructure
3
3
  description: Update documentation structure based on user feedback and intentions using structure modification tools
4
4
  skills:
5
- - url: ../utils/analyze-feedback-intent.yaml
5
+ - url: ../utils/analyze-structure-feedback-intent.yaml
6
6
  - type: ai
7
7
  instructions:
8
8
  - role: system
@@ -0,0 +1,96 @@
1
+ import { getActiveRulesForScope } from "../../../utils/preferences-utils.mjs";
2
+ import { printDocumentStructure } from "../../../utils/docs-finder-utils.mjs";
3
+ import addTranslatesToStructure from "../../utils/add-translates-to-structure.mjs";
4
+
5
+ export default async function addDocumentsToStructure(input = {}, options = {}) {
6
+ const { originalDocumentStructure = [], translateLanguages = [] } = input;
7
+ const analyzeIntent = options.context?.agents?.["analyzeStructureFeedbackIntent"];
8
+ const updateDocumentStructure = options.context?.agents?.["updateDocumentStructure"];
9
+ const allFeedback = [];
10
+ let currentStructure = [...originalDocumentStructure];
11
+ let isFirstAdd = true;
12
+
13
+ printDocumentStructure(originalDocumentStructure);
14
+
15
+ // update website structure
16
+ if (!options.context.userContext) {
17
+ options.context.userContext = {};
18
+ }
19
+
20
+ // Add document
21
+ while (true) {
22
+ let feedback = await options.prompts.input({
23
+ message: isFirstAdd
24
+ ? "You can add a new document.\n" +
25
+ " • e.g. Add a new document 'Troubleshooting'\n\n" +
26
+ "Press Enter to finish:"
27
+ : "You can continue adding documents, or press Enter to finish:",
28
+ });
29
+
30
+ feedback = feedback.trim();
31
+
32
+ // end the loop
33
+ if (!feedback) {
34
+ break;
35
+ }
36
+
37
+ try {
38
+ // validate feedback
39
+ const { intentType } = await options.context.invoke(analyzeIntent, {
40
+ feedback,
41
+ });
42
+
43
+ if (intentType !== "add") {
44
+ console.log(`⚠️ You can only add documents at this stage.`);
45
+ continue;
46
+ }
47
+ options.context.userContext.currentStructure = currentStructure;
48
+
49
+ const structureRules = getActiveRulesForScope("structure", []);
50
+ const globalRules = getActiveRulesForScope("global", []);
51
+ const allApplicableRules = [...structureRules, ...globalRules];
52
+ const userPreferences = allApplicableRules.map((rule) => rule.rule).join("\n\n");
53
+
54
+ await options.context.invoke(updateDocumentStructure, {
55
+ ...input,
56
+ dataSourceChunk: input.dataSources[0].dataSourceChunk,
57
+ feedback,
58
+ documentStructure: currentStructure,
59
+ needDataSources: true,
60
+ userPreferences,
61
+ });
62
+
63
+ allFeedback.push(feedback);
64
+
65
+ currentStructure = options.context.userContext.currentStructure;
66
+ printDocumentStructure(currentStructure);
67
+ isFirstAdd = false;
68
+ } catch (error) {
69
+ console.error("Error processing feedback:", {
70
+ type: error.name,
71
+ message: error.message,
72
+ });
73
+ process.exit(0);
74
+ }
75
+ }
76
+
77
+ if (currentStructure.length > originalDocumentStructure.length) {
78
+ const originalPaths = new Set(originalDocumentStructure.map((doc) => doc.path));
79
+ const { documentExecutionStructure } = addTranslatesToStructure({
80
+ originalDocumentStructure: currentStructure,
81
+ translateLanguages,
82
+ });
83
+ const newDocuments = documentExecutionStructure.filter((doc) => !originalPaths.has(doc.path));
84
+
85
+ return {
86
+ originalDocumentStructure: currentStructure,
87
+ documentStructure: JSON.parse(JSON.stringify(currentStructure)),
88
+ documentExecutionStructure,
89
+ newDocuments,
90
+ allFeedback,
91
+ };
92
+ } else {
93
+ console.log("No documents were added");
94
+ process.exit(0);
95
+ }
96
+ }
@@ -0,0 +1,47 @@
1
+ name: findDocumentsToAddLinks
2
+ description: Use AI to analyze document structure and determine which documents should reference newly added documents
3
+ task_render_mode: hide
4
+ instructions:
5
+ - role: system
6
+ url: ../../../prompts/structure/find-documents-to-add-links.md
7
+ input_schema:
8
+ type: object
9
+ properties:
10
+ originalDocumentStructure:
11
+ type: array
12
+ description: Original document structure before adding documents
13
+ documentStructure:
14
+ type: array
15
+ description: Updated document structure after adding documents
16
+ newDocuments:
17
+ type: array
18
+ description: Array of newly added documents
19
+ required:
20
+ - originalDocumentStructure
21
+ - documentStructure
22
+ - newDocuments
23
+ output_schema:
24
+ type: object
25
+ properties:
26
+ documentsWithNewLinks:
27
+ type: array
28
+ description: Array of existing documents that should add links to new documents
29
+ items:
30
+ type: object
31
+ properties:
32
+ path:
33
+ type: string
34
+ description: The path of the existing document that should be updated
35
+ newLinks:
36
+ type: array
37
+ description: Array of new document paths that should be added as links to this document
38
+ items:
39
+ type: string
40
+ required:
41
+ - path
42
+ - newLinks
43
+ required:
44
+ - documentsWithNewLinks
45
+
46
+
47
+
@@ -0,0 +1,46 @@
1
+ type: team
2
+ name: userAddDocument
3
+ description: Add documents to the documentation structure
4
+ skills:
5
+ - url: ../../init/index.mjs
6
+ default_input:
7
+ skipIfExists: true
8
+ - ../../utils/load-sources.mjs
9
+ - ./add-documents-to-structure.mjs
10
+ - url: ../../utils/save-output.mjs
11
+ default_input:
12
+ saveKey: documentStructure
13
+ savePath:
14
+ $get: outputDir
15
+ fileName: structure-plan.json
16
+ - ../../utils/save-sidebar.mjs
17
+ - ../../utils/ensure-document-icons.mjs
18
+ - ../../utils/format-document-structure.mjs
19
+ - ../../media/load-media-description.mjs
20
+ - type: team
21
+ skills:
22
+ - ../../update/check-document.mjs
23
+ iterate_on: newDocuments
24
+ concurrency: 5
25
+ - ./find-documents-to-add-links.yaml
26
+ - ./review-documents-with-new-links.mjs
27
+ - type: team
28
+ name: batchAddNewLinks
29
+ description: Batch add new links to documents
30
+ skills:
31
+ - ../utils/init-current-content.mjs
32
+ - ../../utils/transform-detail-data-sources.mjs
33
+ - ../../update/update-single/update-single-document-detail.mjs
34
+ iterate_on: documentsToUpdate
35
+ concurrency: 5
36
+ - ./prepare-documents-to-translate.mjs
37
+ - type: team
38
+ name: batchTranslateDocuments
39
+ description: Batch translate documents to multiple languages
40
+ skills:
41
+ - ../../localize/translate-multilingual.yaml
42
+ iterate_on: documentsToTranslate
43
+ concurrency: 5
44
+ - ../../utils/post-generate.mjs
45
+ - ./print-add-document-summary.mjs
46
+ mode: sequential
@@ -0,0 +1,22 @@
1
+ export default async function prepareDocumentsToTranslate(input, options) {
2
+ const { documentsWithNewLinks = [] } = input;
3
+ const documentsToTranslate = [];
4
+
5
+ documentsWithNewLinks.forEach((doc) => {
6
+ const content = options.context.userContext.currentContents[doc.path];
7
+
8
+ if (content) {
9
+ documentsToTranslate.push({
10
+ ...doc,
11
+ content,
12
+ });
13
+ } else {
14
+ console.warn(`⚠️ Could not find content from userContext at path: ${doc.path}`);
15
+ }
16
+ });
17
+
18
+ return {
19
+ documentsToUpdate: [], // clear, reduce token consumption
20
+ documentsToTranslate,
21
+ };
22
+ }
@@ -0,0 +1,56 @@
1
+ import chalk from "chalk";
2
+
3
+ /**
4
+ * Print summary of added documents and documents with new links
5
+ */
6
+ export default async function printAddDocumentSummary({
7
+ newDocuments = [],
8
+ documentsWithNewLinks = [],
9
+ }) {
10
+ let message = `\n${"=".repeat(80)}\n`;
11
+ message += `${chalk.bold.cyan("📊 Summary")}\n`;
12
+ message += `${"=".repeat(80)}\n\n`;
13
+
14
+ // Display added documents
15
+ if (newDocuments && newDocuments.length > 0) {
16
+ message += `✨ Added Documents:\n`;
17
+ message += ` Total: ${newDocuments.length} document(s)\n\n`;
18
+ newDocuments.forEach((doc, index) => {
19
+ message += ` ${chalk.cyan(`${index + 1}. ${doc.path}`)}`;
20
+ if (doc.title && doc.title !== doc.path) {
21
+ message += ` - ${chalk.yellow(doc.title)}`;
22
+ }
23
+ message += `\n\n`;
24
+ });
25
+ } else {
26
+ message += `✨ Added Documents:\n`;
27
+ message += `${chalk.gray(" No documents were added.\n\n")}`;
28
+ }
29
+
30
+ // Display documents with new links
31
+ if (documentsWithNewLinks && documentsWithNewLinks.length > 0) {
32
+ message += `✅ Documents updated (Added new links):\n`;
33
+ message += ` Total: ${documentsWithNewLinks.length} document(s)\n\n`;
34
+ documentsWithNewLinks.forEach((doc, index) => {
35
+ message += ` ${chalk.cyan(`${index + 1}. ${doc.path}`)}`;
36
+ if (doc.title && doc.title !== doc.path) {
37
+ message += ` - ${chalk.yellow(doc.title)}`;
38
+ }
39
+ message += `\n`;
40
+ if (doc.newLinks && doc.newLinks.length > 0) {
41
+ message += ` New links added: ${chalk.gray(doc.newLinks.join(", "))}\n`;
42
+ }
43
+ message += `\n`;
44
+ });
45
+ } else {
46
+ message += `✅ Documents updated (Added new links):\n`;
47
+ message += `${chalk.gray(" No documents needed to be updated.\n\n")}`;
48
+ }
49
+
50
+ message += `${"=".repeat(80)}\n\n`;
51
+
52
+ return { message };
53
+ }
54
+
55
+ printAddDocumentSummary.taskTitle = "Print add document summary";
56
+ printAddDocumentSummary.description = "Display summary of added documents";
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Review documentsWithNewLinks and let user select which documents should be updated
3
+ */
4
+ export default async function reviewDocumentsWithNewLinks(
5
+ { documentsWithNewLinks = [], documentExecutionStructure = [] },
6
+ options,
7
+ ) {
8
+ // If no documents to review, return empty array
9
+ if (!documentsWithNewLinks || documentsWithNewLinks.length === 0) {
10
+ return { documentsWithNewLinks: [] };
11
+ }
12
+
13
+ // Let user select which documents to update (default: all selected)
14
+ const selectedDocs = await options.prompts.checkbox({
15
+ message:
16
+ "Select documents that need new links added (all selected by default, press Enter to confirm, or unselect all to skip):",
17
+ choices: documentsWithNewLinks.map((document, index) => ({
18
+ name: `${document.path} → ${document.newLinks.join(", ")}`,
19
+ value: index,
20
+ checked: true, // Default to all selected
21
+ })),
22
+ });
23
+
24
+ // Filter documentsWithNewLinks based on user selection
25
+ const filteredDocs = selectedDocs.map((index) => documentsWithNewLinks[index]).filter(Boolean);
26
+
27
+ if (filteredDocs.length === 0) {
28
+ console.log(`\n⚠️ No documents selected. Skipping link updates.\n`);
29
+ } else {
30
+ console.log(
31
+ `\n✅ Selected ${filteredDocs.length} out of ${documentsWithNewLinks.length} documents to update.\n`,
32
+ );
33
+ }
34
+
35
+ // save original documentsWithNewLinks to user context
36
+ options.context.userContext.originalDocumentsWithNewLinks = filteredDocs;
37
+
38
+ if (filteredDocs.length === 0) {
39
+ return {
40
+ documentsWithNewLinks: [],
41
+ documentsToUpdate: [],
42
+ };
43
+ }
44
+
45
+ // Prepare documents: add necessary fields for update (without content)
46
+ const preparedDocs = [];
47
+
48
+ for (const doc of filteredDocs) {
49
+ if (!doc.path) continue;
50
+
51
+ // Find corresponding document in documentStructure to get additional fields
52
+ const structureDoc = documentExecutionStructure.find((item) => item.path === doc.path);
53
+
54
+ // Generate feedback message for adding new links
55
+ const newLinksList = doc.newLinks.join(", ");
56
+ const feedback = `Add the following links to this document: ${newLinksList}. Identify suitable places within the existing content — such as relevant sections, navigation items — and insert the links naturally to maintain context and readability.`;
57
+
58
+ preparedDocs.push({
59
+ ...structureDoc,
60
+ feedback,
61
+ newLinks: doc.newLinks,
62
+ });
63
+ }
64
+
65
+ return {
66
+ documentsWithNewLinks: preparedDocs, // for print summary
67
+ documentsToUpdate: JSON.parse(JSON.stringify(preparedDocs)), // for batch update
68
+ };
69
+ }
70
+
71
+ reviewDocumentsWithNewLinks.taskTitle = "Review documents to update";
72
+ reviewDocumentsWithNewLinks.description =
73
+ "Let the user review and select which documents should be updated with new links";
@@ -0,0 +1,67 @@
1
+ import {
2
+ buildAllowedLinksFromStructure,
3
+ generateFileName,
4
+ pathToFlatName,
5
+ readFileContent,
6
+ } from "../../../utils/docs-finder-utils.mjs";
7
+ import { checkMarkdown, getLinkFromError } from "../../../utils/markdown-checker.mjs";
8
+
9
+ export default async function findDocumentsWithInvalidLinks({
10
+ documentStructure = [],
11
+ docsDir,
12
+ locale = "en",
13
+ }) {
14
+ if (!Array.isArray(documentStructure) || documentStructure.length === 0) {
15
+ return {
16
+ documentsWithInvalidLinks: [],
17
+ };
18
+ }
19
+
20
+ if (!docsDir) {
21
+ return {
22
+ documentsWithInvalidLinks: [],
23
+ error: "docsDir is required to check document links",
24
+ };
25
+ }
26
+
27
+ // Check each document for invalid links
28
+ const allowedLinks = buildAllowedLinksFromStructure(documentStructure);
29
+ const documentsWithInvalidLinks = [];
30
+
31
+ for (const doc of documentStructure) {
32
+ if (!doc.path) continue;
33
+
34
+ // Generate filename from document path
35
+ const flatName = pathToFlatName(doc.path);
36
+ const fileName = generateFileName(flatName, locale);
37
+
38
+ // Read document content
39
+ const content = await readFileContent(docsDir, fileName);
40
+
41
+ if (!content) {
42
+ // Skip if content cannot be read
43
+ continue;
44
+ }
45
+
46
+ // Use checkMarkdown to check for dead links
47
+ const allErrors = await checkMarkdown(content, doc.path, {
48
+ allowedLinks,
49
+ baseDir: docsDir,
50
+ });
51
+
52
+ // Filter only dead link errors and extract invalid links
53
+ const invalidLinks = allErrors.map(getLinkFromError).filter(Boolean);
54
+
55
+ if (invalidLinks.length > 0) {
56
+ documentsWithInvalidLinks.push({
57
+ path: doc.path,
58
+ title: doc.title || doc.path,
59
+ invalidLinks,
60
+ });
61
+ }
62
+ }
63
+
64
+ return {
65
+ documentsWithInvalidLinks,
66
+ };
67
+ }
@@ -0,0 +1,41 @@
1
+ type: team
2
+ name: userRemoveDocument
3
+ description: Remove documents from the documentation structure
4
+ skills:
5
+ - url: ../../init/index.mjs
6
+ default_input:
7
+ skipIfExists: true
8
+ - ../../utils/load-sources.mjs
9
+ - ./remove-documents-from-structure.mjs
10
+ - url: ../../utils/save-output.mjs
11
+ default_input:
12
+ saveKey: documentStructure
13
+ savePath:
14
+ $get: outputDir
15
+ fileName: structure-plan.json
16
+ - ../../utils/save-sidebar.mjs
17
+ - ./find-documents-with-invalid-links.mjs
18
+ - ../../utils/add-translates-to-structure.mjs
19
+ - ./review-documents-with-invalid-links.mjs
20
+ - ../../utils/format-document-structure.mjs
21
+ - ../../media/load-media-description.mjs
22
+ - type: team
23
+ name: batchRemoveInvalidLinks
24
+ description: Batch remove invalid links from documents
25
+ skills:
26
+ - ../utils/init-current-content.mjs
27
+ - ../../utils/transform-detail-data-sources.mjs
28
+ - ../../update/update-single/update-single-document-detail.mjs
29
+ iterate_on: documentsToUpdate
30
+ concurrency: 5
31
+ - ./prepare-documents-to-translate.mjs
32
+ - type: team
33
+ name: batchTranslateDocuments
34
+ description: Batch translate documents to multiple languages
35
+ skills:
36
+ - ../../localize/translate-multilingual.yaml
37
+ iterate_on: documentsToTranslate
38
+ concurrency: 5
39
+ - ../../utils/post-generate.mjs
40
+ - ./print-remove-document-summary.mjs
41
+ mode: sequential
@@ -0,0 +1,22 @@
1
+ export default async function prepareDocumentsToTranslate(input, options) {
2
+ const { documentsWithInvalidLinks = [] } = input;
3
+ const documentsToTranslate = [];
4
+
5
+ documentsWithInvalidLinks.forEach((doc) => {
6
+ const content = options.context.userContext.currentContents[doc.path];
7
+
8
+ if (content) {
9
+ documentsToTranslate.push({
10
+ ...doc,
11
+ content,
12
+ });
13
+ } else {
14
+ console.warn(`⚠️ Could not find content from userContext at path: ${doc.path}`);
15
+ }
16
+ });
17
+
18
+ return {
19
+ documentsToUpdate: [], // clear, reduce token consumption
20
+ documentsToTranslate,
21
+ };
22
+ }
@@ -0,0 +1,56 @@
1
+ import chalk from "chalk";
2
+
3
+ /**
4
+ * Print summary of removed documents and documents with invalid links
5
+ */
6
+ export default async function printRemoveDocumentSummary({
7
+ deletedDocuments = [],
8
+ documentsWithInvalidLinks = [],
9
+ }) {
10
+ let message = `\n${"=".repeat(80)}\n`;
11
+ message += `${chalk.bold.cyan("📊 Summary")}\n`;
12
+ message += `${"=".repeat(80)}\n\n`;
13
+
14
+ // Display removed documents
15
+ if (deletedDocuments && deletedDocuments.length > 0) {
16
+ message += `🗑️ Removed Documents:\n`;
17
+ message += ` Total: ${deletedDocuments.length} document(s)\n\n`;
18
+ deletedDocuments.forEach((doc, index) => {
19
+ message += ` ${chalk.cyan(`${index + 1}. ${doc.path}`)}`;
20
+ if (doc.title && doc.title !== doc.path) {
21
+ message += ` - ${chalk.yellow(doc.title)}`;
22
+ }
23
+ message += `\n\n`;
24
+ });
25
+ } else {
26
+ message += `🗑️ Removed Documents:\n`;
27
+ message += `${chalk.gray(" No documents were removed.\n\n")}`;
28
+ }
29
+
30
+ // Display documents with invalid links
31
+ if (documentsWithInvalidLinks && documentsWithInvalidLinks.length > 0) {
32
+ message += `✅ Documents fixed (Removed invalid links):\n`;
33
+ message += ` Total: ${documentsWithInvalidLinks.length} document(s)\n\n`;
34
+ documentsWithInvalidLinks.forEach((doc, index) => {
35
+ message += ` ${chalk.cyan(`${index + 1}. ${doc.path}`)}`;
36
+ if (doc.title && doc.title !== doc.path) {
37
+ message += ` - ${chalk.yellow(doc.title)}`;
38
+ }
39
+ message += `\n`;
40
+ if (doc.invalidLinks && doc.invalidLinks.length > 0) {
41
+ message += ` Invalid links fixed: ${chalk.gray(doc.invalidLinks.join(", "))}\n`;
42
+ }
43
+ message += `\n`;
44
+ });
45
+ } else {
46
+ message += `✅ Documents fixed (Removed invalid links):\n`;
47
+ message += `${chalk.gray(" No documents needed to be fixed.\n\n")}`;
48
+ }
49
+
50
+ message += `${"=".repeat(80)}\n\n`;
51
+
52
+ return { message };
53
+ }
54
+
55
+ printRemoveDocumentSummary.taskTitle = "Print remove document summary";
56
+ printRemoveDocumentSummary.description = "Display summary of removed documents";