@aigne/doc-smith 0.1.3 → 0.2.0

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.
@@ -0,0 +1,28 @@
1
+ ## Related Issue
2
+
3
+ <!-- Use keywords like fixes, closes, resolves, relates to link the issue. In principle, all PRs should be associated with an issue -->
4
+
5
+ ### Major Changes
6
+
7
+ <!--
8
+ @example:
9
+ 1. Fixed xxx
10
+ 2. Improved xxx
11
+ 3. Adjusted xxx
12
+ -->
13
+
14
+ ### Screenshots
15
+
16
+ <!-- If the changes are related to the UI, whether CLI or WEB, screenshots should be included -->
17
+
18
+ ### Test Plan
19
+
20
+ <!-- If this change is not covered by automated tests, what is your test case collection? Please write it as a to-do list below -->
21
+
22
+ ### Checklist
23
+
24
+ - [ ] This change requires documentation updates, and I have updated the relevant documentation. If the documentation has not been updated, please create a documentation update issue and link it here
25
+ - [ ] The changes are already covered by tests, and I have adjusted the test coverage for the changed parts
26
+ - [ ] The newly added code logic is also covered by tests
27
+ - [ ] This change adds dependencies, and they are placed in dependencies and devDependencies
28
+ - [ ] This change includes adding or updating npm dependencies, and it does not result in multiple versions of the same dependency [check the diff of pnpm-lock.yaml]
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.1.4...v0.2.0) (2025-08-05)
4
+
5
+
6
+ ### Features
7
+
8
+ * support automatic init configuration when calling agents ([24d29db](https://github.com/AIGNE-io/aigne-doc-smith/commit/24d29db4dd86709750aa22ff649e7dacc4124126))
9
+ * update docs when sources changed ([#9](https://github.com/AIGNE-io/aigne-doc-smith/issues/9)) ([4adcecf](https://github.com/AIGNE-io/aigne-doc-smith/commit/4adcecfb32e72c9e88d0b0bd8ce0a91022847ca7))
10
+
11
+ ## [0.1.4](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.1.3...v0.1.4) (2025-08-04)
12
+
13
+
14
+ ### Miscellaneous Chores
15
+
16
+ * release 0.1.4 ([4122cf5](https://github.com/AIGNE-io/aigne-doc-smith/commit/4122cf5cc0285bef2b96803f393e744121d22acf))
17
+
3
18
  ## [0.1.3](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.1.2...v0.1.3) (2025-08-04)
4
19
 
5
20
 
package/README.md CHANGED
@@ -61,13 +61,13 @@ Contributions are welcome! Please feel free to submit a pull request or open an
61
61
  npx --no doc-smith run --entry-agent init
62
62
 
63
63
  # 生成命令
64
- npx --no doc-smith run --entry-agent generator --model gemini:gemini-2.5-flash
64
+ npx --no doc-smith run --entry-agent generate --model gemini:gemini-2.5-flash
65
65
 
66
66
  # 重新生成单篇
67
- npx --no doc-smith run --entry-agent regenerator --input-path bitnet-getting-started
67
+ npx --no doc-smith run --entry-agent update --input-path bitnet-getting-started
68
68
 
69
69
  # 结构规划优化
70
- npx --no doc-smith run --entry-agent generator --input-feedback "补充节点的 sourceIds,确保所有节点 sourceIds 都有值" --model gemini:gemini-2.5-pro
70
+ npx --no doc-smith run --entry-agent generate --input-feedback "补充节点的 sourceIds,确保所有节点 sourceIds 都有值" --model gemini:gemini-2.5-pro
71
71
 
72
72
 
73
73
  # 发布文档
@@ -10,5 +10,9 @@ input_schema:
10
10
  type: string
11
11
  description: 结构规划的上下文,用于辅助结构规划
12
12
  structurePlanResult: ./schema/structure-plan-result.yaml
13
+ modifiedFiles:
14
+ type: array
15
+ items: { type: string }
16
+ description: Array of modified files since last generation
13
17
  iterate_on: structurePlanResult
14
18
  mode: sequential
@@ -3,12 +3,22 @@ import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { TeamAgent } from "@aigne/core";
5
5
  import checkDetailResult from "./check-detail-result.mjs";
6
+ import { hasSourceFilesChanged } from "../utils/utils.mjs";
6
7
 
7
8
  // Get current script directory
8
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
10
 
10
11
  export default async function checkDetailGenerated(
11
- { path, docsDir, sourceIds, originalStructurePlan, structurePlan, ...rest },
12
+ {
13
+ path,
14
+ docsDir,
15
+ sourceIds,
16
+ originalStructurePlan,
17
+ structurePlan,
18
+ modifiedFiles,
19
+ lastGitHead,
20
+ ...rest
21
+ },
12
22
  options
13
23
  ) {
14
24
  // Check if the detail file already exists
@@ -61,6 +71,21 @@ export default async function checkDetailGenerated(
61
71
  }
62
72
  }
63
73
 
74
+ // Check if source files have changed since last generation
75
+ let sourceFilesChanged = false;
76
+ if (sourceIds && sourceIds.length > 0 && modifiedFiles) {
77
+ sourceFilesChanged = hasSourceFilesChanged(sourceIds, modifiedFiles);
78
+
79
+ if (sourceFilesChanged) {
80
+ console.log(`Source files changed for ${path}, will regenerate`);
81
+ }
82
+ }
83
+
84
+ // If lastGitHead is not set, regenerate
85
+ if (!lastGitHead) {
86
+ sourceFilesChanged = true;
87
+ }
88
+
64
89
  // If file exists, check content validation
65
90
  let contentValidationFailed = false;
66
91
  if (detailGenerated && fileContent && structurePlan) {
@@ -74,8 +99,13 @@ export default async function checkDetailGenerated(
74
99
  }
75
100
  }
76
101
 
77
- // If file exists, sourceIds haven't changed, and content validation passes, no need to regenerate
78
- if (detailGenerated && !sourceIdsChanged && !contentValidationFailed) {
102
+ // If file exists, sourceIds haven't changed, source files haven't changed, and content validation passes, no need to regenerate
103
+ if (
104
+ detailGenerated &&
105
+ !sourceIdsChanged &&
106
+ !sourceFilesChanged &&
107
+ !contentValidationFailed
108
+ ) {
79
109
  return {
80
110
  path,
81
111
  docsDir,
@@ -51,49 +51,35 @@ export default async function checkDetailResult({
51
51
  }
52
52
  };
53
53
 
54
- const checkTableSeparators = (text, source) => {
55
- // Split text into lines and check each line
54
+ const performAllChecks = (text, source) => {
55
+ // Split text into lines once and perform all checks in a single pass
56
56
  const lines = text.split("\n");
57
- for (let i = 0; i < lines.length; i++) {
58
- const line = lines[i];
59
- if (tableSeparatorRegex.test(line)) {
60
- isApproved = false;
61
- detailFeedback.push(
62
- `Found an incorrect table separator in ${source} at line ${
63
- i + 1
64
- }: ${line.trim()}`
65
- );
66
- }
67
- }
68
- };
69
57
 
70
- const checkSingleLine = (text, source) => {
71
- // Count newline characters to check if content is only on one line
72
- const newlineCount = (text.match(/\n/g) || []).length;
73
- if (newlineCount === 0 && text.trim().length > 0) {
74
- isApproved = false;
75
- detailFeedback.push(
76
- `Found single line content in ${source}: content appears to be on only one line, check for missing line breaks`
77
- );
78
- }
79
- };
80
-
81
- const checkCodeBlockIndentation = (text, source) => {
82
- // Split text into lines and check each line
83
- const lines = text.split("\n");
58
+ // State variables for different checks
84
59
  let inCodeBlock = false;
85
60
  let codeBlockIndentLevel = 0;
86
61
  let codeBlockStartLine = 0;
62
+ let inMermaidBlock = false;
63
+ let mermaidStartLine = 0;
87
64
 
88
65
  for (let i = 0; i < lines.length; i++) {
89
66
  const line = lines[i];
67
+ const lineNumber = i + 1;
90
68
 
91
- // Check if this line is a code block marker
69
+ // Check table separators
70
+ if (tableSeparatorRegex.test(line)) {
71
+ isApproved = false;
72
+ detailFeedback.push(
73
+ `Found an incorrect table separator in ${source} at line ${lineNumber}: ${line.trim()}`
74
+ );
75
+ }
76
+
77
+ // Check code block markers and indentation
92
78
  if (codeBlockRegex.test(line)) {
93
79
  if (!inCodeBlock) {
94
80
  // Starting a new code block
95
81
  inCodeBlock = true;
96
- codeBlockStartLine = i + 1;
82
+ codeBlockStartLine = lineNumber;
97
83
  // Calculate indentation level of the code block marker
98
84
  const match = line.match(/^(\s*)(```)/);
99
85
  codeBlockIndentLevel = match ? match[1].length : 0;
@@ -102,11 +88,8 @@ export default async function checkDetailResult({
102
88
  inCodeBlock = false;
103
89
  codeBlockIndentLevel = 0;
104
90
  }
105
- continue;
106
- }
107
-
108
- // If we're inside a code block, check if content has proper indentation
109
- if (inCodeBlock) {
91
+ } else if (inCodeBlock) {
92
+ // If we're inside a code block, check if content has proper indentation
110
93
  const contentIndentLevel = line.match(/^(\s*)/)[1].length;
111
94
 
112
95
  // If code block marker has indentation, content should have at least the same indentation
@@ -116,23 +99,51 @@ export default async function checkDetailResult({
116
99
  ) {
117
100
  isApproved = false;
118
101
  detailFeedback.push(
119
- `Found code block with inconsistent indentation in ${source} at line ${codeBlockStartLine}: code block marker has ${codeBlockIndentLevel} spaces indentation but content at line ${
120
- i + 1
121
- } has only ${contentIndentLevel} spaces indentation`
102
+ `Found code block with inconsistent indentation in ${source} at line ${codeBlockStartLine}: code block marker has ${codeBlockIndentLevel} spaces indentation but content at line ${lineNumber} has only ${contentIndentLevel} spaces indentation`
122
103
  );
123
104
  // Reset to avoid multiple errors for the same code block
124
105
  inCodeBlock = false;
125
106
  codeBlockIndentLevel = 0;
126
107
  }
127
108
  }
109
+
110
+ // Check mermaid block markers
111
+ if (/^\s*```mermaid\s*$/.test(line)) {
112
+ inMermaidBlock = true;
113
+ mermaidStartLine = lineNumber;
114
+ } else if (inMermaidBlock && /^\s*```\s*$/.test(line)) {
115
+ inMermaidBlock = false;
116
+ } else if (inMermaidBlock) {
117
+ // If we're inside a mermaid block, check for backticks in node labels
118
+ // Check for node definitions with backticks in labels
119
+ // Pattern: A["label with backticks"] or A{"label with backticks"}
120
+ const nodeLabelRegex =
121
+ /[A-Za-z0-9_]+\["([^"]*`[^"]*)"\]|[A-Za-z0-9_]+{"([^}]*`[^}]*)"}/g;
122
+ let match;
123
+
124
+ while ((match = nodeLabelRegex.exec(line)) !== null) {
125
+ const label = match[1] || match[2];
126
+ isApproved = false;
127
+ detailFeedback.push(
128
+ `Found backticks in Mermaid node label in ${source} at line ${lineNumber}: "${label}" - backticks in node labels cause rendering issues in Mermaid diagrams`
129
+ );
130
+ }
131
+ }
132
+ }
133
+
134
+ // Check single line content (this needs to be done after the loop)
135
+ const newlineCount = (text.match(/\n/g) || []).length;
136
+ if (newlineCount === 0 && text.trim().length > 0) {
137
+ isApproved = false;
138
+ detailFeedback.push(
139
+ `Found single line content in ${source}: content appears to be on only one line, check for missing line breaks`
140
+ );
128
141
  }
129
142
  };
130
143
 
131
144
  // Check content
132
145
  checkLinks(reviewContent, "result");
133
- checkTableSeparators(reviewContent, "result");
134
- checkSingleLine(reviewContent, "result");
135
- checkCodeBlockIndentation(reviewContent, "result");
146
+ performAllChecks(reviewContent, "result");
136
147
 
137
148
  return {
138
149
  isApproved,
@@ -1,15 +1,49 @@
1
- import { dirname } from "node:path";
2
- import { fileURLToPath } from "node:url";
3
-
4
- // Get current script directory
5
- const __dirname = dirname(fileURLToPath(import.meta.url));
1
+ import {
2
+ getCurrentGitHead,
3
+ hasFileChangesBetweenCommits,
4
+ } from "../utils/utils.mjs";
6
5
 
7
6
  export default async function checkStructurePlanning(
8
- { originalStructurePlan, feedback, ...rest },
7
+ { originalStructurePlan, feedback, lastGitHead, ...rest },
9
8
  options
10
9
  ) {
11
- // If originalStructurePlan exists, return directly
12
- if (originalStructurePlan && !feedback) {
10
+ // Check if we need to regenerate structure plan
11
+ let shouldRegenerate = false;
12
+ let finalFeedback = feedback;
13
+
14
+ // If no feedback and originalStructurePlan exists, check for git changes
15
+ if (originalStructurePlan) {
16
+ // If no lastGitHead, regenerate by default
17
+ if (!lastGitHead) {
18
+ shouldRegenerate = true;
19
+ } else {
20
+ // Check if there are relevant file changes since last generation
21
+ const currentGitHead = getCurrentGitHead();
22
+ if (currentGitHead && currentGitHead !== lastGitHead) {
23
+ const hasChanges = hasFileChangesBetweenCommits(
24
+ lastGitHead,
25
+ currentGitHead
26
+ );
27
+ if (hasChanges) {
28
+ shouldRegenerate = true;
29
+ }
30
+ }
31
+ }
32
+
33
+ if (shouldRegenerate) {
34
+ finalFeedback = `
35
+ ${finalFeedback || ""}
36
+
37
+ 根据最新的 DataSources 更新结构规划:
38
+ 1. 对于新增的内容,可以根据需要新增节点,或补充到原有节点展示
39
+ 2. 谨慎删除节点,除非节点关联 sourceIds 都被删除了
40
+ 3. 不能修改原有节点的 path
41
+ `;
42
+ }
43
+ }
44
+
45
+ // If no regeneration needed, return original structure plan
46
+ if (originalStructurePlan && !feedback && !shouldRegenerate) {
13
47
  return {
14
48
  structurePlan: originalStructurePlan,
15
49
  };
@@ -18,7 +52,7 @@ export default async function checkStructurePlanning(
18
52
  const panningAgent = options.context.agents["reflective-structure-planner"];
19
53
 
20
54
  const result = await options.context.invoke(panningAgent, {
21
- feedback: feedback || "",
55
+ feedback: finalFeedback || "",
22
56
  originalStructurePlan,
23
57
  ...rest,
24
58
  });
@@ -4,6 +4,9 @@ alias:
4
4
  - up
5
5
  description: Optimize and regenerate individual document content and translations
6
6
  skills:
7
+ - url: ./input-generator.mjs
8
+ default_input:
9
+ skipIfExists: true
7
10
  - ./load-config.mjs
8
11
  - ./load-sources.mjs
9
12
  - type: transform
@@ -5,6 +5,9 @@ alias:
5
5
  - g
6
6
  description: Automatically generates comprehensive project documentation
7
7
  skills:
8
+ - url: ./input-generator.mjs
9
+ default_input:
10
+ skipIfExists: true
8
11
  - ./load-config.mjs
9
12
  - ./load-sources.mjs
10
13
  - ./check-structure-planning.mjs
@@ -1,6 +1,38 @@
1
- import { writeFile, mkdir } from "node:fs/promises";
1
+ import { writeFile, mkdir, readFile } from "node:fs/promises";
2
2
  import { join, dirname } from "node:path";
3
3
 
4
+ // Predefined document generation styles
5
+ const DOCUMENT_STYLES = {
6
+ actionFirst: {
7
+ name: "Action-First Style",
8
+ rules:
9
+ "Action-first and task-oriented; steps first, copyable examples, minimal context; second person, active voice, short sentences",
10
+ },
11
+ conceptFirst: {
12
+ name: "Concept-First Style",
13
+ rules:
14
+ "Why/What before How; precise and restrained, provide trade-offs and comparisons; support with architecture/flow/sequence diagrams",
15
+ },
16
+ specReference: {
17
+ name: "Spec-Reference Style",
18
+ rules:
19
+ "Objective and precise, no rhetoric; tables/Schema focused, authoritative fields and defaults; clear error codes and multi-language examples",
20
+ },
21
+ custom: {
22
+ name: "Custom Rules",
23
+ rules: "Enter your own documentation generation rules",
24
+ },
25
+ };
26
+
27
+ // Predefined target audiences
28
+ const TARGET_AUDIENCES = {
29
+ actionFirst: "Developers, Implementation Engineers, DevOps",
30
+ conceptFirst:
31
+ "Architects, Technical Leads, Developers interested in principles",
32
+ generalUsers: "General Users",
33
+ custom: "Enter your own target audience",
34
+ };
35
+
4
36
  /**
5
37
  * Guide users through multi-turn dialogue to collect information and generate YAML configuration
6
38
  * @param {Object} params
@@ -9,48 +41,125 @@ import { join, dirname } from "node:path";
9
41
  * @returns {Promise<Object>}
10
42
  */
11
43
  export default async function init(
12
- { outputPath = "./doc-smith", fileName = "config.yaml" },
44
+ { outputPath = "./doc-smith", fileName = "config.yaml", skipIfExists = false },
13
45
  options
14
46
  ) {
15
- console.log("Welcome to AIGNE Doc Smith!");
16
- console.log(
17
- "I will help you generate a configuration file through several questions.\n"
18
- );
47
+ if (skipIfExists) {
48
+ const filePath = join(outputPath, fileName);
49
+ if (await readFile(filePath, "utf8").catch(() => null)) {
50
+ return {}
51
+ }
52
+ }
53
+
54
+ console.log("🚀 Welcome to AIGNE Doc Smith!");
55
+ console.log("Let's create your documentation configuration.\n");
19
56
 
20
57
  // Collect user information
21
58
  const input = {};
22
59
 
23
- // 1. Document generation rules
24
- console.log("=== Document Generation Rules ===");
25
- const rulesInput = await options.prompts.input({
26
- message: "Please describe the document generation rules and requirements:",
60
+ // 1. Document generation rules with style selection
61
+ console.log("📝 Step 1/6: Document Generation Rules");
62
+
63
+ // Let user select a document style
64
+ const styleChoice = await options.prompts.select({
65
+ message: "Choose your documentation style:",
66
+ choices: Object.entries(DOCUMENT_STYLES).map(([key, style]) => ({
67
+ name: `${style.name} - ${style.rules}`,
68
+ value: key,
69
+ })),
27
70
  });
28
- input.rules = rulesInput.trim();
29
71
 
30
- // 2. Target audience
31
- console.log("\n=== Target Audience ===");
32
- const targetAudienceInput = await options.prompts.input({
33
- message:
34
- "What is the target audience? (e.g., developers, users, press Enter for default 'developers'):",
72
+ let rules;
73
+ if (styleChoice === "custom") {
74
+ // User wants to input custom rules
75
+ rules = await options.prompts.input({
76
+ message: "Enter your custom documentation rules:",
77
+ });
78
+ } else {
79
+ // Use predefined style directly
80
+ rules = DOCUMENT_STYLES[styleChoice].rules;
81
+ console.log(`✅ Selected: ${DOCUMENT_STYLES[styleChoice].name}`);
82
+ }
83
+
84
+ input.rules = rules.trim();
85
+
86
+ // 2. Target audience selection
87
+ console.log("\n👥 Step 2/6: Target Audience");
88
+
89
+ // Let user select target audience
90
+ const audienceChoice = await options.prompts.select({
91
+ message: "Who is your target audience?",
92
+ choices: Object.entries(TARGET_AUDIENCES).map(([key, audience]) => ({
93
+ name: audience,
94
+ value: key,
95
+ })),
35
96
  });
36
- input.targetAudience = targetAudienceInput.trim() || "developers";
97
+
98
+ let targetAudience;
99
+ if (audienceChoice === "custom") {
100
+ // User wants to input custom audience
101
+ targetAudience = await options.prompts.input({
102
+ message: "Enter your custom target audience:",
103
+ });
104
+ } else {
105
+ // Use predefined audience directly
106
+ targetAudience = TARGET_AUDIENCES[audienceChoice];
107
+ console.log(`✅ Selected: ${TARGET_AUDIENCES[audienceChoice]}`);
108
+ }
109
+
110
+ input.targetAudience = targetAudience.trim();
37
111
 
38
112
  // 3. Language settings
39
- console.log("\n=== Language Settings ===");
113
+ console.log("\n🌐 Step 3/6: Primary Language");
40
114
  const localeInput = await options.prompts.input({
41
- message: "Primary language (e.g., en, zh, press Enter for default 'en'):",
115
+ message:
116
+ "Primary documentation language (e.g., en, zh, press Enter for 'en'):",
42
117
  });
43
118
  input.locale = localeInput.trim() || "en";
44
119
 
45
120
  // 4. Translation languages
46
- console.log("\n=== Translation Settings ===");
47
- const translateInput = await options.prompts.input({
48
- message:
49
- "Translation language list (comma-separated, e.g., zh,en, press Enter to skip):",
121
+ console.log("\n🔄 Step 4/6: Translation Languages");
122
+ console.log(
123
+ "Enter additional languages for translation (press Enter to skip):"
124
+ );
125
+ const translateLanguages = [];
126
+ while (true) {
127
+ const langInput = await options.prompts.input({
128
+ message: `Language ${translateLanguages.length + 1} (e.g., zh, ja, fr):`,
129
+ });
130
+ if (!langInput.trim()) {
131
+ break;
132
+ }
133
+ translateLanguages.push(langInput.trim());
134
+ }
135
+ input.translateLanguages = translateLanguages;
136
+
137
+ // 5. Documentation directory
138
+ console.log("\n📁 Step 5/6: Output Directory");
139
+ const docsDirInput = await options.prompts.input({
140
+ message: `Where to save generated docs (press Enter for '${outputPath}/docs'):`,
50
141
  });
51
- input.translateLanguages = translateInput.trim()
52
- ? translateInput.split(",").map((lang) => lang.trim())
53
- : [];
142
+ input.docsDir = docsDirInput.trim() || `${outputPath}/docs`;
143
+
144
+ // 6. Source code paths
145
+ console.log("\n🔍 Step 6/6: Source Code Paths");
146
+ console.log(
147
+ "Enter paths to analyze for documentation (press Enter to use './'):"
148
+ );
149
+
150
+ const sourcePaths = [];
151
+ while (true) {
152
+ const pathInput = await options.prompts.input({
153
+ message: `Path ${sourcePaths.length + 1} (e.g., ./src, ./lib):`,
154
+ });
155
+ if (!pathInput.trim()) {
156
+ break;
157
+ }
158
+ sourcePaths.push(pathInput.trim());
159
+ }
160
+
161
+ // If no paths entered, use default
162
+ input.sourcesPath = sourcePaths.length > 0 ? sourcePaths : ["./"];
54
163
 
55
164
  // Generate YAML content
56
165
  const yamlContent = generateYAML(input, outputPath);
@@ -64,12 +173,17 @@ export default async function init(
64
173
  await mkdir(dirPath, { recursive: true });
65
174
 
66
175
  await writeFile(filePath, yamlContent, "utf8");
67
- console.log(`\n Configuration file saved to: ${filePath}`);
176
+ console.log(`\n🎉 Configuration saved to: ${filePath}`);
177
+ console.log(
178
+ "💡 You can edit the configuration file anytime to modify settings."
179
+ );
180
+ console.log(
181
+ "🚀 Run 'aigne doc generate' to start documentation generation!"
182
+ );
68
183
 
69
184
  return {
70
185
  inputGeneratorStatus: true,
71
186
  inputGeneratorPath: filePath,
72
- inputGeneratorContent: yamlContent,
73
187
  };
74
188
  } catch (error) {
75
189
  console.error(`❌ Failed to save configuration file: ${error.message}`);
@@ -121,11 +235,13 @@ function generateYAML(input, outputPath) {
121
235
  yaml += `# - en # Example: English translation\n`;
122
236
  }
123
237
 
124
- // Add default directory and source path configurations
125
- yaml += `docsDir: ${outputPath}/docs # Directory to save generated documentation\n`;
126
- yaml += `outputDir: ${outputPath}/output # Directory to save output files\n`;
238
+ // Add directory and source path configurations
239
+ yaml += `docsDir: ${input.docsDir} # Directory to save generated documentation\n`;
240
+ // yaml += `outputDir: ${outputPath}/output # Directory to save output files\n`;
127
241
  yaml += `sourcesPath: # Source code paths to analyze\n`;
128
- yaml += ` - ./ # Current directory\n`;
242
+ input.sourcesPath.forEach((path) => {
243
+ yaml += ` - ${path}\n`;
244
+ });
129
245
 
130
246
  return yaml;
131
247
  }
@@ -24,6 +24,7 @@ export default async function loadConfig({ config }) {
24
24
  sourcesPath: ["./"],
25
25
  docDir: "./doc-smith/docs",
26
26
  outputDir: "./doc-smith/output",
27
+ lastGitHead: parsedConfig.lastGitHead || "",
27
28
  ...parsedConfig,
28
29
  };
29
30
  } catch (error) {