@aigne/doc-smith 0.9.6 → 0.9.7-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.
- package/CHANGELOG.md +16 -0
- package/agents/clear/clear-generated-docs.mjs +2 -2
- package/agents/create/index.yaml +0 -17
- package/agents/create/merge-diagram.yaml +1 -2
- package/agents/create/user-add-document/add-documents-to-structure.mjs +2 -8
- package/agents/create/user-add-document/review-documents-with-new-links.mjs +3 -3
- package/agents/create/user-remove-document/index.yaml +0 -1
- package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +5 -9
- package/agents/init/check.mjs +2 -2
- package/agents/init/index.mjs +12 -3
- package/agents/localize/choose-language.mjs +4 -7
- package/agents/localize/index.yaml +1 -9
- package/agents/update/batch-generate-document.yaml +10 -2
- package/agents/update/check-document.mjs +4 -3
- package/agents/update/check-generate-diagram.mjs +5 -2
- package/agents/update/index.yaml +1 -9
- package/agents/update/save-and-translate-document.mjs +0 -1
- package/agents/update/update-single/update-single-document-detail.mjs +11 -4
- package/agents/utils/choose-docs.mjs +7 -19
- package/agents/utils/find-item-by-path.mjs +5 -15
- package/agents/utils/post-generate.mjs +1 -1
- package/aigne.yaml +0 -1
- package/package.json +11 -9
- package/prompts/common/document/markdown-syntax-rules.md +65 -0
- package/prompts/detail/custom/admonition-usage-rules.md +94 -0
- package/prompts/detail/custom/custom-components/x-card-usage-rules.md +1 -1
- package/prompts/detail/custom/custom-components/x-field-desc-usage-rules.md +34 -0
- package/prompts/detail/custom/custom-components/x-field-group-usage-rules.md +0 -15
- package/prompts/detail/custom/custom-components/x-field-usage-rules.md +1 -1
- package/prompts/detail/generate/document-rules.md +2 -7
- package/prompts/detail/generate/system-prompt.md +2 -0
- package/prompts/detail/update/system-prompt.md +2 -0
- package/prompts/translate/admonition.md +20 -0
- package/prompts/translate/translate-document.md +2 -0
- package/utils/constants/index.mjs +8 -21
- package/utils/d2-utils.mjs +40 -1
- package/utils/docs-finder-utils.mjs +19 -25
- package/utils/file-utils.mjs +1 -1
- package/agents/schema/document-execution-structure.yaml +0 -32
- package/agents/utils/add-translates-to-structure.mjs +0 -29
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.7-beta.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.7-beta...v0.9.7-beta.1) (2025-11-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **ci:** ensure pipeline fails on test failures ([#328](https://github.com/AIGNE-io/aigne-doc-smith/issues/328)) ([56fb4d5](https://github.com/AIGNE-io/aigne-doc-smith/commit/56fb4d5259a21a6cf76f67c6ac5a43a7c1403b99))
|
|
9
|
+
* supports admonition syntax ([#338](https://github.com/AIGNE-io/aigne-doc-smith/issues/338)) ([db19661](https://github.com/AIGNE-io/aigne-doc-smith/commit/db19661e1c2d654181d932e0834e7e011a3ad8a5))
|
|
10
|
+
|
|
11
|
+
## [0.9.7-beta](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.6...v0.9.7-beta) (2025-11-25)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* documentExecutionStructure might be an object ([#332](https://github.com/AIGNE-io/aigne-doc-smith/issues/332)) ([337b350](https://github.com/AIGNE-io/aigne-doc-smith/commit/337b350d5fa045edb7b2db84f0892151aa8518ab))
|
|
17
|
+
* update default exclusion patterns, keeping only the necessary items ([#334](https://github.com/AIGNE-io/aigne-doc-smith/issues/334)) ([f1431cf](https://github.com/AIGNE-io/aigne-doc-smith/commit/f1431cf3d600c77c05c8e346712f79aa689ffe27))
|
|
18
|
+
|
|
3
19
|
## [0.9.6](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.6-beta.2...v0.9.6) (2025-11-21)
|
|
4
20
|
|
|
5
21
|
## [0.9.6-beta.2](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.9.6-beta.1...v0.9.6-beta.2) (2025-11-20)
|
|
@@ -29,12 +29,12 @@ export default async function clearGeneratedDocs(input = {}, options = {}) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const
|
|
32
|
+
const documentStructure = (await loadDocumentStructure(outputDir)) || [];
|
|
33
33
|
// select documents interactively
|
|
34
34
|
const chooseResult = await chooseDocs(
|
|
35
35
|
{
|
|
36
36
|
docs: [], // Empty to trigger interactive selection
|
|
37
|
-
|
|
37
|
+
documentStructure,
|
|
38
38
|
docsDir: generatedDocsPath,
|
|
39
39
|
locale: locale || "en",
|
|
40
40
|
isTranslate: false,
|
package/agents/create/index.yaml
CHANGED
|
@@ -25,23 +25,6 @@ skills:
|
|
|
25
25
|
fileName: structure-plan.json
|
|
26
26
|
- ../utils/save-sidebar.mjs
|
|
27
27
|
- ../utils/ensure-document-icons.mjs
|
|
28
|
-
- type: transform
|
|
29
|
-
name: transformData
|
|
30
|
-
task_render_mode: hide
|
|
31
|
-
jsonata: |
|
|
32
|
-
$merge([
|
|
33
|
-
$,
|
|
34
|
-
{
|
|
35
|
-
'documentExecutionStructure': $map(documentStructure, function($item) {
|
|
36
|
-
$merge([
|
|
37
|
-
$item,
|
|
38
|
-
{
|
|
39
|
-
'translates': [$map(translateLanguages, function($lang) { {"language": $lang} })]
|
|
40
|
-
}
|
|
41
|
-
])
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
])
|
|
45
28
|
- ../utils/format-document-structure.mjs
|
|
46
29
|
- ../media/load-media-description.mjs
|
|
47
30
|
- ../update/batch-generate-document.yaml
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { getActiveRulesForScope } from "../../../utils/preferences-utils.mjs";
|
|
2
2
|
import { printDocumentStructure } from "../../../utils/docs-finder-utils.mjs";
|
|
3
|
-
import addTranslatesToStructure from "../../utils/add-translates-to-structure.mjs";
|
|
4
3
|
|
|
5
4
|
export default async function addDocumentsToStructure(input = {}, options = {}) {
|
|
6
|
-
const { originalDocumentStructure = []
|
|
5
|
+
const { originalDocumentStructure = [] } = input;
|
|
7
6
|
const analyzeIntent = options.context?.agents?.["analyzeStructureFeedbackIntent"];
|
|
8
7
|
const updateDocumentStructure = options.context?.agents?.["updateDocumentStructure"];
|
|
9
8
|
const allFeedback = [];
|
|
@@ -76,16 +75,11 @@ export default async function addDocumentsToStructure(input = {}, options = {})
|
|
|
76
75
|
|
|
77
76
|
if (currentStructure.length > originalDocumentStructure.length) {
|
|
78
77
|
const originalPaths = new Set(originalDocumentStructure.map((doc) => doc.path));
|
|
79
|
-
const
|
|
80
|
-
originalDocumentStructure: currentStructure,
|
|
81
|
-
translateLanguages,
|
|
82
|
-
});
|
|
83
|
-
const newDocuments = documentExecutionStructure.filter((doc) => !originalPaths.has(doc.path));
|
|
78
|
+
const newDocuments = currentStructure.filter((doc) => !originalPaths.has(doc.path));
|
|
84
79
|
|
|
85
80
|
return {
|
|
86
81
|
originalDocumentStructure: currentStructure,
|
|
87
82
|
documentStructure: JSON.parse(JSON.stringify(currentStructure)),
|
|
88
|
-
documentExecutionStructure,
|
|
89
83
|
newDocuments,
|
|
90
84
|
allFeedback,
|
|
91
85
|
};
|
|
@@ -8,7 +8,7 @@ import { pathExists } from "../../../utils/file-utils.mjs";
|
|
|
8
8
|
* Review documentsWithNewLinks and let user select which documents should be updated
|
|
9
9
|
*/
|
|
10
10
|
export default async function reviewDocumentsWithNewLinks(
|
|
11
|
-
{ documentsWithNewLinks = [],
|
|
11
|
+
{ documentsWithNewLinks = [], documentStructure = [], locale = "en", docsDir },
|
|
12
12
|
options,
|
|
13
13
|
) {
|
|
14
14
|
// If no documents to review, return empty array
|
|
@@ -22,7 +22,7 @@ export default async function reviewDocumentsWithNewLinks(
|
|
|
22
22
|
documentsWithNewLinks.map((document, index) =>
|
|
23
23
|
limit(async () => {
|
|
24
24
|
// Find corresponding document in documentStructure to get title
|
|
25
|
-
const structureDoc =
|
|
25
|
+
const structureDoc = documentStructure.find((item) => item.path === document.path);
|
|
26
26
|
const title = structureDoc?.title || document.path;
|
|
27
27
|
|
|
28
28
|
// Generate filename from document path
|
|
@@ -86,7 +86,7 @@ export default async function reviewDocumentsWithNewLinks(
|
|
|
86
86
|
if (!doc.path) continue;
|
|
87
87
|
|
|
88
88
|
// Find corresponding document in documentStructure to get additional fields
|
|
89
|
-
const structureDoc =
|
|
89
|
+
const structureDoc = documentStructure.find((item) => item.path === doc.path);
|
|
90
90
|
|
|
91
91
|
// Generate feedback message for adding new links
|
|
92
92
|
const newLinksList = doc.newLinks.join(", ");
|
|
@@ -15,7 +15,6 @@ skills:
|
|
|
15
15
|
fileName: structure-plan.json
|
|
16
16
|
- ../../utils/save-sidebar.mjs
|
|
17
17
|
- ./find-documents-with-invalid-links.mjs
|
|
18
|
-
- ../../utils/add-translates-to-structure.mjs
|
|
19
18
|
- ./review-documents-with-invalid-links.mjs
|
|
20
19
|
- ../../utils/format-document-structure.mjs
|
|
21
20
|
- ../../media/load-media-description.mjs
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
/**
|
|
8
8
|
* Generate feedback message for fixing invalid links in a document
|
|
9
9
|
*/
|
|
10
|
-
function generateInvalidLinksFeedback(invalidLinks, documentPath,
|
|
10
|
+
function generateInvalidLinksFeedback(invalidLinks, documentPath, documentStructure) {
|
|
11
11
|
const invalidLinksList = invalidLinks.map((link) => `- ${link}`).join("\n");
|
|
12
12
|
|
|
13
13
|
// Build allowed links from document structure for replacement suggestions
|
|
14
|
-
const allowedLinks = buildAllowedLinksFromStructure(
|
|
14
|
+
const allowedLinks = buildAllowedLinksFromStructure(documentStructure);
|
|
15
15
|
const allowedLinksArray = Array.from(allowedLinks)
|
|
16
16
|
.filter((link) => link !== documentPath) // Exclude current document path
|
|
17
17
|
.sort();
|
|
@@ -48,7 +48,7 @@ ${allowedLinksList}
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export default async function reviewDocumentsWithInvalidLinks(input = {}, options = {}) {
|
|
51
|
-
const { documentsWithInvalidLinks = [],
|
|
51
|
+
const { documentsWithInvalidLinks = [], documentStructure = [], locale = "en" } = input;
|
|
52
52
|
|
|
53
53
|
// If no documents with invalid links, return empty array
|
|
54
54
|
if (!Array.isArray(documentsWithInvalidLinks) || documentsWithInvalidLinks.length === 0) {
|
|
@@ -96,14 +96,10 @@ export default async function reviewDocumentsWithInvalidLinks(input = {}, option
|
|
|
96
96
|
if (!doc.path) continue;
|
|
97
97
|
|
|
98
98
|
// Find corresponding document in documentStructure to get additional fields
|
|
99
|
-
const structureDoc =
|
|
99
|
+
const structureDoc = documentStructure.find((item) => item.path === doc.path);
|
|
100
100
|
|
|
101
101
|
// Generate feedback message for fixing invalid links
|
|
102
|
-
const feedback = generateInvalidLinksFeedback(
|
|
103
|
-
doc.invalidLinks,
|
|
104
|
-
doc.path,
|
|
105
|
-
documentExecutionStructure,
|
|
106
|
-
);
|
|
102
|
+
const feedback = generateInvalidLinksFeedback(doc.invalidLinks, doc.path, documentStructure);
|
|
107
103
|
|
|
108
104
|
preparedDocs.push({
|
|
109
105
|
...structureDoc,
|
package/agents/init/check.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { getMainLanguageFiles } from "../../utils/docs-finder-utils.mjs";
|
|
3
3
|
|
|
4
|
-
export default async function checkNeedGenerate({ docsDir, locale,
|
|
5
|
-
const mainLanguageFiles = await getMainLanguageFiles(docsDir, locale,
|
|
4
|
+
export default async function checkNeedGenerate({ docsDir, locale, documentStructure }) {
|
|
5
|
+
const mainLanguageFiles = await getMainLanguageFiles(docsDir, locale, documentStructure);
|
|
6
6
|
|
|
7
7
|
if (mainLanguageFiles.length === 0) {
|
|
8
8
|
console.log(
|
package/agents/init/index.mjs
CHANGED
|
@@ -48,7 +48,14 @@ export default async function init(input, options) {
|
|
|
48
48
|
options,
|
|
49
49
|
)?.reasoningEffort;
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
// for translation agent
|
|
52
|
+
if (config.translateLanguages) {
|
|
53
|
+
config.translates = config.translateLanguages.map((lang) => ({ language: lang }));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
...config,
|
|
58
|
+
};
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
async function _init(
|
|
@@ -284,7 +291,9 @@ async function _init(
|
|
|
284
291
|
` 1. Use paths like ${chalk.green("./src")}, ${chalk.green("./README.md")} or ${chalk.green("!./src/private")}.`,
|
|
285
292
|
);
|
|
286
293
|
console.log(
|
|
287
|
-
` 2. Use globs like ${chalk.green("src/**/*.js")} or ${chalk.green(
|
|
294
|
+
` 2. Use globs like ${chalk.green("src/**/*.js")} or ${chalk.green(
|
|
295
|
+
"!private/**/*.js",
|
|
296
|
+
)} for more specific file matching.`,
|
|
288
297
|
);
|
|
289
298
|
console.log(` 3. Use URLs like ${chalk.green("https://example.com/openapi.yaml")}.`);
|
|
290
299
|
console.log("💡 If you leave this empty, we will scan the entire directory.");
|
|
@@ -601,7 +610,7 @@ ${modelSection}
|
|
|
601
610
|
|
|
602
611
|
// Directory and source path configurations - safely serialize
|
|
603
612
|
const docsDirSection = yamlStringify({ docsDir: config.docsDir }).trim();
|
|
604
|
-
yaml += `${docsDirSection
|
|
613
|
+
yaml += `${docsDirSection} # The directory where the generated documentation will be saved.\n`;
|
|
605
614
|
|
|
606
615
|
const sourcesPathSection = yamlStringify({ sourcesPath: config.sourcesPath }).trim();
|
|
607
616
|
yaml += `${sourcesPathSection.replace(/^sourcesPath:/, "sourcesPath: # The source code paths to analyze.")}\n`;
|
|
@@ -76,16 +76,13 @@ export default async function chooseLanguage({ langs, locale, selectedDocs }, op
|
|
|
76
76
|
await saveValueToConfig("translateLanguages", updatedTranslateLanguages);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
...doc,
|
|
82
|
-
translates: selectedLanguages.map((lang) => ({ language: lang })),
|
|
83
|
-
};
|
|
84
|
-
});
|
|
79
|
+
// Convert selectedLanguages to translates format
|
|
80
|
+
const translates = selectedLanguages.map((lang) => ({ language: lang }));
|
|
85
81
|
|
|
86
82
|
return {
|
|
87
83
|
selectedLanguages,
|
|
88
|
-
selectedDocs
|
|
84
|
+
selectedDocs,
|
|
85
|
+
translates,
|
|
89
86
|
};
|
|
90
87
|
}
|
|
91
88
|
|
|
@@ -16,15 +16,7 @@ skills:
|
|
|
16
16
|
$merge([
|
|
17
17
|
$,
|
|
18
18
|
{
|
|
19
|
-
'documentStructure': originalDocumentStructure
|
|
20
|
-
'documentExecutionStructure': $map(originalDocumentStructure, function($item) {
|
|
21
|
-
$merge([
|
|
22
|
-
$item,
|
|
23
|
-
{
|
|
24
|
-
'translates': [$map(translateLanguages, function($lang) { {"language": $lang} })]
|
|
25
|
-
}
|
|
26
|
-
])
|
|
27
|
-
})
|
|
19
|
+
'documentStructure': originalDocumentStructure
|
|
28
20
|
}
|
|
29
21
|
])
|
|
30
22
|
- url: ../utils/choose-docs.mjs
|
|
@@ -9,11 +9,19 @@ input_schema:
|
|
|
9
9
|
detailDataSource:
|
|
10
10
|
type: string
|
|
11
11
|
description: Context for documentation structure generation, used to assist generate documentation structure
|
|
12
|
-
|
|
12
|
+
documentStructure: ../schema/document-structure.yaml
|
|
13
|
+
translates:
|
|
14
|
+
type: array
|
|
15
|
+
items:
|
|
16
|
+
type: object
|
|
17
|
+
properties:
|
|
18
|
+
language:
|
|
19
|
+
type: string
|
|
20
|
+
description: List of languages to translate documents to
|
|
13
21
|
modifiedFiles:
|
|
14
22
|
type: array
|
|
15
23
|
items: { type: string }
|
|
16
24
|
description: Array of modified files since last generation
|
|
17
|
-
iterate_on:
|
|
25
|
+
iterate_on: documentStructure
|
|
18
26
|
concurrency: 5
|
|
19
27
|
mode: sequential
|
|
@@ -21,7 +21,7 @@ export default async function checkDocument(
|
|
|
21
21
|
modifiedFiles,
|
|
22
22
|
forceRegenerate,
|
|
23
23
|
locale,
|
|
24
|
-
translates,
|
|
24
|
+
translates = [],
|
|
25
25
|
...rest
|
|
26
26
|
},
|
|
27
27
|
options,
|
|
@@ -87,7 +87,8 @@ export default async function checkDocument(
|
|
|
87
87
|
contentValidationFailed = true;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
const
|
|
90
|
+
const translateList = Array.isArray(translates) ? translates : [];
|
|
91
|
+
const languages = translateList.map((x) => x.language);
|
|
91
92
|
const lackLanguages = new Set(languages);
|
|
92
93
|
const skills = [];
|
|
93
94
|
|
|
@@ -140,7 +141,7 @@ export default async function checkDocument(
|
|
|
140
141
|
|
|
141
142
|
const result = await options.context.invoke(teamAgent, {
|
|
142
143
|
...rest,
|
|
143
|
-
translates:
|
|
144
|
+
translates: translateList.filter((x) => lackLanguages.has(x.language)),
|
|
144
145
|
locale,
|
|
145
146
|
docsDir,
|
|
146
147
|
path,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DIAGRAM_PLACEHOLDER } from "../../utils/d2-utils.mjs";
|
|
1
|
+
import { DIAGRAM_PLACEHOLDER, replacePlaceholderWithD2 } from "../../utils/d2-utils.mjs";
|
|
2
2
|
|
|
3
3
|
const DEFAULT_DIAGRAMMING_EFFORT = 5;
|
|
4
4
|
const MIN_DIAGRAMMING_EFFORT = 0;
|
|
@@ -68,7 +68,10 @@ export default async function checkGenerateDiagram(
|
|
|
68
68
|
|
|
69
69
|
if (diagramSourceCode && !skipGenerateDiagram) {
|
|
70
70
|
if (content.includes(DIAGRAM_PLACEHOLDER)) {
|
|
71
|
-
content =
|
|
71
|
+
content = replacePlaceholderWithD2({
|
|
72
|
+
content,
|
|
73
|
+
diagramSourceCode,
|
|
74
|
+
});
|
|
72
75
|
} else {
|
|
73
76
|
const mergeAgent = options.context?.agents?.["mergeDiagramToDocument"];
|
|
74
77
|
({ content } = await options.context.invoke(mergeAgent, {
|
package/agents/update/index.yaml
CHANGED
|
@@ -16,15 +16,7 @@ skills:
|
|
|
16
16
|
$merge([
|
|
17
17
|
$,
|
|
18
18
|
{
|
|
19
|
-
'documentStructure': originalDocumentStructure
|
|
20
|
-
'documentExecutionStructure': $map(originalDocumentStructure, function($item) {
|
|
21
|
-
$merge([
|
|
22
|
-
$item,
|
|
23
|
-
{
|
|
24
|
-
'translates': [$map(translateLanguages, function($lang) { {"language": $lang} })]
|
|
25
|
-
}
|
|
26
|
-
])
|
|
27
|
-
})
|
|
19
|
+
'documentStructure': originalDocumentStructure
|
|
28
20
|
}
|
|
29
21
|
])
|
|
30
22
|
- url: ../utils/choose-docs.mjs
|
|
@@ -61,7 +61,6 @@ export default async function saveAndTranslateDocument(input, options) {
|
|
|
61
61
|
await options.context.invoke(translateAgent, {
|
|
62
62
|
...input, // context is required
|
|
63
63
|
content: doc.content,
|
|
64
|
-
translates: doc.translates,
|
|
65
64
|
title: doc.title,
|
|
66
65
|
path: doc.path,
|
|
67
66
|
docsDir,
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { AIAgent } from "@aigne/core";
|
|
2
2
|
import { pick } from "@aigne/core/utils/type-utils.js";
|
|
3
3
|
import z from "zod";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
DIAGRAM_PLACEHOLDER,
|
|
6
|
+
replaceD2WithPlaceholder,
|
|
7
|
+
replacePlaceholderWithD2,
|
|
8
|
+
} from "../../../utils/d2-utils.mjs";
|
|
5
9
|
import { userContextAt } from "../../../utils/utils.mjs";
|
|
6
10
|
|
|
7
11
|
async function getIntentType(input, options) {
|
|
@@ -64,7 +68,7 @@ async function addDiagram(input, options) {
|
|
|
64
68
|
async function updateDiagram(input, options) {
|
|
65
69
|
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
66
70
|
const currentContent = contentContext.get();
|
|
67
|
-
let [content, previousDiagramContent] =
|
|
71
|
+
let [content, previousDiagramContent] = replaceD2WithPlaceholder({
|
|
68
72
|
content: currentContent,
|
|
69
73
|
});
|
|
70
74
|
const generateAgent = options.context?.agents?.["generateDiagram"];
|
|
@@ -74,7 +78,10 @@ async function updateDiagram(input, options) {
|
|
|
74
78
|
previousDiagramContent,
|
|
75
79
|
feedback: input.feedback,
|
|
76
80
|
});
|
|
77
|
-
content =
|
|
81
|
+
content = replacePlaceholderWithD2({
|
|
82
|
+
content,
|
|
83
|
+
diagramSourceCode,
|
|
84
|
+
});
|
|
78
85
|
contentContext.set(content);
|
|
79
86
|
await saveDoc(input, options, { content });
|
|
80
87
|
return { content };
|
|
@@ -83,7 +90,7 @@ async function updateDiagram(input, options) {
|
|
|
83
90
|
async function deleteDiagram(input, options) {
|
|
84
91
|
const contentContext = userContextAt(options, `currentContents.${input.path}`);
|
|
85
92
|
const currentContent = contentContext.get();
|
|
86
|
-
const [documentContent] =
|
|
93
|
+
const [documentContent] = replaceD2WithPlaceholder({
|
|
87
94
|
content: currentContent,
|
|
88
95
|
});
|
|
89
96
|
const instructions = `<role>
|
|
@@ -18,7 +18,7 @@ function getFeedbackMessage(action) {
|
|
|
18
18
|
export default async function chooseDocs(
|
|
19
19
|
{
|
|
20
20
|
docs,
|
|
21
|
-
|
|
21
|
+
documentStructure,
|
|
22
22
|
boardId,
|
|
23
23
|
docsDir,
|
|
24
24
|
isTranslate,
|
|
@@ -38,11 +38,7 @@ export default async function chooseDocs(
|
|
|
38
38
|
if (!docs || docs.length === 0) {
|
|
39
39
|
try {
|
|
40
40
|
// Get all main language .md files in docsDir
|
|
41
|
-
const mainLanguageFiles = await getMainLanguageFiles(
|
|
42
|
-
docsDir,
|
|
43
|
-
locale,
|
|
44
|
-
documentExecutionStructure,
|
|
45
|
-
);
|
|
41
|
+
const mainLanguageFiles = await getMainLanguageFiles(docsDir, locale, documentStructure);
|
|
46
42
|
|
|
47
43
|
if (mainLanguageFiles.length === 0) {
|
|
48
44
|
throw new Error(
|
|
@@ -56,7 +52,7 @@ export default async function chooseDocs(
|
|
|
56
52
|
const choices = mainLanguageFiles.map((file) => {
|
|
57
53
|
// Convert filename to flat path to find corresponding documentation structure item
|
|
58
54
|
const flatName = file.replace(/\.md$/, "").replace(/\.\w+(-\w+)?$/, "");
|
|
59
|
-
const docItem =
|
|
55
|
+
const docItem = documentStructure.find((item) => {
|
|
60
56
|
const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
|
|
61
57
|
return itemFlattenedPath === flatName;
|
|
62
58
|
});
|
|
@@ -96,7 +92,7 @@ export default async function chooseDocs(
|
|
|
96
92
|
}
|
|
97
93
|
|
|
98
94
|
// Process selected files and convert to found items
|
|
99
|
-
foundItems = await processSelectedFiles(selectedFiles,
|
|
95
|
+
foundItems = await processSelectedFiles(selectedFiles, documentStructure, docsDir);
|
|
100
96
|
} catch (error) {
|
|
101
97
|
console.log(
|
|
102
98
|
getActionText(`\nFailed to select documents to {action}: ${error.message}`, docAction),
|
|
@@ -106,16 +102,10 @@ export default async function chooseDocs(
|
|
|
106
102
|
} else {
|
|
107
103
|
// Process the provided docs array
|
|
108
104
|
for (const docPath of docs) {
|
|
109
|
-
const foundItem = await findItemByPath(
|
|
110
|
-
documentExecutionStructure,
|
|
111
|
-
docPath,
|
|
112
|
-
boardId,
|
|
113
|
-
docsDir,
|
|
114
|
-
locale,
|
|
115
|
-
);
|
|
105
|
+
const foundItem = await findItemByPath(documentStructure, docPath, boardId, docsDir, locale);
|
|
116
106
|
|
|
117
107
|
if (!foundItem) {
|
|
118
|
-
console.warn(`⚠️ Item with path "${docPath}" not found in
|
|
108
|
+
console.warn(`⚠️ Item with path "${docPath}" not found in documentStructure`);
|
|
119
109
|
continue;
|
|
120
110
|
}
|
|
121
111
|
|
|
@@ -125,9 +115,7 @@ export default async function chooseDocs(
|
|
|
125
115
|
}
|
|
126
116
|
|
|
127
117
|
if (foundItems.length === 0) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
"None of the specified document paths were found in documentExecutionStructure",
|
|
130
|
-
);
|
|
118
|
+
throw new Error("None of the specified document paths were found in documentStructure");
|
|
131
119
|
}
|
|
132
120
|
}
|
|
133
121
|
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "../../utils/docs-finder-utils.mjs";
|
|
10
10
|
|
|
11
11
|
export default async function findItemByPath(
|
|
12
|
-
{ doc,
|
|
12
|
+
{ doc, documentStructure, boardId, docsDir, isTranslate, feedback, locale },
|
|
13
13
|
options,
|
|
14
14
|
) {
|
|
15
15
|
let foundItem = null;
|
|
@@ -21,11 +21,7 @@ export default async function findItemByPath(
|
|
|
21
21
|
if (!docPath) {
|
|
22
22
|
try {
|
|
23
23
|
// Get all main language .md files in docsDir
|
|
24
|
-
const mainLanguageFiles = await getMainLanguageFiles(
|
|
25
|
-
docsDir,
|
|
26
|
-
locale,
|
|
27
|
-
documentExecutionStructure,
|
|
28
|
-
);
|
|
24
|
+
const mainLanguageFiles = await getMainLanguageFiles(docsDir, locale, documentStructure);
|
|
29
25
|
|
|
30
26
|
if (mainLanguageFiles.length === 0) {
|
|
31
27
|
throw new Error("No documents found in the docs directory");
|
|
@@ -65,7 +61,7 @@ export default async function findItemByPath(
|
|
|
65
61
|
const flatName = fileNameToFlatPath(selectedFile);
|
|
66
62
|
|
|
67
63
|
// Try to find matching item by comparing flattened paths
|
|
68
|
-
const foundItemByFile = findItemByFlatName(
|
|
64
|
+
const foundItemByFile = findItemByFlatName(documentStructure, flatName);
|
|
69
65
|
|
|
70
66
|
if (!foundItemByFile) {
|
|
71
67
|
throw new Error("No document found");
|
|
@@ -84,16 +80,10 @@ export default async function findItemByPath(
|
|
|
84
80
|
}
|
|
85
81
|
|
|
86
82
|
// Use the utility function to find item and read content
|
|
87
|
-
foundItem = await findItemByPathUtil(
|
|
88
|
-
documentExecutionStructure,
|
|
89
|
-
docPath,
|
|
90
|
-
boardId,
|
|
91
|
-
docsDir,
|
|
92
|
-
locale,
|
|
93
|
-
);
|
|
83
|
+
foundItem = await findItemByPathUtil(documentStructure, docPath, boardId, docsDir, locale);
|
|
94
84
|
|
|
95
85
|
if (!foundItem) {
|
|
96
|
-
throw new Error(`Item with path "${docPath}" not found in
|
|
86
|
+
throw new Error(`Item with path "${docPath}" not found in documentStructure`);
|
|
97
87
|
}
|
|
98
88
|
|
|
99
89
|
// Prompt for feedback if not provided
|
|
@@ -11,7 +11,7 @@ import { getCurrentGitHead, saveGitHeadToConfig } from "../../utils/utils.mjs";
|
|
|
11
11
|
* @returns {Promise<Array<{ path: string, success: boolean, error?: string }>>}
|
|
12
12
|
*/
|
|
13
13
|
export default async function postGenerate({
|
|
14
|
-
|
|
14
|
+
documentStructure,
|
|
15
15
|
docsDir,
|
|
16
16
|
translateLanguages = [],
|
|
17
17
|
locale,
|
package/aigne.yaml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/doc-smith",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7-beta.1",
|
|
4
4
|
"description": "AI-driven documentation generation tool built on the AIGNE Framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"author": "Arcblock <blocklet@arcblock.io> https://github.com/blocklet",
|
|
25
25
|
"license": "Elastic-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@aigne/cli": "^1.
|
|
28
|
-
"@aigne/core": "^1.
|
|
29
|
-
"@aigne/publish-docs": "^0.
|
|
30
|
-
"@blocklet/payment-broker-client": "^1.22.
|
|
27
|
+
"@aigne/cli": "^1.56.0",
|
|
28
|
+
"@aigne/core": "^1.69.0",
|
|
29
|
+
"@aigne/publish-docs": "^0.14.1",
|
|
30
|
+
"@blocklet/payment-broker-client": "^1.22.24",
|
|
31
31
|
"@terrastruct/d2": "^0.1.33",
|
|
32
32
|
"chalk": "^5.5.0",
|
|
33
33
|
"debug": "^4.4.1",
|
|
@@ -66,10 +66,12 @@
|
|
|
66
66
|
"@biomejs/biome": "^2.2.4"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
|
-
"test": "bun test",
|
|
70
|
-
"test:coverage2": "bun test --coverage",
|
|
71
|
-
"test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text",
|
|
72
|
-
"test:
|
|
69
|
+
"test": "bun test --preload ./tests/setup/mock-process-exit.mjs",
|
|
70
|
+
"test:coverage2": "bun test --preload ./tests/setup/mock-process-exit.mjs --coverage",
|
|
71
|
+
"test:coverage": "bun test --preload ./tests/setup/mock-process-exit.mjs --coverage --coverage-reporter=lcov --coverage-reporter=text",
|
|
72
|
+
"test:deploy": "bun test --preload ./tests/setup/mock-process-exit.mjs tests/utils/deploy.test.mjs --coverage --coverage-reporter=text",
|
|
73
|
+
"test:user-review": "bun test --preload ./tests/setup/mock-process-exit.mjs tests/agents/update/user-review-document.test.mjs --coverage --coverage-reporter=lcov --coverage-reporter=text",
|
|
74
|
+
"test:watch": "bun test --preload ./tests/setup/mock-process-exit.mjs --watch",
|
|
73
75
|
"lint": "biome lint && biome format",
|
|
74
76
|
"update:deps": "npx -y taze major -r -w -f -n '/@abtnode|@aigne|@arcblock|@blocklet|@did-connect|@did-pay|@did-space|@nft-store|@nft-studio|@ocap/' && pnpm install && pnpm run deduplicate",
|
|
75
77
|
"deduplicate": "pnpm dedupe",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<markdown_syntax_rules>
|
|
2
|
+
|
|
3
|
+
## Markdown Syntax Standard
|
|
4
|
+
|
|
5
|
+
### Allowed Syntax
|
|
6
|
+
|
|
7
|
+
**Inline** (used within text):
|
|
8
|
+
|
|
9
|
+
- Emphasis: `**bold**`, `*italic*`, `~~strikethrough~~`
|
|
10
|
+
- Links: `[text](url)`
|
|
11
|
+
- Images: ``
|
|
12
|
+
- Inline Code: `` `code` ``
|
|
13
|
+
|
|
14
|
+
**Block** (standalone blocks):
|
|
15
|
+
|
|
16
|
+
- Headings: `#`, `##`, `###`, etc.
|
|
17
|
+
- Lists: `- item`, `1. item`
|
|
18
|
+
- Task Lists: `- [ ]`, `- [x]`
|
|
19
|
+
- Blockquotes: `> quote`
|
|
20
|
+
- Code Block: ` ```language ... ``` `
|
|
21
|
+
- Tables: `| col | col |` with `|---|---|` separator
|
|
22
|
+
- Horizontal Rule: `---`
|
|
23
|
+
- Admonition: `:::severity ... :::`
|
|
24
|
+
|
|
25
|
+
### Prohibited Syntax
|
|
26
|
+
|
|
27
|
+
The following are **strictly forbidden**:
|
|
28
|
+
|
|
29
|
+
- Footnotes: `[^1]: note text`
|
|
30
|
+
- Math/LaTeX: `$inline$`, `$$ block $$`
|
|
31
|
+
- Highlight: `==highlighted==`
|
|
32
|
+
- Subscript/Superscript: `H~2~O`, `X^2^`
|
|
33
|
+
- Abbreviations: `*[HTML]: Hyper Text Markup Language`
|
|
34
|
+
|
|
35
|
+
### Link Rules
|
|
36
|
+
|
|
37
|
+
- Links must reference valid external URLs or paths from the document structure
|
|
38
|
+
- Use absolute paths from the documentation structure for internal links
|
|
39
|
+
|
|
40
|
+
### Table Formatting Rules
|
|
41
|
+
|
|
42
|
+
- Separator row (`|---|---|---|`) must match the exact column count of header row
|
|
43
|
+
- Each row must have the same number of columns
|
|
44
|
+
- Use tables for predefined values (e.g., status types, options) or term definitions
|
|
45
|
+
- Validate table structure before output
|
|
46
|
+
|
|
47
|
+
### Code Block Rules
|
|
48
|
+
|
|
49
|
+
- Ensure code blocks are properly closed
|
|
50
|
+
- Generate complete, syntactically correct code (JSON, etc.)
|
|
51
|
+
- Perform self-validation to ensure all code blocks, lists, and tables are properly closed without truncation
|
|
52
|
+
|
|
53
|
+
### Block-Level Elements
|
|
54
|
+
|
|
55
|
+
Block-level elements are standalone content blocks that must be visually separated from surrounding content.
|
|
56
|
+
|
|
57
|
+
Block-Level Element List:
|
|
58
|
+
|
|
59
|
+
- Admonition: `:::severity ... :::`
|
|
60
|
+
- Code Block: ` ```language ... ``` `
|
|
61
|
+
- Custom Components: `<x-cards>`, `<x-card>`, `<x-field-group>`, etc.
|
|
62
|
+
|
|
63
|
+
**Spacing Rule:** Always insert a blank line before and after any block-level element when it is **adjacent to** other Markdown content (headings, paragraphs, lists, etc.).
|
|
64
|
+
|
|
65
|
+
</markdown_syntax_rules>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<admonition_syntax_rules>
|
|
2
|
+
|
|
3
|
+
## Admonition Syntax Rules
|
|
4
|
+
|
|
5
|
+
Admonition is a Markdown block extension used to highlight important information. Use it sparingly.
|
|
6
|
+
|
|
7
|
+
### Syntax Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
:::severity
|
|
11
|
+
content
|
|
12
|
+
:::
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Syntax Rules
|
|
16
|
+
|
|
17
|
+
The `severity` is **required** and must be one of the following:
|
|
18
|
+
|
|
19
|
+
- `success`: Positive outcome or best practice
|
|
20
|
+
- `info`: General tips
|
|
21
|
+
- `warning`: Cautions or potential issues
|
|
22
|
+
- `error`: Critical risks or breaking operations
|
|
23
|
+
|
|
24
|
+
The `content` is **required** and MUST strictly comply with the rules below:
|
|
25
|
+
|
|
26
|
+
- The `content` MUST be plain text only
|
|
27
|
+
- The `content` MUST be a single paragraph (no line breaks).
|
|
28
|
+
- Nesting any blocks or Admonitions is forbidden.
|
|
29
|
+
- Recommended length: within 200 characters.
|
|
30
|
+
|
|
31
|
+
### Usage Guidelines
|
|
32
|
+
|
|
33
|
+
- Use sparingly, only for messages that truly require user attention
|
|
34
|
+
- Do not use Admonition if the content needs any Markdown syntax from <markdown_syntax_rules> — use regular paragraphs instead
|
|
35
|
+
- Keep the text short, clear, and actionable
|
|
36
|
+
- Choose the severity level according to the importance of the message
|
|
37
|
+
|
|
38
|
+
### Good Examples
|
|
39
|
+
|
|
40
|
+
1. All four severity types:
|
|
41
|
+
|
|
42
|
+
```md
|
|
43
|
+
:::success
|
|
44
|
+
Your configuration is complete.
|
|
45
|
+
:::
|
|
46
|
+
|
|
47
|
+
:::info
|
|
48
|
+
Environment variables can override this setting.
|
|
49
|
+
:::
|
|
50
|
+
|
|
51
|
+
:::warning
|
|
52
|
+
This API will be removed in v3.0.
|
|
53
|
+
:::
|
|
54
|
+
|
|
55
|
+
:::error
|
|
56
|
+
Never commit API keys to version control.
|
|
57
|
+
:::
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Bad Examples
|
|
61
|
+
1. Contains Markdown Syntax:
|
|
62
|
+
|
|
63
|
+
```md
|
|
64
|
+
:::info
|
|
65
|
+
No **bold**, *italic*, or `inline code` allowed.
|
|
66
|
+
:::
|
|
67
|
+
|
|
68
|
+
:::warning
|
|
69
|
+
No [links](https://example.com) allowed.
|
|
70
|
+
:::
|
|
71
|
+
|
|
72
|
+
:::info
|
|
73
|
+
- No lists
|
|
74
|
+
- Or bullet points
|
|
75
|
+
:::
|
|
76
|
+
|
|
77
|
+
:::error
|
|
78
|
+
```sh
|
|
79
|
+
npm i
|
|
80
|
+
```
|
|
81
|
+
:::
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
2. Multi-paragraph:
|
|
85
|
+
|
|
86
|
+
```md
|
|
87
|
+
:::warning
|
|
88
|
+
No multi-paragraph.
|
|
89
|
+
|
|
90
|
+
Like this.
|
|
91
|
+
:::
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
</admonition_syntax_rules>
|
|
@@ -18,7 +18,7 @@ XCard is individual link display card, suitable for displaying individual links
|
|
|
18
18
|
### Children
|
|
19
19
|
|
|
20
20
|
- Must be written within `<x-card>...</x-card>` children.
|
|
21
|
-
-
|
|
21
|
+
- Plain Text Only: Do not use any Markdown syntax (see `<markdown_syntax_rules>` for the full list).
|
|
22
22
|
|
|
23
23
|
### Good Examples
|
|
24
24
|
|
|
@@ -17,6 +17,11 @@ XFieldDesc is rich field description. Used to provide rich text descriptions for
|
|
|
17
17
|
### Usage Rules
|
|
18
18
|
|
|
19
19
|
- **Parent Requirement**: Must be child of `<x-field>`: `<x-field-desc>` can only appear as a child element of `<x-field>` components
|
|
20
|
+
- **Avoid Redundant Information**: Do not repeat information in `<x-field-desc>` that is already expressed by the parent `<x-field>` attributes. Specifically:
|
|
21
|
+
- **Required Status**: Do not mention "required" or "optional" in descriptions since `data-required` attribute already indicates this
|
|
22
|
+
- **Default Values**: Do not repeat default values in descriptions since `data-default` attribute already shows this
|
|
23
|
+
- **Deprecated Status**: Do not mention "deprecated" in descriptions since `data-deprecated` attribute already indicates this
|
|
24
|
+
- Focus descriptions on the field's purpose, format, constraints, example values, and usage guidance instead
|
|
20
25
|
|
|
21
26
|
### Good Examples
|
|
22
27
|
|
|
@@ -83,4 +88,33 @@ XFieldDesc is rich field description. Used to provide rich text descriptions for
|
|
|
83
88
|
</x-field-group>
|
|
84
89
|
```
|
|
85
90
|
|
|
91
|
+
- Example 7: Redundant required information in description (violates "Avoid Redundant Information" rule)
|
|
92
|
+
```md
|
|
93
|
+
<x-field-group>
|
|
94
|
+
<x-field data-name="api_key" data-type="string" data-required="true">
|
|
95
|
+
<x-field-desc markdown>Your **API key** for authentication. **This field is required.**</x-field-desc>
|
|
96
|
+
</x-field>
|
|
97
|
+
<x-field data-name="timeout" data-type="number" data-required="false" data-default="5000">
|
|
98
|
+
<x-field-desc markdown>Request timeout in milliseconds. **Optional**, defaults to `5000`.</x-field-desc>
|
|
99
|
+
</x-field>
|
|
100
|
+
<x-field data-name="old_api" data-type="string" data-deprecated="true">
|
|
101
|
+
<x-field-desc markdown>Old API endpoint. **This field is deprecated.**</x-field-desc>
|
|
102
|
+
</x-field>
|
|
103
|
+
</x-field-group>
|
|
104
|
+
```
|
|
105
|
+
**Correct approach:**
|
|
106
|
+
```md
|
|
107
|
+
<x-field-group>
|
|
108
|
+
<x-field data-name="api_key" data-type="string" data-required="true">
|
|
109
|
+
<x-field-desc markdown>Your **API key** for authentication. Generate one from the `Settings > API Keys` section.</x-field-desc>
|
|
110
|
+
</x-field>
|
|
111
|
+
<x-field data-name="timeout" data-type="number" data-required="false" data-default="5000">
|
|
112
|
+
<x-field-desc markdown>Request timeout in milliseconds.</x-field-desc>
|
|
113
|
+
</x-field>
|
|
114
|
+
<x-field data-name="old_api" data-type="string" data-deprecated="true">
|
|
115
|
+
<x-field-desc markdown>Old API endpoint. Use the new endpoint instead.</x-field-desc>
|
|
116
|
+
</x-field>
|
|
117
|
+
</x-field-group>
|
|
118
|
+
```
|
|
119
|
+
|
|
86
120
|
</x-field-desc-usage-rules>
|
|
@@ -15,7 +15,6 @@ XFieldGroup is `<x-field>` grouping container. Used to group multiple related `<
|
|
|
15
15
|
|
|
16
16
|
- **Top-Level Only**: Used only at the top level for grouping related `<x-field>` elements. Cannot be nested inside other `<x-field>` or `<x-field-group>` elements
|
|
17
17
|
- **Structured Data Only**: Use `<x-field-group>` for fields **other than simple types** (`string`, `number`, `boolean`, `symbol`), e.g., Properties, Context, Parameters, Return values. For simple-type fields, use plain Markdown text.
|
|
18
|
-
- **Spacing Around**: Always insert a blank line before and after `<x-field-group>` when it’s adjacent to Markdown content.
|
|
19
18
|
|
|
20
19
|
### Good Examples
|
|
21
20
|
|
|
@@ -78,18 +77,4 @@ XFieldGroup is `<x-field>` grouping container. Used to group multiple related `<
|
|
|
78
77
|
</x-field-group>
|
|
79
78
|
```
|
|
80
79
|
|
|
81
|
-
- Example 6: Missing blank line before x-field-group (violates "Spacing Around" rule)
|
|
82
|
-
```md
|
|
83
|
-
**Parameters**
|
|
84
|
-
<x-field-group>
|
|
85
|
-
<x-field data-name="initialState" data-type="any" data-required="false">
|
|
86
|
-
<x-field-desc markdown>The initial state value.</x-field-desc>
|
|
87
|
-
</x-field>
|
|
88
|
-
</x-field-group>
|
|
89
|
-
|
|
90
|
-
`useReducer` returns an array with two items:
|
|
91
|
-
<x-field-group>
|
|
92
|
-
<x-field data-name="dispatch" data-type="function" data-desc="A function that you can call with an action to update the state."></x-field>
|
|
93
|
-
</x-field-group>
|
|
94
|
-
```
|
|
95
80
|
</x-field-group-usage-rules>
|
|
@@ -10,7 +10,7 @@ XField is structured data field, suitable for displaying API parameters, return
|
|
|
10
10
|
- `data-default` (optional): Default value for the field
|
|
11
11
|
- `data-required` (optional): Whether the field is required ("true" or "false")
|
|
12
12
|
- `data-deprecated` (optional): Whether the field is deprecated ("true" or "false")
|
|
13
|
-
- `data-desc` (optional): Simple description of the field (
|
|
13
|
+
- `data-desc` (optional): Simple description of the field. Do not use any Markdown syntax (see `<markdown_syntax_rules>` for the full list).
|
|
14
14
|
|
|
15
15
|
### Children
|
|
16
16
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
<document_rules>
|
|
3
3
|
|
|
4
|
+
{% include "../../common/document/markdown-syntax-rules.md" %}
|
|
5
|
+
|
|
4
6
|
Documentation Generation Rules:
|
|
5
7
|
- **Opening Hook Requirement:** The document must begin with a compelling, relaxed, and concise introductory paragraph (The "Hook").
|
|
6
8
|
- **Hook Content:** This paragraph must clearly state the specific outcome, knowledge, or skill the reader will gain upon completing the document (Preferably 50 words or less).
|
|
@@ -13,9 +15,6 @@ Documentation Generation Rules:
|
|
|
13
15
|
- Since API names are already specified in document titles, avoid repeating them in subheadings—use sub-API names directly
|
|
14
16
|
- Include links to related documents in the introduction using Markdown format to help users navigate to relevant content
|
|
15
17
|
- Add links to further reading materials in the summary section using Markdown format
|
|
16
|
-
- **Markdown Syntax Constraint**: Use only GitHub Flavored Markdown (GFM) syntax by default. Prohibited extensions include: custom blocks `:::`, footnotes `[^1]: notes`, math formulas `$$ LaTeX`, highlighted text `==code==`, and other non-GFM syntax unless explicitly defined in custom component rules
|
|
17
|
-
- Use proper Markdown link syntax, for example: [Next Chapter Title](next_chapter_path)
|
|
18
|
-
- **Ensure next_chapter_path references either external URLs or valid paths from the documentation structure**—use absolute paths from the documentation structure
|
|
19
18
|
- When detailDataSource includes third-party links, incorporate them appropriately throughout the document
|
|
20
19
|
- Structure each section with: title, introduction, code examples, response data samples, and explanatory notes. Place explanations directly after code examples without separate "Example Description" subheadings
|
|
21
20
|
- Maintain content completeness and logical flow so users can follow the documentation seamlessly
|
|
@@ -23,10 +22,6 @@ Documentation Generation Rules:
|
|
|
23
22
|
- All interface and method documentation must include **response data examples**
|
|
24
23
|
- **Use `<x-field-group>` for all structured data**: Represent objects with nested `<x-field>` elements, and expand each structure to the **deepest relevant level**.
|
|
25
24
|
- **Enhance field descriptions with example values**: For structured data defined using `<x-field-group>`, extract example values from type definitions, comments, or test cases to make documentation more practical and user-friendly.
|
|
26
|
-
- **Use Markdown tables** for predefined values (e.g., status types, options) or term definitions to improve clarity and allow side-by-side comparison.
|
|
27
|
-
- Validate output Markdown for completeness, ensuring tables are properly formatted
|
|
28
|
-
- **Content Integrity**: Generate complete, syntactically correct code blocks (JSON, etc.). Perform self-validation to ensure all code blocks, lists, and tables are properly closed without truncation
|
|
29
|
-
- **Markdown Syntax Validation**: Ensure correct Markdown formatting, particularly table separators (e.g., `|---|---|---|`) that match column counts
|
|
30
25
|
- Use README files for reference only—extract the most current and comprehensive information directly from source code
|
|
31
26
|
- Omit tag information from document headers as it's processed programmatically
|
|
32
27
|
- Parse `jsx` syntax correctly when present in code samples
|
|
@@ -42,6 +42,8 @@ Documentation content generation rules:
|
|
|
42
42
|
|
|
43
43
|
{% include "../custom/code-block-usage-rules.md" %}
|
|
44
44
|
|
|
45
|
+
{% include "../custom/admonition-usage-rules.md" %}
|
|
46
|
+
|
|
45
47
|
{% include "../../common/document/media-file-list-usage-rules.md" %}
|
|
46
48
|
|
|
47
49
|
{% include "../../common/document/openapi-usage-rules.md" %}
|
|
@@ -68,6 +68,8 @@ Documentation content optimization rules:
|
|
|
68
68
|
|
|
69
69
|
{% include "../custom/code-block-usage-rules.md" %}
|
|
70
70
|
|
|
71
|
+
{% include "../custom/admonition-usage-rules.md" %}
|
|
72
|
+
|
|
71
73
|
{% include "../../common/document/media-file-list-usage-rules.md" %}
|
|
72
74
|
|
|
73
75
|
{% include "../../common/document/openapi-usage-rules.md" %}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<admonition_rules>
|
|
2
|
+
|
|
3
|
+
Admonition blocks use the following format:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
:::severity
|
|
7
|
+
|
|
8
|
+
text
|
|
9
|
+
|
|
10
|
+
:::
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Admonition Translation Rules:
|
|
14
|
+
|
|
15
|
+
- **Translate** the text content only
|
|
16
|
+
- **Do not translate** the severity keyword (success, info, warning, error)
|
|
17
|
+
- **Preserve** the `:::` syntax and block structure
|
|
18
|
+
|
|
19
|
+
</admonition_rules>
|
|
20
|
+
|
|
@@ -24,6 +24,8 @@ Translation Requirements:
|
|
|
24
24
|
- Translate Descriptions Only in <x-field>: All `<x-field>` component attributes must maintain the original format. Only translate the description content within `data-desc` attribute or `<x-field-desc>` elements.
|
|
25
25
|
|
|
26
26
|
{% include "./code-block.md" %}
|
|
27
|
+
|
|
28
|
+
{% include "./admonition.md" %}
|
|
27
29
|
</translation_rules>
|
|
28
30
|
|
|
29
31
|
{% if feedback %}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Default file patterns for inclusion and exclusion
|
|
2
|
-
export const DEFAULT_INCLUDE_PATTERNS = [
|
|
2
|
+
export const DEFAULT_INCLUDE_PATTERNS = Object.freeze([
|
|
3
3
|
// Python
|
|
4
4
|
"*.py",
|
|
5
5
|
"*.pyi",
|
|
@@ -100,42 +100,29 @@ export const DEFAULT_INCLUDE_PATTERNS = [
|
|
|
100
100
|
"*.mkv",
|
|
101
101
|
"*.webm",
|
|
102
102
|
"*.m4v",
|
|
103
|
-
];
|
|
103
|
+
]);
|
|
104
104
|
|
|
105
|
-
export const DEFAULT_EXCLUDE_PATTERNS = [
|
|
106
|
-
"**/aigne-docs/**",
|
|
105
|
+
export const DEFAULT_EXCLUDE_PATTERNS = Object.freeze([
|
|
107
106
|
"**/doc-smith/**",
|
|
108
107
|
"**/.aigne/**",
|
|
109
|
-
"**/data/**",
|
|
110
|
-
"**/public/**",
|
|
111
|
-
"**/static/**",
|
|
112
108
|
"**/vendor/**",
|
|
113
109
|
"**/temp/**",
|
|
114
|
-
"**/*docs/**",
|
|
115
|
-
"**/*doc/**",
|
|
116
110
|
"**/*venv/**",
|
|
117
111
|
"*.venv/**",
|
|
118
|
-
"*test*",
|
|
119
|
-
"**/*test/**",
|
|
120
|
-
"**/*tests/**",
|
|
121
|
-
"**/*examples/**",
|
|
122
|
-
"**/playgrounds/**",
|
|
123
|
-
"v1/**",
|
|
124
112
|
"**/dist/**",
|
|
125
113
|
"**/*build/**",
|
|
126
114
|
"**/*experimental/**",
|
|
127
115
|
"**/*deprecated/**",
|
|
128
|
-
"
|
|
129
|
-
"
|
|
116
|
+
"**/misc/**",
|
|
117
|
+
"**/legacy/**",
|
|
130
118
|
".git/**",
|
|
131
119
|
".github/**",
|
|
132
120
|
".next/**",
|
|
133
121
|
".vscode/**",
|
|
134
|
-
"
|
|
135
|
-
"
|
|
122
|
+
"**/obj/**",
|
|
123
|
+
"**/bin/**",
|
|
136
124
|
"**/*node_modules/**",
|
|
137
125
|
"*.log",
|
|
138
|
-
"**/*test.*",
|
|
139
126
|
"**/pnpm-lock.yaml",
|
|
140
127
|
"**/yarn.lock",
|
|
141
128
|
"**/package-lock.json",
|
|
@@ -143,7 +130,7 @@ export const DEFAULT_EXCLUDE_PATTERNS = [
|
|
|
143
130
|
"**/bun.lockb",
|
|
144
131
|
"**/bun.lock",
|
|
145
132
|
"**/bun.lockb",
|
|
146
|
-
];
|
|
133
|
+
]);
|
|
147
134
|
|
|
148
135
|
// Supported languages for documentation
|
|
149
136
|
export const SUPPORTED_LANGUAGES = [
|
package/utils/d2-utils.mjs
CHANGED
|
@@ -206,7 +206,12 @@ export function wrapCode({ content }) {
|
|
|
206
206
|
return `\`\`\`d2\n${content}\n\`\`\``;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Replaces D2 code block with DIAGRAM_PLACEHOLDER.
|
|
211
|
+
* @param {string} content - Document content containing D2 code block
|
|
212
|
+
* @returns {Array} - [contentWithPlaceholder, originalCodeBlock]
|
|
213
|
+
*/
|
|
214
|
+
export function replaceD2WithPlaceholder({ content }) {
|
|
210
215
|
const [firstMatch] = Array.from(content.matchAll(codeBlockRegex));
|
|
211
216
|
if (firstMatch) {
|
|
212
217
|
const matchContent = firstMatch[0];
|
|
@@ -216,3 +221,37 @@ export function replacePlaceholder({ content }) {
|
|
|
216
221
|
|
|
217
222
|
return [content, ""];
|
|
218
223
|
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Replaces DIAGRAM_PLACEHOLDER with D2 code block, ensuring proper spacing.
|
|
227
|
+
* @param {string} content - Document content containing DIAGRAM_PLACEHOLDER
|
|
228
|
+
* @param {string} diagramSourceCode - D2 diagram source code (without markdown wrapper)
|
|
229
|
+
* @returns {string} - Content with placeholder replaced by code block
|
|
230
|
+
*/
|
|
231
|
+
export function replacePlaceholderWithD2({ content, diagramSourceCode }) {
|
|
232
|
+
if (!content || !diagramSourceCode) {
|
|
233
|
+
return content;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const placeholderIndex = content.indexOf(DIAGRAM_PLACEHOLDER);
|
|
237
|
+
if (placeholderIndex === -1) {
|
|
238
|
+
return content;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Check if placeholder has newlines around it
|
|
242
|
+
const beforePlaceholder = content.substring(0, placeholderIndex);
|
|
243
|
+
const afterPlaceholder = content.substring(placeholderIndex + DIAGRAM_PLACEHOLDER.length);
|
|
244
|
+
|
|
245
|
+
const codeBlock = wrapCode({ content: diagramSourceCode });
|
|
246
|
+
|
|
247
|
+
// Add newlines if missing
|
|
248
|
+
let replacement = codeBlock;
|
|
249
|
+
if (beforePlaceholder && !beforePlaceholder.endsWith("\n")) {
|
|
250
|
+
replacement = `\n${replacement}`;
|
|
251
|
+
}
|
|
252
|
+
if (afterPlaceholder && !afterPlaceholder.startsWith("\n")) {
|
|
253
|
+
replacement = `${replacement}\n`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return content.replace(DIAGRAM_PLACEHOLDER, replacement);
|
|
257
|
+
}
|
|
@@ -36,20 +36,14 @@ export function generateFileName(flatName, locale) {
|
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Find a single item by path in documentation structure result and read its content
|
|
39
|
-
* @param {Array}
|
|
39
|
+
* @param {Array} documentStructure - Array of documentation structure items
|
|
40
40
|
* @param {string} docPath - Document path to find (supports .md filenames)
|
|
41
41
|
* @param {string} boardId - Board ID for fallback matching
|
|
42
42
|
* @param {string} docsDir - Docs directory path for reading content
|
|
43
43
|
* @param {string} locale - Main language locale (e.g., 'en', 'zh', 'fr')
|
|
44
44
|
* @returns {Promise<Object|null>} Found item with content or null
|
|
45
45
|
*/
|
|
46
|
-
export async function findItemByPath(
|
|
47
|
-
documentExecutionStructure,
|
|
48
|
-
docPath,
|
|
49
|
-
boardId,
|
|
50
|
-
docsDir,
|
|
51
|
-
locale = "en",
|
|
52
|
-
) {
|
|
46
|
+
export async function findItemByPath(documentStructure, docPath, boardId, docsDir, locale = "en") {
|
|
53
47
|
let foundItem = null;
|
|
54
48
|
let fileName = null;
|
|
55
49
|
|
|
@@ -57,10 +51,10 @@ export async function findItemByPath(
|
|
|
57
51
|
if (docPath.endsWith(".md")) {
|
|
58
52
|
fileName = docPath;
|
|
59
53
|
const flatName = fileNameToFlatPath(docPath);
|
|
60
|
-
foundItem = findItemByFlatName(
|
|
54
|
+
foundItem = findItemByFlatName(documentStructure, flatName);
|
|
61
55
|
} else {
|
|
62
56
|
// First try direct path matching
|
|
63
|
-
foundItem =
|
|
57
|
+
foundItem = documentStructure.find((item) => item.path === docPath);
|
|
64
58
|
|
|
65
59
|
// If not found and boardId is provided, try boardId-flattenedPath format matching
|
|
66
60
|
if (!foundItem && boardId) {
|
|
@@ -70,7 +64,7 @@ export async function findItemByPath(
|
|
|
70
64
|
const flattenedPath = docPath.substring(boardId.length + 1);
|
|
71
65
|
|
|
72
66
|
// Find item by comparing flattened paths
|
|
73
|
-
foundItem =
|
|
67
|
+
foundItem = documentStructure.find((item) => {
|
|
74
68
|
// Convert item.path to flattened format (replace / with -)
|
|
75
69
|
const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
|
|
76
70
|
return itemFlattenedPath === flattenedPath;
|
|
@@ -127,10 +121,10 @@ export async function readFileContent(docsDir, fileName) {
|
|
|
127
121
|
* Get main language markdown files from docs directory
|
|
128
122
|
* @param {string} docsDir - Docs directory path
|
|
129
123
|
* @param {string} locale - Main language locale (e.g., 'en', 'zh', 'fr')
|
|
130
|
-
* @param {Array}
|
|
131
|
-
* @returns {Promise<string[]>} Array of main language .md files ordered by
|
|
124
|
+
* @param {Array} documentStructure - Array of documentation structure items to determine file order
|
|
125
|
+
* @returns {Promise<string[]>} Array of main language .md files ordered by documentStructure
|
|
132
126
|
*/
|
|
133
|
-
export async function getMainLanguageFiles(docsDir, locale,
|
|
127
|
+
export async function getMainLanguageFiles(docsDir, locale, documentStructure = null) {
|
|
134
128
|
// Check if docsDir exists
|
|
135
129
|
try {
|
|
136
130
|
await access(docsDir);
|
|
@@ -162,17 +156,17 @@ export async function getMainLanguageFiles(docsDir, locale, documentExecutionStr
|
|
|
162
156
|
}
|
|
163
157
|
});
|
|
164
158
|
|
|
165
|
-
// If
|
|
166
|
-
if (
|
|
159
|
+
// If documentStructure is provided, sort files according to the order in documentStructure
|
|
160
|
+
if (documentStructure && Array.isArray(documentStructure)) {
|
|
167
161
|
// Create a map from flat file name to documentation structure order
|
|
168
162
|
const orderMap = new Map();
|
|
169
|
-
|
|
163
|
+
documentStructure.forEach((item, index) => {
|
|
170
164
|
const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
|
|
171
165
|
const expectedFileName = generateFileName(itemFlattenedPath, locale);
|
|
172
166
|
orderMap.set(expectedFileName, index);
|
|
173
167
|
});
|
|
174
168
|
|
|
175
|
-
// Sort filtered files based on their order in
|
|
169
|
+
// Sort filtered files based on their order in documentStructure
|
|
176
170
|
return filteredFiles.sort((a, b) => {
|
|
177
171
|
const orderA = orderMap.get(a);
|
|
178
172
|
const orderB = orderMap.get(b);
|
|
@@ -191,7 +185,7 @@ export async function getMainLanguageFiles(docsDir, locale, documentExecutionStr
|
|
|
191
185
|
});
|
|
192
186
|
}
|
|
193
187
|
|
|
194
|
-
// If no
|
|
188
|
+
// If no documentStructure provided, return files in alphabetical order
|
|
195
189
|
return filteredFiles.sort();
|
|
196
190
|
}
|
|
197
191
|
|
|
@@ -212,12 +206,12 @@ export function fileNameToFlatPath(fileName) {
|
|
|
212
206
|
|
|
213
207
|
/**
|
|
214
208
|
* Find documentation structure item by flattened file name
|
|
215
|
-
* @param {Array}
|
|
209
|
+
* @param {Array} documentStructure - Array of documentation structure items
|
|
216
210
|
* @param {string} flatName - Flattened file name
|
|
217
211
|
* @returns {Object|null} Found item or null
|
|
218
212
|
*/
|
|
219
|
-
export function findItemByFlatName(
|
|
220
|
-
return
|
|
213
|
+
export function findItemByFlatName(documentStructure, flatName) {
|
|
214
|
+
return documentStructure.find((item) => {
|
|
221
215
|
const itemFlattenedPath = item.path.replace(/^\//, "").replace(/\//g, "-");
|
|
222
216
|
return itemFlattenedPath === flatName;
|
|
223
217
|
});
|
|
@@ -226,11 +220,11 @@ export function findItemByFlatName(documentExecutionStructure, flatName) {
|
|
|
226
220
|
/**
|
|
227
221
|
* Process selected files and convert to found items with content
|
|
228
222
|
* @param {string[]} selectedFiles - Array of selected file names
|
|
229
|
-
* @param {Array}
|
|
223
|
+
* @param {Array} documentStructure - Array of documentation structure items
|
|
230
224
|
* @param {string} docsDir - Docs directory path
|
|
231
225
|
* @returns {Promise<Object[]>} Array of found items with content
|
|
232
226
|
*/
|
|
233
|
-
export async function processSelectedFiles(selectedFiles,
|
|
227
|
+
export async function processSelectedFiles(selectedFiles, documentStructure, docsDir) {
|
|
234
228
|
const foundItems = [];
|
|
235
229
|
|
|
236
230
|
for (const selectedFile of selectedFiles) {
|
|
@@ -241,7 +235,7 @@ export async function processSelectedFiles(selectedFiles, documentExecutionStruc
|
|
|
241
235
|
const flatName = fileNameToFlatPath(selectedFile);
|
|
242
236
|
|
|
243
237
|
// Try to find matching item by comparing flattened paths
|
|
244
|
-
const foundItemByFile = findItemByFlatName(
|
|
238
|
+
const foundItemByFile = findItemByFlatName(documentStructure, flatName);
|
|
245
239
|
|
|
246
240
|
if (foundItemByFile) {
|
|
247
241
|
const result = {
|
package/utils/file-utils.mjs
CHANGED
|
@@ -188,7 +188,7 @@ export async function getFilesWithGlob(dir, includePatterns, excludePatterns, gi
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
// Add default exclusions if not already present
|
|
191
|
-
const defaultExclusions = ["node_modules/**", "
|
|
191
|
+
const defaultExclusions = ["node_modules/**", "temp/**"];
|
|
192
192
|
for (const exclusion of defaultExclusions) {
|
|
193
193
|
if (!allIgnorePatterns.includes(exclusion)) {
|
|
194
194
|
allIgnorePatterns.push(exclusion);
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
type: array
|
|
2
|
-
items:
|
|
3
|
-
type: object
|
|
4
|
-
properties:
|
|
5
|
-
title:
|
|
6
|
-
type: string
|
|
7
|
-
description:
|
|
8
|
-
type: string
|
|
9
|
-
path:
|
|
10
|
-
type: string
|
|
11
|
-
description: Path in URL format, cannot be empty, must start with /, no need to include language level, e.g., /zh/about should return /about
|
|
12
|
-
parentId:
|
|
13
|
-
type:
|
|
14
|
-
- string
|
|
15
|
-
- "null"
|
|
16
|
-
translates:
|
|
17
|
-
type: array
|
|
18
|
-
items:
|
|
19
|
-
type: object
|
|
20
|
-
properties:
|
|
21
|
-
language:
|
|
22
|
-
type: string
|
|
23
|
-
description: Language code, such as zh, en, ja, etc.
|
|
24
|
-
sourceIds:
|
|
25
|
-
type: array
|
|
26
|
-
items:
|
|
27
|
-
type: string
|
|
28
|
-
description: Associated sourceId from `<data_sources>` for subsequent translation and content generation, must come from sourceId in `<data_sources>`, cannot have fake ids, cannot be empty
|
|
29
|
-
required:
|
|
30
|
-
- title
|
|
31
|
-
- description
|
|
32
|
-
- path
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export default function addTranslatesToStructure({
|
|
2
|
-
originalDocumentStructure = [],
|
|
3
|
-
translateLanguages = [],
|
|
4
|
-
}) {
|
|
5
|
-
const documentExecutionStructure = (originalDocumentStructure || []).map((item) => ({
|
|
6
|
-
...item,
|
|
7
|
-
translates: (translateLanguages || []).map((lang) => ({ language: lang })),
|
|
8
|
-
}));
|
|
9
|
-
|
|
10
|
-
return {
|
|
11
|
-
documentExecutionStructure,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
addTranslatesToStructure.inputSchema = {
|
|
16
|
-
type: "object",
|
|
17
|
-
properties: {
|
|
18
|
-
originalDocumentStructure: { type: "array", items: { type: "object" } },
|
|
19
|
-
translateLanguages: { type: "array", items: { type: "string" } },
|
|
20
|
-
},
|
|
21
|
-
required: ["originalDocumentStructure", "translateLanguages"],
|
|
22
|
-
};
|
|
23
|
-
addTranslatesToStructure.outputSchema = {
|
|
24
|
-
type: "object",
|
|
25
|
-
properties: {
|
|
26
|
-
documentExecutionStructure: { type: "array" },
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
addTranslatesToStructure.task_render_mode = "hide";
|