@aigne/doc-smith 0.8.14 → 0.8.15-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 +19 -0
- package/agents/update/check-document.mjs +15 -0
- package/agents/update/index.yaml +1 -1
- package/agents/utils/choose-docs.mjs +6 -1
- package/agents/utils/load-sources.mjs +80 -22
- package/agents/utils/transform-detail-datasources.mjs +24 -2
- package/package.json +1 -1
- package/prompts/detail/custom/custom-components.md +247 -153
- package/prompts/detail/d2-diagram/system-prompt.md +33 -7
- package/prompts/detail/generate/detail-example.md +24 -8
- package/prompts/detail/generate/document-rules.md +4 -5
- package/prompts/detail/generate/user-prompt.md +37 -0
- package/prompts/structure/generate/user-prompt.md +34 -0
- package/prompts/translate/code-block.md +14 -7
- package/prompts/translate/translate-document.md +111 -7
- package/utils/file-utils.mjs +83 -7
- package/utils/openapi/index.mjs +24 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.15-beta.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.8.15-beta...v0.8.15-beta.1) (2025-10-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* support openapi datasource, generate better api docs ([#212](https://github.com/AIGNE-io/aigne-doc-smith/issues/212)) ([6a683f1](https://github.com/AIGNE-io/aigne-doc-smith/commit/6a683f117aa94f265383be6e1b3b957803004032))
|
|
9
|
+
|
|
10
|
+
## [0.8.15-beta](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.8.14...v0.8.15-beta) (2025-10-21)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* update document publish prompt for better user experience ([#208](https://github.com/AIGNE-io/aigne-doc-smith/issues/208)) ([0726c23](https://github.com/AIGNE-io/aigne-doc-smith/commit/0726c23ed2d47b2126c0896d71922860b7436895))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* enforce stricter rules for x-field component and markdown ([#210](https://github.com/AIGNE-io/aigne-doc-smith/issues/210)) ([d69ee53](https://github.com/AIGNE-io/aigne-doc-smith/commit/d69ee53dbd113859a822d3391cc6cbf2f02bb75e))
|
|
21
|
+
|
|
3
22
|
## [0.8.14](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.8.14-beta.2...v0.8.14) (2025-10-19)
|
|
4
23
|
|
|
5
24
|
## [0.8.14-beta.2](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.8.14-beta.1...v0.8.14-beta.2) (2025-10-19)
|
|
@@ -2,6 +2,7 @@ import { access, readFile } from "node:fs/promises";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { TeamAgent } from "@aigne/core";
|
|
5
|
+
|
|
5
6
|
import checkDetailResult from "../utils/check-detail-result.mjs";
|
|
6
7
|
|
|
7
8
|
// Get current script directory
|
|
@@ -102,6 +103,19 @@ export default async function checkDocument(
|
|
|
102
103
|
options.context.agents["saveSingleDoc"],
|
|
103
104
|
],
|
|
104
105
|
});
|
|
106
|
+
let openAPISpec = null;
|
|
107
|
+
|
|
108
|
+
if (options.context?.userContext?.openAPISpec?.sourceId) {
|
|
109
|
+
const matchingDocument = originalDocumentStructure.find((item) => {
|
|
110
|
+
if (item.path === path) {
|
|
111
|
+
return item.sourceIds.find((x) => x === options.context.userContext.openAPISpec.sourceId);
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
});
|
|
115
|
+
if (matchingDocument) {
|
|
116
|
+
openAPISpec = options.context.userContext.openAPISpec;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
105
119
|
|
|
106
120
|
const result = await options.context.invoke(teamAgent, {
|
|
107
121
|
...rest,
|
|
@@ -112,6 +126,7 @@ export default async function checkDocument(
|
|
|
112
126
|
originalDocumentStructure,
|
|
113
127
|
documentStructure,
|
|
114
128
|
detailFeedback: contentValidationFailed ? validationResult.detailFeedback : "",
|
|
129
|
+
openAPISpec,
|
|
115
130
|
});
|
|
116
131
|
|
|
117
132
|
return {
|
package/agents/update/index.yaml
CHANGED
|
@@ -36,7 +36,7 @@ skills:
|
|
|
36
36
|
- ../update/save-and-translate-document.mjs
|
|
37
37
|
- url: ../utils/action-success.mjs
|
|
38
38
|
default_input:
|
|
39
|
-
action: "✅ Documents updated successfully"
|
|
39
|
+
action: "✅ Documents updated successfully!\n💡 Looks good? Run `aigne doc publish` to go live."
|
|
40
40
|
input_schema:
|
|
41
41
|
type: object
|
|
42
42
|
properties:
|
|
@@ -50,7 +50,12 @@ export default async function chooseDocs(
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
// Use title if available, otherwise fall back to filename
|
|
53
|
-
|
|
53
|
+
let displayName = docItem?.title;
|
|
54
|
+
if (displayName) {
|
|
55
|
+
displayName = `${displayName} (${file})`;
|
|
56
|
+
} else {
|
|
57
|
+
displayName = file;
|
|
58
|
+
}
|
|
54
59
|
|
|
55
60
|
return {
|
|
56
61
|
name: displayName,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { statSync } from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import imageSize from "image-size";
|
|
4
5
|
import {
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
loadFilesFromPaths,
|
|
8
9
|
readFileContents,
|
|
9
10
|
getMimeType,
|
|
11
|
+
checkIsRemoteFile,
|
|
10
12
|
} from "../../utils/file-utils.mjs";
|
|
11
13
|
import {
|
|
12
14
|
getCurrentGitHead,
|
|
@@ -18,28 +20,63 @@ import {
|
|
|
18
20
|
DEFAULT_EXCLUDE_PATTERNS,
|
|
19
21
|
DEFAULT_INCLUDE_PATTERNS,
|
|
20
22
|
} from "../../utils/constants/index.mjs";
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
import { isOpenAPISpecFile } from "../../utils/openapi/index.mjs";
|
|
24
|
+
|
|
25
|
+
export default async function loadSources(
|
|
26
|
+
{
|
|
27
|
+
sources = [],
|
|
28
|
+
sourcesPath = [],
|
|
29
|
+
includePatterns,
|
|
30
|
+
excludePatterns,
|
|
31
|
+
outputDir,
|
|
32
|
+
docsDir,
|
|
33
|
+
"doc-path": docPath,
|
|
34
|
+
boardId,
|
|
35
|
+
useDefaultPatterns = true,
|
|
36
|
+
lastGitHead,
|
|
37
|
+
reset = false,
|
|
38
|
+
media,
|
|
39
|
+
} = {},
|
|
40
|
+
options,
|
|
41
|
+
) {
|
|
36
42
|
let files = Array.isArray(sources) ? [...sources] : [];
|
|
37
43
|
const { minImageWidth } = media || { minImageWidth: 800 };
|
|
38
44
|
|
|
39
45
|
if (sourcesPath) {
|
|
40
|
-
const
|
|
46
|
+
const sourcesPathList = Array.isArray(sourcesPath) ? sourcesPath : [sourcesPath];
|
|
47
|
+
const pickSourcesPath = [];
|
|
48
|
+
const omitSourcesPath = [];
|
|
49
|
+
sourcesPathList.forEach((x) => {
|
|
50
|
+
if (typeof x !== "string" || !x) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (x.startsWith("!")) {
|
|
54
|
+
omitSourcesPath.push(x.substring(1));
|
|
55
|
+
} else {
|
|
56
|
+
pickSourcesPath.push(x);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const customExcludePatterns = omitSourcesPath
|
|
61
|
+
.map((x) => {
|
|
62
|
+
try {
|
|
63
|
+
const stats = statSync(x);
|
|
64
|
+
if (stats.isFile()) {
|
|
65
|
+
return x;
|
|
66
|
+
}
|
|
67
|
+
if (stats.isDirectory()) {
|
|
68
|
+
return `${x}/**`;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.warn(`Failed to stat path ${x}: ${error.message}`);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
.filter(Boolean);
|
|
77
|
+
const allFiles = await loadFilesFromPaths(pickSourcesPath, {
|
|
41
78
|
includePatterns,
|
|
42
|
-
excludePatterns,
|
|
79
|
+
excludePatterns: [...new Set([...(excludePatterns || []), ...customExcludePatterns])],
|
|
43
80
|
useDefaultPatterns,
|
|
44
81
|
defaultIncludePatterns: DEFAULT_INCLUDE_PATTERNS,
|
|
45
82
|
defaultExcludePatterns: DEFAULT_EXCLUDE_PATTERNS,
|
|
@@ -50,9 +87,6 @@ export default async function loadSources({
|
|
|
50
87
|
|
|
51
88
|
files = [...new Set(files)];
|
|
52
89
|
|
|
53
|
-
// all files path
|
|
54
|
-
const allFilesPaths = files.map((file) => `- ${toRelativePath(file)}`).join("\n");
|
|
55
|
-
|
|
56
90
|
// Define media file extensions
|
|
57
91
|
const mediaExtensions = [
|
|
58
92
|
".jpg",
|
|
@@ -110,7 +144,7 @@ export default async function loadSources({
|
|
|
110
144
|
files.map(async (file) => {
|
|
111
145
|
const ext = path.extname(file).toLowerCase();
|
|
112
146
|
|
|
113
|
-
if (mediaExtensions.includes(ext)) {
|
|
147
|
+
if (mediaExtensions.includes(ext) && !checkIsRemoteFile(file)) {
|
|
114
148
|
// This is a media file
|
|
115
149
|
const relativePath = path.relative(docsDir, file);
|
|
116
150
|
const fileName = path.basename(file);
|
|
@@ -161,7 +195,7 @@ export default async function loadSources({
|
|
|
161
195
|
}
|
|
162
196
|
|
|
163
197
|
// Read all source files using the utility function
|
|
164
|
-
|
|
198
|
+
let sourceFiles = await readFileContents(sourceFilesPaths, process.cwd());
|
|
165
199
|
|
|
166
200
|
// Count tokens and lines using utility function
|
|
167
201
|
const { totalTokens, totalLines } = calculateFileStats(sourceFiles);
|
|
@@ -169,8 +203,32 @@ export default async function loadSources({
|
|
|
169
203
|
// check if totalTokens is too large
|
|
170
204
|
const isLargeContext = totalTokens > INTELLIGENT_SUGGESTION_TOKEN_THRESHOLD;
|
|
171
205
|
|
|
206
|
+
// filter OpenAPI doc should after check isLargeContext
|
|
207
|
+
sourceFiles = sourceFiles.filter((file) => {
|
|
208
|
+
if (options?.context?.userContext.openAPISpec) return true;
|
|
209
|
+
|
|
210
|
+
const isOpenAPI = isOpenAPISpecFile(file.content);
|
|
211
|
+
if (isOpenAPI && options?.context?.userContext) {
|
|
212
|
+
options.context.userContext.openAPISpec = file;
|
|
213
|
+
}
|
|
214
|
+
return !isOpenAPI;
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const httpFileList = [];
|
|
218
|
+
|
|
219
|
+
sourceFiles.forEach((file) => {
|
|
220
|
+
if (checkIsRemoteFile(file.sourceId)) {
|
|
221
|
+
httpFileList.push(file);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
if (options?.context?.userContext) {
|
|
225
|
+
options.context.userContext.httpFileList = httpFileList;
|
|
226
|
+
}
|
|
227
|
+
|
|
172
228
|
// Build allSources string using utility function
|
|
173
229
|
const allSources = buildSourcesContent(sourceFiles, isLargeContext);
|
|
230
|
+
// all files path
|
|
231
|
+
const allFilesPaths = sourceFiles.map((x) => `- ${toRelativePath(x.sourceId)}`).join("\n");
|
|
174
232
|
|
|
175
233
|
// Get the last documentation structure
|
|
176
234
|
let originalDocumentStructure;
|
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { normalizePath, toRelativePath } from "../../utils/utils.mjs";
|
|
3
|
+
import { checkIsRemoteFile } from "../../utils/file-utils.mjs";
|
|
3
4
|
|
|
4
|
-
export default function transformDetailDatasources({ sourceIds }) {
|
|
5
|
+
export default function transformDetailDatasources({ sourceIds }, options = {}) {
|
|
5
6
|
// Read file content for each sourceId, ignoring failures
|
|
7
|
+
let openAPISpec;
|
|
8
|
+
const httpFileList = options?.context?.userContext?.httpFileList || [];
|
|
6
9
|
const contents = (sourceIds || [])
|
|
10
|
+
.filter((id) => {
|
|
11
|
+
const openApiSourceId = options?.context?.userContext?.openAPISpec?.sourceId;
|
|
12
|
+
if (openApiSourceId !== undefined && openApiSourceId === id) {
|
|
13
|
+
openAPISpec = options.context.userContext.openAPISpec;
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
})
|
|
7
18
|
.map((id) => {
|
|
8
19
|
try {
|
|
20
|
+
if (checkIsRemoteFile(id)) {
|
|
21
|
+
const findFile = httpFileList.find((f) => f.sourceId === id);
|
|
22
|
+
if (findFile) {
|
|
23
|
+
return `// sourceId: ${id}\n${findFile.content}\n`;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
9
28
|
const normalizedId = normalizePath(id);
|
|
10
29
|
const content = fs.readFileSync(normalizedId, "utf8");
|
|
11
30
|
const relativeId = toRelativePath(id);
|
|
@@ -17,7 +36,10 @@ export default function transformDetailDatasources({ sourceIds }) {
|
|
|
17
36
|
})
|
|
18
37
|
.filter(Boolean);
|
|
19
38
|
|
|
20
|
-
return {
|
|
39
|
+
return {
|
|
40
|
+
detailDataSources: contents.join(""),
|
|
41
|
+
openAPISpec,
|
|
42
|
+
};
|
|
21
43
|
}
|
|
22
44
|
|
|
23
45
|
transformDetailDatasources.task_render_mode = "hide";
|