@aigne/doc-smith 0.9.3-beta.1 → 0.9.3-beta.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.3-beta.2](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.3-beta.1...v0.9.3-beta.2) (2025-11-13)
4
+
5
+
6
+ ### Features
7
+
8
+ * allow manual triggering of the publish docs process ([#306](https://github.com/AIGNE-io/aigne-doc-smith/issues/306)) ([9a76a49](https://github.com/AIGNE-io/aigne-doc-smith/commit/9a76a491c1511397b32b60db62142896637dfed2))
9
+ * move ensure document icons to sub-agent ([#305](https://github.com/AIGNE-io/aigne-doc-smith/issues/305)) ([f139070](https://github.com/AIGNE-io/aigne-doc-smith/commit/f1390706cda9348de094c9f5e592a4c34a1b1389))
10
+
3
11
  ## [0.9.3-beta.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.3-beta...v0.9.3-beta.1) (2025-11-13)
4
12
 
5
13
 
@@ -4,7 +4,6 @@ import {
4
4
  validateAddDocumentInput,
5
5
  } from "../../../types/document-structure-schema.mjs";
6
6
  import streamlineDocumentTitlesIfNeeded from "../../utils/streamline-document-titles-if-needed.mjs";
7
- import generateDocumentIconIfNeeded from "../../utils/generate-document-icon-if-needed.mjs";
8
7
 
9
8
  export default async function addDocument(input, options) {
10
9
  // Validate input using Zod schema
@@ -61,12 +60,9 @@ export default async function addDocument(input, options) {
61
60
  // Streamline document titles if needed (will streamline the new document if title > 18 characters)
62
61
  await streamlineDocumentTitlesIfNeeded({ documentStructure: [newDocument] }, options);
63
62
 
64
- // Add the document to the structure first
63
+ // Add the document to the structure
65
64
  const updatedStructure = [...documentStructure, newDocument];
66
65
 
67
- // Generate icon for root-level documents if needed
68
- await generateDocumentIconIfNeeded({ documentStructure: updatedStructure }, options);
69
-
70
66
  const successMessage = `addDocument executed successfully.
71
67
  Successfully added document '${title}' with path '${path}'.
72
68
  Check if the latest version of documentStructure meets user feedback, if so, just return 'success'.`;
@@ -4,7 +4,6 @@ import {
4
4
  validateUpdateDocumentInput,
5
5
  } from "../../../types/document-structure-schema.mjs";
6
6
  import streamlineDocumentTitlesIfNeeded from "../../utils/streamline-document-titles-if-needed.mjs";
7
- import generateDocumentIconIfNeeded from "../../utils/generate-document-icon-if-needed.mjs";
8
7
 
9
8
  export default async function updateDocument(input, options) {
10
9
  // Validate input using Zod schema
@@ -56,16 +55,6 @@ export default async function updateDocument(input, options) {
56
55
  const updatedStructure = [...documentStructure];
57
56
  updatedStructure[documentIndex] = updatedDocument;
58
57
 
59
- // Generate/update icon for root-level documents if needed
60
- // Pass original document for comparison to detect title/description changes
61
- await generateDocumentIconIfNeeded(
62
- {
63
- documentStructure: updatedStructure,
64
- originalItems: [originalDocument],
65
- },
66
- options,
67
- );
68
-
69
58
  const updates = [];
70
59
  if (title !== undefined) updates.push(`title to '${title}'`);
71
60
  if (description !== undefined) updates.push("description");
@@ -24,6 +24,7 @@ skills:
24
24
  $get: outputDir
25
25
  fileName: structure-plan.json
26
26
  - ../utils/save-sidebar.mjs
27
+ - ../utils/ensure-document-icons.mjs
27
28
  - type: transform
28
29
  name: transformData
29
30
  task_render_mode: hide
@@ -11,6 +11,7 @@ skills:
11
11
  checkOnly: true
12
12
  - url: ../init/check.mjs
13
13
  - url: ../utils/load-sources.mjs
14
+ - ../utils/ensure-document-icons.mjs
14
15
  - translate-meta.mjs
15
16
  - publish-docs.mjs
16
17
  input_schema:
@@ -31,6 +31,7 @@ skills:
31
31
  default_input:
32
32
  requiredFeedback: false
33
33
  - ../utils/format-document-structure.mjs
34
+ - ../utils/ensure-document-icons.mjs
34
35
  - ../media/load-media-description.mjs
35
36
  - ../update/check-update-is-single.mjs
36
37
  - ../update/save-and-translate-document.mjs
@@ -0,0 +1,129 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { loadConfigFromFile, processConfigFields } from "../../utils/utils.mjs";
4
+
5
+ /**
6
+ * Ensure all root-level document entries have icons
7
+ * Batch processing: Collects all entries without icons and generates them in a single call
8
+ * Conditionally saves the updated structure if icons were generated
9
+ * This is a reusable agent that can be used in structure planning and before publishing
10
+ */
11
+ export default async function ensureDocumentIcons(inputOrParams, options) {
12
+ // Handle multiple calling patterns:
13
+ // 1. As function skill: (input, options) where input.documentStructure exists
14
+ // 2. As function skill: (input, options) where input.originalDocumentStructure exists
15
+ // 3. As standalone function: ({ documentStructure }, options)
16
+ const documentStructure =
17
+ inputOrParams?.documentStructure ||
18
+ inputOrParams?.originalDocumentStructure ||
19
+ (Array.isArray(inputOrParams) ? inputOrParams : null);
20
+
21
+ if (!documentStructure || !Array.isArray(documentStructure)) {
22
+ // Return input unchanged if no documentStructure to process
23
+ return inputOrParams || {};
24
+ }
25
+
26
+ // Batch collect all root-level items that need icon generation
27
+ // Only process root-level items (parentId is null, undefined, or empty string)
28
+ // Only generate icons for items that don't have one
29
+ const itemsNeedingIcon = documentStructure.filter((item) => {
30
+ // Only process root-level items
31
+ const isRootLevel = !item.parentId || item.parentId === "null" || item.parentId === "";
32
+ if (!isRootLevel) return false;
33
+
34
+ // Must have title and description for icon generation
35
+ if (!item.title || !item.description) return false;
36
+
37
+ // Only generate if icon is missing
38
+ const hasNoIcon = !item.icon || !item.icon.trim();
39
+ return hasNoIcon;
40
+ });
41
+
42
+ // If all items already have icons, skip
43
+ if (itemsNeedingIcon.length === 0) {
44
+ return inputOrParams || {};
45
+ }
46
+
47
+ // Prepare batch list for icon generation
48
+ const documentList = itemsNeedingIcon.map((item) => ({
49
+ path: item.path,
50
+ title: item.title,
51
+ description: item.description,
52
+ }));
53
+
54
+ const iconAgent = options?.context?.agents?.["documentIconGenerate"];
55
+ if (!iconAgent) {
56
+ console.warn("⚠️ documentIconGenerate agent not found. Skipping icon generation.");
57
+ return inputOrParams || {};
58
+ }
59
+
60
+ let iconsGenerated = false;
61
+
62
+ try {
63
+ // Batch generate all missing icons in a single call
64
+ const iconResult = await options.context.invoke(iconAgent, {
65
+ documentList,
66
+ });
67
+
68
+ // Batch update all document items with generated icons using path as the key
69
+ if (iconResult.documentList && Array.isArray(iconResult.documentList)) {
70
+ const iconMap = new Map(iconResult.documentList.map((item) => [item.path, item.icon]));
71
+
72
+ for (const item of documentStructure) {
73
+ const generatedIcon = iconMap.get(item.path);
74
+ if (generatedIcon) {
75
+ item.icon = generatedIcon;
76
+ iconsGenerated = true;
77
+ }
78
+ }
79
+ }
80
+
81
+ // Conditionally save the updated structure if icons were generated
82
+ // Use the same save pattern as save-output.mjs for consistency
83
+ if (iconsGenerated) {
84
+ // Try to get outputDir from multiple sources (same as create flow)
85
+ let outputDir =
86
+ inputOrParams?.outputDir ||
87
+ options?.context?.userContext?.outputDir ||
88
+ options?.context?.config?.outputDir;
89
+
90
+ // If still not found, load from config file and process defaults
91
+ if (!outputDir) {
92
+ try {
93
+ const config = await loadConfigFromFile();
94
+ const processedConfig = await processConfigFields(config || {});
95
+ outputDir = processedConfig?.outputDir;
96
+ } catch {
97
+ // Ignore config load errors
98
+ }
99
+ }
100
+
101
+ if (outputDir) {
102
+ try {
103
+ // Use the same save pattern as save-output.mjs
104
+ const savePath = outputDir;
105
+ const fileName = "structure-plan.json";
106
+ const content = JSON.stringify(documentStructure, null, 2);
107
+
108
+ await fs.mkdir(savePath, { recursive: true });
109
+ const filePath = join(savePath, fileName);
110
+ await fs.writeFile(filePath, content, "utf8");
111
+ } catch (saveError) {
112
+ console.warn("⚠️ Failed to save updated structure:", saveError.message);
113
+ // Continue even if save fails
114
+ }
115
+ }
116
+ }
117
+ } catch (error) {
118
+ console.warn("⚠️ Failed to generate document icons:", error.message);
119
+ console.warn("Continuing without icons.");
120
+ }
121
+
122
+ // Return input unchanged (documentStructure is modified in place)
123
+ return inputOrParams || {};
124
+ }
125
+
126
+ ensureDocumentIcons.taskTitle = "Ensure document icons";
127
+ ensureDocumentIcons.description =
128
+ "Check each root-level document entry for icons - if missing, generate one; if present, skip";
129
+ ensureDocumentIcons.task_render_mode = "hide";
package/aigne.yaml CHANGED
@@ -83,7 +83,6 @@ agents:
83
83
  - ./agents/utils/document-title-streamline.yaml
84
84
  - ./agents/utils/streamline-document-titles-if-needed.mjs
85
85
  - ./agents/utils/document-icon-generate.yaml
86
- - ./agents/utils/generate-document-icon-if-needed.mjs
87
86
 
88
87
  # User Preferences & Chat
89
88
  - ./agents/prefs/index.mjs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/doc-smith",
3
- "version": "0.9.3-beta.1",
3
+ "version": "0.9.3-beta.2",
4
4
  "description": "AI-driven documentation generation tool built on the AIGNE Framework",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -28,12 +28,6 @@ Structural planning rules:
28
28
 
29
29
  2. Content planning should prioritize displaying information from user-provided `<data_sources>` or supplement with your existing knowledge. Do not arbitrarily fabricate information.
30
30
 
31
- 3. **Document Icon Generation:**
32
- - For root-level nodes (where `parentPath` is null or empty), add an `icon` attribute
33
- - Format: `lucide:icon-name` (only Lucide icons supported)
34
- - Choose icons that semantically match the document's purpose based on title and description
35
- - Common icons: `lucide:book` (documentation), `lucide:rocket` (quick start), `lucide:code` (API), `lucide:settings` (configuration), `lucide:graduation-cap` (tutorials), `lucide:folder-open` (overview), `lucide:users` (user guides), `lucide:shield` (security), `lucide:cloud` (deployment)
36
-
37
31
  {% ifAsync docsType == 'general' %}
38
32
  {% include "../../structure/document-rules.md" %}
39
33
  {% endif %}
@@ -1,93 +0,0 @@
1
- /**
2
- * Generate icons for root-level document structure items if they don't have one or if title/description changed
3
- * Reusable function for generating document icons in various contexts
4
- * Can be called as a standalone function with { documentStructure, originalItems? } or as a function skill with (input, options)
5
- * @param {Object|Array} inputOrParams - Either input from previous step (with documentStructure) or params object with documentStructure and optional originalItems
6
- * @param {Object} options - Agent options with context
7
- * @param {Array<{path: string, title?: string, description?: string}>} [inputOrParams.originalItems] - Original items for comparison (optional, used to detect title/description changes)
8
- * @returns {Promise<Object>} - Returns input unchanged (modifies documentStructure in place)
9
- */
10
- export default async function generateDocumentIconIfNeeded(inputOrParams, options) {
11
- // Handle both calling patterns:
12
- // 1. As function skill: (input, options) where input.documentStructure exists
13
- // 2. As standalone function: ({ documentStructure, originalItems? }, options)
14
- const documentStructure =
15
- inputOrParams?.documentStructure || (Array.isArray(inputOrParams) ? inputOrParams : null);
16
- const originalItems = inputOrParams?.originalItems || [];
17
-
18
- if (!documentStructure || !Array.isArray(documentStructure)) {
19
- // Return input unchanged if no documentStructure to process
20
- return inputOrParams || {};
21
- }
22
-
23
- // Create a map of original items by path for quick lookup
24
- const originalItemsMap = new Map(
25
- originalItems.map((item) => [item.path, { title: item.title, description: item.description }]),
26
- );
27
-
28
- // Filter root-level items that need icon generation or update
29
- const itemsNeedingIcon = documentStructure.filter((item) => {
30
- // Only process root-level items (parentId is null, undefined, or empty string)
31
- const isRootLevel = !item.parentId || item.parentId === "null" || item.parentId === "";
32
- if (!isRootLevel) return false;
33
-
34
- // Must have title and description for icon generation
35
- if (!item.title || !item.description) return false;
36
-
37
- // Check if icon is missing
38
- const hasNoIcon = !item.icon;
39
-
40
- // Check if title or description changed (if original item exists)
41
- const originalItem = originalItemsMap.get(item.path);
42
- const titleChanged = originalItem && originalItem.title !== item.title;
43
- const descriptionChanged = originalItem && originalItem.description !== item.description;
44
- const contentChanged = titleChanged || descriptionChanged;
45
-
46
- // Generate/update icon if: missing icon OR content changed
47
- return hasNoIcon || contentChanged;
48
- });
49
-
50
- if (itemsNeedingIcon.length === 0) {
51
- return;
52
- }
53
-
54
- const documentList = itemsNeedingIcon.map((item) => ({
55
- path: item.path,
56
- title: item.title,
57
- description: item.description,
58
- }));
59
-
60
- const iconAgent = options?.context?.agents?.["documentIconGenerate"];
61
- if (!iconAgent) {
62
- console.warn("⚠️ documentIconGenerate agent not found. Skipping icon generation.");
63
- return;
64
- }
65
-
66
- try {
67
- const iconResult = await options.context.invoke(iconAgent, {
68
- documentList,
69
- });
70
-
71
- // Update the document items with generated icons using path as the key
72
- if (iconResult.documentList && Array.isArray(iconResult.documentList)) {
73
- const iconMap = new Map(iconResult.documentList.map((item) => [item.path, item]));
74
-
75
- for (const item of documentStructure) {
76
- const iconData = iconMap.get(item.path);
77
- if (iconData?.icon) {
78
- item.icon = iconData.icon;
79
- }
80
- }
81
- }
82
- } catch (error) {
83
- console.warn("⚠️ Failed to generate document icons:", error.message);
84
- console.warn("Continuing without icons.");
85
- }
86
-
87
- // Return input unchanged (documentStructure is modified in place)
88
- return inputOrParams || {};
89
- }
90
-
91
- generateDocumentIconIfNeeded.taskTitle = "Generate document icons if needed";
92
- generateDocumentIconIfNeeded.description =
93
- "Generate appropriate Lucide icons for root-level document structure items based on their title and description, or update icon if title/description changed";