@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.
Files changed (44) hide show
  1. package/README.md +87 -0
  2. package/agents/batch-docs-detail-generator.yaml +14 -0
  3. package/agents/batch-translate.yaml +44 -0
  4. package/agents/check-detail-generated.mjs +128 -0
  5. package/agents/check-detail-result.mjs +141 -0
  6. package/agents/check-structure-planning-result.yaml +30 -0
  7. package/agents/check-structure-planning.mjs +54 -0
  8. package/agents/content-detail-generator.yaml +50 -0
  9. package/agents/detail-generator-and-translate.yaml +88 -0
  10. package/agents/detail-regenerator.yaml +107 -0
  11. package/agents/docs-generator.yaml +93 -0
  12. package/agents/format-structure-plan.mjs +23 -0
  13. package/agents/input-generator.mjs +142 -0
  14. package/agents/load-sources.mjs +329 -0
  15. package/agents/publish-docs.mjs +212 -0
  16. package/agents/reflective-structure-planner.yaml +10 -0
  17. package/agents/save-docs.mjs +153 -0
  18. package/agents/save-output.mjs +25 -0
  19. package/agents/save-single-doc.mjs +18 -0
  20. package/agents/schema/structure-plan-result.yaml +32 -0
  21. package/agents/schema/structure-plan.yaml +26 -0
  22. package/agents/structure-planning.yaml +49 -0
  23. package/agents/transform-detail-datasources.mjs +14 -0
  24. package/agents/translate.yaml +28 -0
  25. package/aigne.yaml +28 -0
  26. package/biome.json +51 -0
  27. package/docs-mcp/aigne.yaml +8 -0
  28. package/docs-mcp/get-docs-detail.mjs +42 -0
  29. package/docs-mcp/get-docs-structure.mjs +11 -0
  30. package/package.json +33 -0
  31. package/prompts/check-structure-planning-result.md +82 -0
  32. package/prompts/content-detail-generator.md +99 -0
  33. package/prompts/document/detail-example.md +441 -0
  34. package/prompts/document/detail-generator.md +95 -0
  35. package/prompts/document/structure-example.md +98 -0
  36. package/prompts/document/structure-getting-started.md +10 -0
  37. package/prompts/document/structure-planning.md +17 -0
  38. package/prompts/structure-planning.md +108 -0
  39. package/prompts/translator.md +69 -0
  40. package/tests/README.md +93 -0
  41. package/tests/check-detail-result.test.mjs +103 -0
  42. package/tests/load-sources.test.mjs +642 -0
  43. package/tests/test-save-docs.mjs +132 -0
  44. 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();
@@ -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 ![text](link)
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
+ }