@aigne/doc-smith 0.2.4 → 0.2.6
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 +14 -0
- package/README.md +1 -0
- package/agents/check-detail-result.mjs +15 -120
- package/agents/check-structure-plan.mjs +56 -7
- package/agents/detail-generator-and-translate.yaml +7 -1
- package/agents/detail-regenerator.yaml +6 -57
- package/agents/docs-generator.yaml +5 -61
- package/agents/find-item-by-path.mjs +63 -14
- package/agents/input-generator.mjs +31 -21
- package/agents/language-selector.mjs +101 -0
- package/agents/load-config.mjs +3 -3
- package/agents/load-sources.mjs +55 -40
- package/agents/publish-docs.mjs +44 -153
- package/agents/retranslate.yaml +74 -0
- package/agents/save-docs.mjs +12 -2
- package/agents/save-output.mjs +9 -3
- package/agents/save-single-doc.mjs +19 -0
- package/agents/structure-planning.yaml +6 -0
- package/agents/team-publish-docs.yaml +7 -7
- package/agents/translate.yaml +3 -0
- package/aigne.yaml +5 -1
- package/docs-mcp/docs-search.yaml +1 -1
- package/docs-mcp/get-docs-detail.mjs +1 -1
- package/docs-mcp/get-docs-structure.mjs +1 -1
- package/docs-mcp/read-doc-content.mjs +1 -1
- package/package.json +16 -7
- package/prompts/check-structure-planning-result.md +4 -7
- package/prompts/content-detail-generator.md +1 -2
- package/prompts/structure-planning.md +7 -2
- package/prompts/translator.md +4 -0
- package/tests/test-all-validation-cases.mjs +707 -0
- package/utils/constants.mjs +3 -2
- package/utils/markdown-checker.mjs +386 -0
- package/utils/mermaid-validator.mjs +158 -0
- package/utils/mermaid-worker-pool.mjs +254 -0
- package/utils/mermaid-worker.mjs +242 -0
- package/utils/utils.mjs +155 -44
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.6](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.2.5...v0.2.6) (2025-08-12)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* release 0.2.6 ([c5b5ea5](https://github.com/AIGNE-io/aigne-doc-smith/commit/c5b5ea5c404d44f3b0d420f0b57e4ae64ae5d624))
|
|
9
|
+
|
|
10
|
+
## [0.2.5](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.2.4...v0.2.5) (2025-08-08)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* polish cli process ([#17](https://github.com/AIGNE-io/aigne-doc-smith/issues/17)) ([4c94263](https://github.com/AIGNE-io/aigne-doc-smith/commit/4c9426378dff9ca3270bd0e455aa6fb1045f6abb))
|
|
16
|
+
|
|
3
17
|
## [0.2.4](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.2.3...v0.2.4) (2025-08-07)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -206,6 +206,7 @@ aigne doc publish --appUrl https://your-discuss-kit-instance.com
|
|
|
206
206
|
npx --no doc-smith run --entry-agent init
|
|
207
207
|
npx --no doc-smith run --entry-agent generate
|
|
208
208
|
npx --no doc-smith run --entry-agent update
|
|
209
|
+
npx --no doc-smith run --entry-agent retranslate
|
|
209
210
|
npx --no doc-smith run --entry-agent publish
|
|
210
211
|
```
|
|
211
212
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
+
import { checkMarkdown } from "../utils/markdown-checker.mjs";
|
|
2
|
+
|
|
1
3
|
export default async function checkDetailResult({
|
|
2
4
|
structurePlan,
|
|
3
5
|
reviewContent,
|
|
4
6
|
}) {
|
|
5
|
-
const linkRegex = /(?<!\!)\[([^\]]+)\]\(([^)]+)\)/g;
|
|
6
|
-
const tableSeparatorRegex = /^\s*\|\s*-+\s*\|\s*$/;
|
|
7
|
-
const codeBlockRegex = /^\s+```(?:\w+)?$/;
|
|
8
|
-
|
|
9
7
|
let isApproved = true;
|
|
10
8
|
const detailFeedback = [];
|
|
11
9
|
|
|
@@ -25,125 +23,22 @@ export default async function checkDetailResult({
|
|
|
25
23
|
allowedLinks.add(flatPath);
|
|
26
24
|
});
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Only check links that processContent would process
|
|
35
|
-
// Exclude external links and mailto
|
|
36
|
-
if (/^(https?:\/\/|mailto:)/.test(trimLink)) continue;
|
|
37
|
-
|
|
38
|
-
// Preserve anchors
|
|
39
|
-
const [path, hash] = trimLink.split("#");
|
|
40
|
-
|
|
41
|
-
// Only process relative paths or paths starting with /
|
|
42
|
-
if (!path) continue;
|
|
43
|
-
|
|
44
|
-
// Check if this link is in the allowed links set
|
|
45
|
-
if (!allowedLinks.has(trimLink)) {
|
|
46
|
-
isApproved = false;
|
|
47
|
-
detailFeedback.push(
|
|
48
|
-
`Found a dead link in ${source}: [${match[1]}](${trimLink}), ensure the link exists in the structure plan path`
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const performAllChecks = (text, source) => {
|
|
55
|
-
// Split text into lines once and perform all checks in a single pass
|
|
56
|
-
const lines = text.split("\n");
|
|
57
|
-
|
|
58
|
-
// State variables for different checks
|
|
59
|
-
let inCodeBlock = false;
|
|
60
|
-
let codeBlockIndentLevel = 0;
|
|
61
|
-
let codeBlockStartLine = 0;
|
|
62
|
-
let inMermaidBlock = false;
|
|
63
|
-
let mermaidStartLine = 0;
|
|
26
|
+
// Run comprehensive markdown validation with all checks
|
|
27
|
+
try {
|
|
28
|
+
const markdownErrors = await checkMarkdown(reviewContent, "result", {
|
|
29
|
+
allowedLinks,
|
|
30
|
+
});
|
|
64
31
|
|
|
65
|
-
|
|
66
|
-
const line = lines[i];
|
|
67
|
-
const lineNumber = i + 1;
|
|
68
|
-
|
|
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
|
|
78
|
-
if (codeBlockRegex.test(line)) {
|
|
79
|
-
if (!inCodeBlock) {
|
|
80
|
-
// Starting a new code block
|
|
81
|
-
inCodeBlock = true;
|
|
82
|
-
codeBlockStartLine = lineNumber;
|
|
83
|
-
// Calculate indentation level of the code block marker
|
|
84
|
-
const match = line.match(/^(\s*)(```)/);
|
|
85
|
-
codeBlockIndentLevel = match ? match[1].length : 0;
|
|
86
|
-
} else {
|
|
87
|
-
// Ending the code block
|
|
88
|
-
inCodeBlock = false;
|
|
89
|
-
codeBlockIndentLevel = 0;
|
|
90
|
-
}
|
|
91
|
-
} else if (inCodeBlock) {
|
|
92
|
-
// If we're inside a code block, check if content has proper indentation
|
|
93
|
-
const contentIndentLevel = line.match(/^(\s*)/)[1].length;
|
|
94
|
-
|
|
95
|
-
// If code block marker has indentation, content should have at least the same indentation
|
|
96
|
-
if (
|
|
97
|
-
codeBlockIndentLevel > 0 &&
|
|
98
|
-
contentIndentLevel < codeBlockIndentLevel
|
|
99
|
-
) {
|
|
100
|
-
isApproved = false;
|
|
101
|
-
detailFeedback.push(
|
|
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`
|
|
103
|
-
);
|
|
104
|
-
// Reset to avoid multiple errors for the same code block
|
|
105
|
-
inCodeBlock = false;
|
|
106
|
-
codeBlockIndentLevel = 0;
|
|
107
|
-
}
|
|
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) {
|
|
32
|
+
if (markdownErrors.length > 0) {
|
|
137
33
|
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
|
-
);
|
|
34
|
+
detailFeedback.push(...markdownErrors);
|
|
141
35
|
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
36
|
+
} catch (error) {
|
|
37
|
+
isApproved = false;
|
|
38
|
+
detailFeedback.push(
|
|
39
|
+
`Found markdown validation error in result: ${error.message}`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
147
42
|
|
|
148
43
|
return {
|
|
149
44
|
isApproved,
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getCurrentGitHead,
|
|
3
3
|
hasFileChangesBetweenCommits,
|
|
4
|
+
loadConfigFromFile,
|
|
5
|
+
saveValueToConfig,
|
|
6
|
+
getProjectInfo,
|
|
4
7
|
} from "../utils/utils.mjs";
|
|
5
8
|
|
|
6
9
|
export default async function checkStructurePlan(
|
|
7
|
-
{ originalStructurePlan, feedback, lastGitHead,
|
|
10
|
+
{ originalStructurePlan, feedback, lastGitHead, ...rest },
|
|
8
11
|
options
|
|
9
12
|
) {
|
|
10
13
|
// Check if we need to regenerate structure plan
|
|
@@ -38,17 +41,13 @@ export default async function checkStructurePlan(
|
|
|
38
41
|
1. 对于新增的内容,可以根据需要新增节点,或补充到原有节点展示
|
|
39
42
|
2. 谨慎删除节点,除非节点关联 sourceIds 都被删除了
|
|
40
43
|
3. 不能修改原有节点的 path
|
|
44
|
+
4. 根据最新的 Data Sources 按需要更新节点的 sourceIds,如没有大的变化,可以不更新。
|
|
41
45
|
`;
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
// If no regeneration needed, return original structure plan
|
|
46
|
-
if (
|
|
47
|
-
originalStructurePlan &&
|
|
48
|
-
!feedback &&
|
|
49
|
-
!shouldRegenerate &&
|
|
50
|
-
!forceRegenerate
|
|
51
|
-
) {
|
|
50
|
+
if (originalStructurePlan && !feedback && !shouldRegenerate) {
|
|
52
51
|
return {
|
|
53
52
|
structurePlan: originalStructurePlan,
|
|
54
53
|
};
|
|
@@ -62,9 +61,59 @@ export default async function checkStructurePlan(
|
|
|
62
61
|
...rest,
|
|
63
62
|
});
|
|
64
63
|
|
|
64
|
+
let message = "";
|
|
65
|
+
|
|
66
|
+
// Check and save project information if user hasn't modified it
|
|
67
|
+
if (result.projectName || result.projectDesc) {
|
|
68
|
+
try {
|
|
69
|
+
const currentConfig = await loadConfigFromFile();
|
|
70
|
+
const projectInfo = await getProjectInfo();
|
|
71
|
+
|
|
72
|
+
// Check if user has modified project information
|
|
73
|
+
const userModifiedProjectName =
|
|
74
|
+
currentConfig?.projectName &&
|
|
75
|
+
currentConfig.projectName !== projectInfo.name;
|
|
76
|
+
const userModifiedProjectDesc =
|
|
77
|
+
currentConfig?.projectDesc &&
|
|
78
|
+
currentConfig.projectDesc !== projectInfo.description;
|
|
79
|
+
|
|
80
|
+
// If user hasn't modified project info and it's not from GitHub, save AI output
|
|
81
|
+
if (!userModifiedProjectName && !userModifiedProjectDesc) {
|
|
82
|
+
let hasUpdated = false;
|
|
83
|
+
// Don't update if the current info is from GitHub (meaningful repository info)
|
|
84
|
+
if (
|
|
85
|
+
result.projectName &&
|
|
86
|
+
result.projectName !== projectInfo.name &&
|
|
87
|
+
!projectInfo.fromGitHub
|
|
88
|
+
) {
|
|
89
|
+
await saveValueToConfig("projectName", result.projectName);
|
|
90
|
+
message += `Project name: \`${result.projectName}\``;
|
|
91
|
+
hasUpdated = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
result.projectDesc &&
|
|
96
|
+
result.projectDesc !== projectInfo.description &&
|
|
97
|
+
!projectInfo.fromGitHub
|
|
98
|
+
) {
|
|
99
|
+
await saveValueToConfig("projectDesc", result.projectDesc);
|
|
100
|
+
message += `\nProject description: \`${result.projectDesc}\``;
|
|
101
|
+
hasUpdated = true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (hasUpdated) {
|
|
105
|
+
message = `\n### Auto-updated Project Info to \`.aigne/doc-smith/config.yaml\`\n\n${message}\n\n`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.warn("Failed to check/save project information:", error.message);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
65
113
|
return {
|
|
66
114
|
...result,
|
|
67
115
|
feedback: "", // clear feedback
|
|
116
|
+
projectInfoMessage: message,
|
|
68
117
|
originalStructurePlan: originalStructurePlan
|
|
69
118
|
? originalStructurePlan
|
|
70
119
|
: JSON.parse(JSON.stringify(result.structurePlan || [])),
|
|
@@ -15,9 +15,15 @@ skills:
|
|
|
15
15
|
reflection:
|
|
16
16
|
reviewer: ./check-detail-result.mjs
|
|
17
17
|
is_approved: isApproved
|
|
18
|
-
max_iterations:
|
|
18
|
+
max_iterations: 5
|
|
19
19
|
return_last_on_max_iterations: true
|
|
20
20
|
task_title: Generate detail for '{{ title }}'
|
|
21
|
+
- type: transform
|
|
22
|
+
jsonata: |
|
|
23
|
+
$merge([
|
|
24
|
+
$,
|
|
25
|
+
{ "feedback": "" }
|
|
26
|
+
])
|
|
21
27
|
- ./batch-translate.yaml
|
|
22
28
|
- ./save-single-doc.mjs
|
|
23
29
|
input_schema:
|
|
@@ -27,24 +27,16 @@ skills:
|
|
|
27
27
|
])
|
|
28
28
|
- ./find-item-by-path.mjs
|
|
29
29
|
- ./format-structure-plan.mjs
|
|
30
|
-
- ./detail-generator-and-translate.yaml
|
|
30
|
+
- url: ./detail-generator-and-translate.yaml
|
|
31
|
+
default_input:
|
|
32
|
+
isShowMessage: true
|
|
31
33
|
input_schema:
|
|
32
34
|
type: object
|
|
33
35
|
properties:
|
|
34
|
-
config:
|
|
35
|
-
type: string
|
|
36
|
-
description: Path to the config file
|
|
37
|
-
default: ./doc-smith/config.yaml
|
|
38
|
-
# nodeName:
|
|
39
|
-
# type: string
|
|
40
|
-
# description: Name of the section to generate documentation for
|
|
41
|
-
# default: Section
|
|
42
|
-
# locale:
|
|
43
|
-
# type: string
|
|
44
|
-
# description: Primary language for documentation (e.g., zh, en)
|
|
45
|
-
# targetAudience:
|
|
36
|
+
# config:
|
|
46
37
|
# type: string
|
|
47
|
-
# description:
|
|
38
|
+
# description: Path to the config file
|
|
39
|
+
# default: ./.aigne/doc-smith/config.yaml
|
|
48
40
|
glossary:
|
|
49
41
|
type: string
|
|
50
42
|
description: Glossary of terms for consistent terminology
|
|
@@ -54,49 +46,6 @@ input_schema:
|
|
|
54
46
|
feedback:
|
|
55
47
|
type: string
|
|
56
48
|
description: Feedback for content improvement
|
|
57
|
-
# sources:
|
|
58
|
-
# type: array
|
|
59
|
-
# items:
|
|
60
|
-
# type: string
|
|
61
|
-
# description: Source code files for documentation generation
|
|
62
|
-
# sourcesPath:
|
|
63
|
-
# type: array
|
|
64
|
-
# description: Source code paths
|
|
65
|
-
# items:
|
|
66
|
-
# type: string
|
|
67
|
-
# default:
|
|
68
|
-
# - ./
|
|
69
|
-
# includePatterns:
|
|
70
|
-
# type: array
|
|
71
|
-
# description: File patterns to include
|
|
72
|
-
# items:
|
|
73
|
-
# type: string
|
|
74
|
-
# excludePatterns:
|
|
75
|
-
# type: array
|
|
76
|
-
# description: File patterns to exclude
|
|
77
|
-
# items:
|
|
78
|
-
# type: string
|
|
79
|
-
# outputDir:
|
|
80
|
-
# type: string
|
|
81
|
-
# description: Output directory for intermediate files
|
|
82
|
-
# default: ./doc-smith/output
|
|
83
|
-
# docsDir:
|
|
84
|
-
# type: string
|
|
85
|
-
# description: Directory to save generated documentation
|
|
86
|
-
# default: ./doc-smith/docs
|
|
87
|
-
# additionalInformation:
|
|
88
|
-
# type: string
|
|
89
|
-
# description: Additional context or information for documentation
|
|
90
|
-
# translateLanguages:
|
|
91
|
-
# type: array
|
|
92
|
-
# items:
|
|
93
|
-
# type: string
|
|
94
|
-
# description: Target languages for translation (e.g., zh, en)
|
|
95
|
-
# labels:
|
|
96
|
-
# type: array
|
|
97
|
-
# items:
|
|
98
|
-
# type: string
|
|
99
|
-
# description: Tags or labels for categorization
|
|
100
49
|
output_schema:
|
|
101
50
|
type: object
|
|
102
51
|
properties:
|
|
@@ -30,7 +30,8 @@ skills:
|
|
|
30
30
|
'translates': [$map(translateLanguages, function($lang) { {"language": $lang} })]
|
|
31
31
|
}
|
|
32
32
|
])
|
|
33
|
-
})
|
|
33
|
+
}),
|
|
34
|
+
"datasources": ""
|
|
34
35
|
}
|
|
35
36
|
])
|
|
36
37
|
- ./format-structure-plan.mjs
|
|
@@ -40,76 +41,19 @@ skills:
|
|
|
40
41
|
input_schema:
|
|
41
42
|
type: object
|
|
42
43
|
properties:
|
|
43
|
-
config:
|
|
44
|
-
type: string
|
|
45
|
-
description: Path to the config file
|
|
46
|
-
default: ./doc-smith/config.yaml
|
|
47
|
-
# nodeName:
|
|
48
|
-
# type: string
|
|
49
|
-
# description: Name of the section to generate documentation for
|
|
50
|
-
# default: Section
|
|
51
|
-
# rules:
|
|
52
|
-
# type: string
|
|
53
|
-
# description: Documentation generation requirements and rules
|
|
54
|
-
# locale:
|
|
55
|
-
# type: string
|
|
56
|
-
# description: Primary language for documentation (e.g., zh, en)
|
|
57
|
-
# sources:
|
|
58
|
-
# type: array
|
|
59
|
-
# items:
|
|
60
|
-
# type: string
|
|
61
|
-
# description: Source code files for documentation generation
|
|
62
|
-
# sourcesPath:
|
|
63
|
-
# type: array
|
|
64
|
-
# description: Source code paths
|
|
65
|
-
# items:
|
|
66
|
-
# type: string
|
|
67
|
-
# default:
|
|
68
|
-
# - ./
|
|
69
|
-
# includePatterns:
|
|
70
|
-
# type: array
|
|
71
|
-
# description: File patterns to include
|
|
72
|
-
# items:
|
|
73
|
-
# type: string
|
|
74
|
-
# excludePatterns:
|
|
75
|
-
# type: array
|
|
76
|
-
# description: File patterns to exclude
|
|
77
|
-
# items:
|
|
78
|
-
# type: string
|
|
79
|
-
# docsDir:
|
|
44
|
+
# config:
|
|
80
45
|
# type: string
|
|
81
|
-
# description:
|
|
82
|
-
# default:
|
|
83
|
-
# outputDir:
|
|
84
|
-
# type: string
|
|
85
|
-
# description: Output directory for intermediate files
|
|
86
|
-
# default: ./doc-smith/output
|
|
87
|
-
# translateLanguages:
|
|
88
|
-
# type: array
|
|
89
|
-
# items:
|
|
90
|
-
# type: string
|
|
91
|
-
# description: Target languages for translation (e.g., zh, en)
|
|
46
|
+
# description: Path to the config file
|
|
47
|
+
# default: ./.aigne/doc-smith/config.yaml
|
|
92
48
|
glossary:
|
|
93
49
|
type: string
|
|
94
50
|
description: Glossary of terms for consistent terminology
|
|
95
|
-
# additionalInformation:
|
|
96
|
-
# type: string
|
|
97
|
-
# description: Additional context or information for documentation
|
|
98
|
-
# docsType:
|
|
99
|
-
# type: string
|
|
100
|
-
# description: Type of documentation (general, getting-started, reference, faq)
|
|
101
|
-
# default: general
|
|
102
51
|
feedback:
|
|
103
52
|
type: string
|
|
104
53
|
description: Feedback for structure planning adjustments
|
|
105
54
|
forceRegenerate:
|
|
106
55
|
type: boolean
|
|
107
56
|
description: Force regenerate all documentation
|
|
108
|
-
# labels:
|
|
109
|
-
# type: array
|
|
110
|
-
# items:
|
|
111
|
-
# type: string
|
|
112
|
-
# description: Tags or labels for categorization
|
|
113
57
|
required:
|
|
114
58
|
- config
|
|
115
59
|
mode: sequential
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
import { readdir } from "node:fs/promises";
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
|
+
// Helper function to get action-specific text based on isTranslate flag
|
|
5
|
+
function getActionText(isTranslate, baseText) {
|
|
6
|
+
const action = isTranslate ? "retranslate" : "update";
|
|
7
|
+
return baseText.replace("{action}", action);
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
export default async function findItemByPath(
|
|
5
|
-
{
|
|
11
|
+
{
|
|
12
|
+
"doc-path": docPath,
|
|
13
|
+
structurePlanResult,
|
|
14
|
+
boardId,
|
|
15
|
+
docsDir,
|
|
16
|
+
isTranslate,
|
|
17
|
+
feedback,
|
|
18
|
+
},
|
|
6
19
|
options
|
|
7
20
|
) {
|
|
8
21
|
let foundItem = null;
|
|
22
|
+
let selectedFileContent = null;
|
|
9
23
|
|
|
10
24
|
// If docPath is empty, let user select from available documents
|
|
11
25
|
if (!docPath) {
|
|
@@ -22,14 +36,12 @@ export default async function findItemByPath(
|
|
|
22
36
|
);
|
|
23
37
|
|
|
24
38
|
if (mainLanguageFiles.length === 0) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
"Please provide a doc-path parameter to specify which document to update"
|
|
27
|
-
);
|
|
39
|
+
throw new Error("No documents found in the docs directory");
|
|
28
40
|
}
|
|
29
41
|
|
|
30
42
|
// Let user select a file
|
|
31
43
|
const selectedFile = await options.prompts.search({
|
|
32
|
-
message: "Select a document to
|
|
44
|
+
message: getActionText(isTranslate, "Select a document to {action}:"),
|
|
33
45
|
source: async (input, { signal }) => {
|
|
34
46
|
if (!input || input.trim() === "") {
|
|
35
47
|
return mainLanguageFiles.map((file) => ({
|
|
@@ -51,9 +63,19 @@ export default async function findItemByPath(
|
|
|
51
63
|
});
|
|
52
64
|
|
|
53
65
|
if (!selectedFile) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
|
|
66
|
+
throw new Error("No document selected");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Read the selected .md file content
|
|
70
|
+
try {
|
|
71
|
+
const selectedFilePath = join(docsDir, selectedFile);
|
|
72
|
+
selectedFileContent = await readFile(selectedFilePath, "utf-8");
|
|
73
|
+
} catch (readError) {
|
|
74
|
+
console.warn(
|
|
75
|
+
`⚠️ Could not read content from ${selectedFile}:`,
|
|
76
|
+
readError.message
|
|
56
77
|
);
|
|
78
|
+
selectedFileContent = null;
|
|
57
79
|
}
|
|
58
80
|
|
|
59
81
|
// Convert filename back to path
|
|
@@ -71,15 +93,17 @@ export default async function findItemByPath(
|
|
|
71
93
|
return itemFlattenedPath === flatName;
|
|
72
94
|
});
|
|
73
95
|
if (!foundItemByFile) {
|
|
74
|
-
throw new Error(
|
|
75
|
-
"Please provide a doc-path parameter to specify which document to update"
|
|
76
|
-
);
|
|
96
|
+
throw new Error("No document found");
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
docPath = foundItemByFile.path;
|
|
80
100
|
} catch (error) {
|
|
101
|
+
console.error(error);
|
|
81
102
|
throw new Error(
|
|
82
|
-
|
|
103
|
+
getActionText(
|
|
104
|
+
isTranslate,
|
|
105
|
+
"Please provide a doc-path parameter to specify which document to {action}"
|
|
106
|
+
)
|
|
83
107
|
);
|
|
84
108
|
}
|
|
85
109
|
}
|
|
@@ -111,8 +135,33 @@ export default async function findItemByPath(
|
|
|
111
135
|
);
|
|
112
136
|
}
|
|
113
137
|
|
|
114
|
-
//
|
|
115
|
-
|
|
138
|
+
// Prompt for feedback if not provided
|
|
139
|
+
let userFeedback = feedback;
|
|
140
|
+
if (!userFeedback) {
|
|
141
|
+
const feedbackMessage = getActionText(
|
|
142
|
+
isTranslate,
|
|
143
|
+
"Please provide feedback for the {action} (press Enter to skip):"
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
userFeedback = await options.prompts.input({
|
|
147
|
+
message: feedbackMessage,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Merge the found item with originalStructurePlan and add content if available
|
|
152
|
+
const result = {
|
|
116
153
|
...foundItem,
|
|
117
154
|
};
|
|
155
|
+
|
|
156
|
+
// Add content if we read it from user selection
|
|
157
|
+
if (selectedFileContent !== null) {
|
|
158
|
+
result.content = selectedFileContent;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Add feedback to result if provided
|
|
162
|
+
if (userFeedback && userFeedback.trim()) {
|
|
163
|
+
result.feedback = userFeedback.trim();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return result;
|
|
118
167
|
}
|