@aigne/doc-smith 0.0.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/README.md +87 -0
- package/agents/batch-docs-detail-generator.yaml +14 -0
- package/agents/batch-translate.yaml +44 -0
- package/agents/check-detail-generated.mjs +128 -0
- package/agents/check-detail-result.mjs +141 -0
- package/agents/check-structure-planning-result.yaml +30 -0
- package/agents/check-structure-planning.mjs +54 -0
- package/agents/content-detail-generator.yaml +50 -0
- package/agents/detail-generator-and-translate.yaml +88 -0
- package/agents/detail-regenerator.yaml +107 -0
- package/agents/docs-generator.yaml +93 -0
- package/agents/format-structure-plan.mjs +23 -0
- package/agents/input-generator.mjs +142 -0
- package/agents/load-sources.mjs +329 -0
- package/agents/publish-docs.mjs +212 -0
- package/agents/reflective-structure-planner.yaml +10 -0
- package/agents/save-docs.mjs +153 -0
- package/agents/save-output.mjs +25 -0
- package/agents/save-single-doc.mjs +18 -0
- package/agents/schema/structure-plan-result.yaml +32 -0
- package/agents/schema/structure-plan.yaml +26 -0
- package/agents/structure-planning.yaml +49 -0
- package/agents/transform-detail-datasources.mjs +14 -0
- package/agents/translate.yaml +28 -0
- package/aigne.yaml +28 -0
- package/biome.json +51 -0
- package/docs-mcp/aigne.yaml +8 -0
- package/docs-mcp/get-docs-detail.mjs +42 -0
- package/docs-mcp/get-docs-structure.mjs +11 -0
- package/package.json +33 -0
- package/prompts/check-structure-planning-result.md +82 -0
- package/prompts/content-detail-generator.md +99 -0
- package/prompts/document/detail-example.md +441 -0
- package/prompts/document/detail-generator.md +95 -0
- package/prompts/document/structure-example.md +98 -0
- package/prompts/document/structure-getting-started.md +10 -0
- package/prompts/document/structure-planning.md +17 -0
- package/prompts/structure-planning.md +108 -0
- package/prompts/translator.md +69 -0
- package/tests/README.md +93 -0
- package/tests/check-detail-result.test.mjs +103 -0
- package/tests/load-sources.test.mjs +642 -0
- package/tests/test-save-docs.mjs +132 -0
- package/utils/utils.mjs +86 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { writeFile, mkdir, readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import saveDocs from "../agents/save-docs.mjs";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
async function testSaveDocs() {
|
|
10
|
+
// Create a temporary test directory
|
|
11
|
+
const testDir = join(__dirname, "test-docs");
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Create test directory
|
|
15
|
+
await mkdir(testDir, { recursive: true });
|
|
16
|
+
|
|
17
|
+
// Create some test files
|
|
18
|
+
const testFiles = [
|
|
19
|
+
"overview.md",
|
|
20
|
+
"getting-started.md",
|
|
21
|
+
"getting-started.zh.md",
|
|
22
|
+
"getting-started.en.md",
|
|
23
|
+
"old-file.md", // This should be deleted
|
|
24
|
+
"another-old-file.md", // This should be deleted
|
|
25
|
+
"old-translation.zh.md", // This should be deleted
|
|
26
|
+
"_sidebar.md", // This should be preserved
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
for (const file of testFiles) {
|
|
30
|
+
await writeFile(join(testDir, file), `# Test content for ${file}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log("Created test files:");
|
|
34
|
+
const files = await readdir(testDir);
|
|
35
|
+
console.log(files);
|
|
36
|
+
|
|
37
|
+
// Test structure plan
|
|
38
|
+
const structurePlan = [
|
|
39
|
+
{
|
|
40
|
+
path: "/overview",
|
|
41
|
+
title: "Overview",
|
|
42
|
+
description: "Overview page",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
path: "/getting-started",
|
|
46
|
+
title: "Getting Started",
|
|
47
|
+
description: "Getting started guide",
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
// Test with translation languages
|
|
52
|
+
const translateLanguages = ["zh", "en"];
|
|
53
|
+
|
|
54
|
+
console.log("\nRunning saveDocs with cleanup...");
|
|
55
|
+
const result = await saveDocs({
|
|
56
|
+
structurePlanResult: structurePlan,
|
|
57
|
+
docsDir: testDir,
|
|
58
|
+
translateLanguages,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.log("\nSaveDocs result:");
|
|
62
|
+
console.log(JSON.stringify(result, null, 2));
|
|
63
|
+
|
|
64
|
+
console.log("\nFiles after cleanup:");
|
|
65
|
+
const remainingFiles = await readdir(testDir);
|
|
66
|
+
console.log(remainingFiles);
|
|
67
|
+
|
|
68
|
+
// Expected files after cleanup:
|
|
69
|
+
// - overview.md (existing)
|
|
70
|
+
// - getting-started.md (existing)
|
|
71
|
+
// - getting-started.zh.md (existing)
|
|
72
|
+
// - getting-started.en.md (existing)
|
|
73
|
+
// - _sidebar.md (generated)
|
|
74
|
+
// Note: overview.zh.md and overview.en.md are not created by saveDocs,
|
|
75
|
+
// they would be created by saveDocWithTranslations when content is generated
|
|
76
|
+
const expectedFiles = [
|
|
77
|
+
"overview.md",
|
|
78
|
+
"getting-started.md",
|
|
79
|
+
"getting-started.zh.md",
|
|
80
|
+
"getting-started.en.md",
|
|
81
|
+
"_sidebar.md",
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
const missingFiles = expectedFiles.filter(
|
|
85
|
+
(file) => !remainingFiles.includes(file)
|
|
86
|
+
);
|
|
87
|
+
const extraFiles = remainingFiles.filter(
|
|
88
|
+
(file) => !expectedFiles.includes(file)
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (missingFiles.length === 0 && extraFiles.length === 0) {
|
|
92
|
+
console.log("\n✅ Test passed! All files are as expected.");
|
|
93
|
+
} else {
|
|
94
|
+
console.log("\n❌ Test failed!");
|
|
95
|
+
if (missingFiles.length > 0) {
|
|
96
|
+
console.log("Missing files:", missingFiles);
|
|
97
|
+
}
|
|
98
|
+
if (extraFiles.length > 0) {
|
|
99
|
+
console.log("Extra files:", extraFiles);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Verify that invalid files were deleted
|
|
104
|
+
const deletedFiles = [
|
|
105
|
+
"old-file.md",
|
|
106
|
+
"another-old-file.md",
|
|
107
|
+
"old-translation.zh.md",
|
|
108
|
+
];
|
|
109
|
+
const stillExist = deletedFiles.filter((file) =>
|
|
110
|
+
remainingFiles.includes(file)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (stillExist.length === 0) {
|
|
114
|
+
console.log("✅ All invalid files were successfully deleted.");
|
|
115
|
+
} else {
|
|
116
|
+
console.log("❌ Some invalid files still exist:", stillExist);
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error("Test failed with error:", error);
|
|
120
|
+
} finally {
|
|
121
|
+
// Clean up test directory
|
|
122
|
+
try {
|
|
123
|
+
const { rm } = await import("node:fs/promises");
|
|
124
|
+
await rm(testDir, { recursive: true, force: true });
|
|
125
|
+
console.log("\nCleaned up test directory");
|
|
126
|
+
} catch (err) {
|
|
127
|
+
console.log("Failed to clean up test directory:", err.message);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
testSaveDocs();
|
package/utils/utils.mjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export function processContent({ content }) {
|
|
5
|
+
// Match markdown regular links [text](link), exclude images 
|
|
6
|
+
return content.replace(
|
|
7
|
+
/(?<!!)\[([^\]]+)\]\(([^)]+)\)/g,
|
|
8
|
+
(match, text, link) => {
|
|
9
|
+
const trimLink = link.trim();
|
|
10
|
+
// Exclude external links and mailto
|
|
11
|
+
if (/^(https?:\/\/|mailto:)/.test(trimLink)) return match;
|
|
12
|
+
// Preserve anchors
|
|
13
|
+
const [path, hash] = trimLink.split("#");
|
|
14
|
+
// Skip if already has extension
|
|
15
|
+
if (/\.[a-zA-Z0-9]+$/.test(path)) return match;
|
|
16
|
+
// Only process relative paths or paths starting with /
|
|
17
|
+
if (!path) return match;
|
|
18
|
+
// Flatten to ./xxx-yyy.md
|
|
19
|
+
let finalPath = path;
|
|
20
|
+
if (path.startsWith(".")) {
|
|
21
|
+
finalPath = path.replace(/^\./, "");
|
|
22
|
+
}
|
|
23
|
+
let flatPath = finalPath.replace(/^\//, "").replace(/\//g, "-");
|
|
24
|
+
flatPath = `./${flatPath}.md`;
|
|
25
|
+
const newLink = hash ? `${flatPath}#${hash}` : flatPath;
|
|
26
|
+
return `[${text}](${newLink})`;
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Save a single document and its translations to files
|
|
33
|
+
* @param {Object} params
|
|
34
|
+
* @param {string} params.path - Relative path (without extension)
|
|
35
|
+
* @param {string} params.content - Main document content
|
|
36
|
+
* @param {string} params.docsDir - Root directory
|
|
37
|
+
* @param {Array<{language: string, translation: string}>} [params.translates] - Translation content
|
|
38
|
+
* @param {Array<string>} [params.labels] - Document labels for front matter
|
|
39
|
+
* @returns {Promise<Array<{ path: string, success: boolean, error?: string }>>}
|
|
40
|
+
*/
|
|
41
|
+
export async function saveDocWithTranslations({
|
|
42
|
+
path: docPath,
|
|
43
|
+
content,
|
|
44
|
+
docsDir,
|
|
45
|
+
translates = [],
|
|
46
|
+
labels,
|
|
47
|
+
}) {
|
|
48
|
+
const results = [];
|
|
49
|
+
try {
|
|
50
|
+
// Flatten path: remove leading /, replace all / with -
|
|
51
|
+
const flatName = docPath.replace(/^\//, "").replace(/\//g, "-");
|
|
52
|
+
const fileFullName = `${flatName}.md`;
|
|
53
|
+
const filePath = path.join(docsDir, fileFullName);
|
|
54
|
+
await fs.mkdir(docsDir, { recursive: true });
|
|
55
|
+
|
|
56
|
+
// Add labels front matter if labels are provided
|
|
57
|
+
let finalContent = processContent({ content });
|
|
58
|
+
if (labels && labels.length > 0) {
|
|
59
|
+
const frontMatter = `---\nlabels: ${JSON.stringify(labels)}\n---\n\n`;
|
|
60
|
+
finalContent = frontMatter + finalContent;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await fs.writeFile(filePath, finalContent, "utf8");
|
|
64
|
+
results.push({ path: filePath, success: true });
|
|
65
|
+
|
|
66
|
+
for (const translate of translates) {
|
|
67
|
+
const translateFileName = `${flatName}.${translate.language}.md`;
|
|
68
|
+
const translatePath = path.join(docsDir, translateFileName);
|
|
69
|
+
|
|
70
|
+
// Add labels front matter to translation content if labels are provided
|
|
71
|
+
let finalTranslationContent = processContent({
|
|
72
|
+
content: translate.translation,
|
|
73
|
+
});
|
|
74
|
+
if (labels && labels.length > 0) {
|
|
75
|
+
const frontMatter = `---\nlabels: ${JSON.stringify(labels)}\n---\n\n`;
|
|
76
|
+
finalTranslationContent = frontMatter + finalTranslationContent;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await fs.writeFile(translatePath, finalTranslationContent, "utf8");
|
|
80
|
+
results.push({ path: translatePath, success: true });
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
results.push({ path: docPath, success: false, error: err.message });
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|