@aigne/doc-smith 0.8.11-beta → 0.8.11-beta.2
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/.aigne/doc-smith/config.yaml +2 -0
- package/.aigne/doc-smith/output/structure-plan.json +3 -3
- package/.aigne/doc-smith/upload-cache.yaml +252 -0
- package/.github/workflows/publish-docs.yml +67 -0
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +22 -0
- package/README.md +45 -115
- package/agents/clear/choose-contents.mjs +170 -0
- package/agents/clear/clear-auth-tokens.mjs +111 -0
- package/agents/clear/clear-document-config.mjs +39 -0
- package/agents/clear/clear-document-structure.mjs +106 -0
- package/agents/clear/clear-generated-docs.mjs +51 -0
- package/agents/clear/index.yaml +23 -0
- package/agents/evaluate/code-snippet.mjs +93 -0
- package/agents/evaluate/document-structure.yaml +70 -0
- package/agents/evaluate/document.yaml +79 -0
- package/agents/evaluate/generate-report.mjs +78 -0
- package/agents/evaluate/index.yaml +39 -0
- package/agents/generate/document-structure-tools/add-document.mjs +56 -0
- package/agents/generate/document-structure-tools/delete-document.mjs +49 -0
- package/agents/generate/document-structure-tools/move-document.mjs +82 -0
- package/agents/generate/document-structure-tools/update-document.mjs +50 -0
- package/agents/generate/generate-structure.yaml +1 -1
- package/agents/generate/update-document-structure.yaml +42 -0
- package/agents/generate/user-review-document-structure.mjs +6 -4
- package/agents/init/index.mjs +1 -1
- package/agents/publish/publish-docs.mjs +12 -3
- package/agents/translate/choose-language.mjs +1 -1
- package/agents/update/batch-update-document.yaml +7 -0
- package/agents/update/check-update-is-single.mjs +38 -0
- package/agents/update/document-tools/update-document-content.mjs +293 -0
- package/agents/update/index.yaml +4 -10
- package/agents/update/update-document-detail.yaml +52 -0
- package/agents/update/update-single-document.yaml +15 -0
- package/agents/update/user-review-document.mjs +248 -0
- package/agents/utils/choose-docs.mjs +4 -2
- package/agents/utils/format-document-structure.mjs +12 -2
- package/agents/utils/load-document-all-content.mjs +84 -0
- package/agents/utils/load-sources.mjs +4 -1
- package/aigne.yaml +59 -20
- package/assets/report-template/report.html +198 -0
- package/biome.json +14 -2
- package/docs/advanced-how-it-works.ja.md +101 -0
- package/docs/advanced-how-it-works.zh-TW.md +101 -0
- package/docs/advanced-how-it-works.zh.md +20 -20
- package/docs/advanced-quality-assurance.ja.md +96 -0
- package/docs/advanced-quality-assurance.zh-TW.md +96 -0
- package/docs/advanced-quality-assurance.zh.md +18 -18
- package/docs/advanced.ja.md +16 -0
- package/docs/advanced.zh-TW.md +16 -0
- package/docs/advanced.zh.md +4 -4
- package/docs/changelog.ja.md +309 -0
- package/docs/changelog.zh-TW.md +309 -0
- package/docs/changelog.zh.md +23 -23
- package/docs/cli-reference.ja.md +210 -0
- package/docs/cli-reference.zh-TW.md +210 -0
- package/docs/cli-reference.zh.md +21 -21
- package/docs/configuration-interactive-setup.ja.md +135 -0
- package/docs/configuration-interactive-setup.zh-TW.md +135 -0
- package/docs/configuration-interactive-setup.zh.md +29 -29
- package/docs/configuration-language-support.ja.md +94 -0
- package/docs/configuration-language-support.zh-TW.md +94 -0
- package/docs/configuration-language-support.zh.md +13 -13
- package/docs/configuration-llm-setup.ja.md +54 -0
- package/docs/configuration-llm-setup.zh-TW.md +54 -0
- package/docs/configuration-llm-setup.zh.md +12 -12
- package/docs/configuration-preferences.ja.md +129 -0
- package/docs/configuration-preferences.zh-TW.md +129 -0
- package/docs/configuration-preferences.zh.md +36 -36
- package/docs/configuration.ja.md +172 -0
- package/docs/configuration.zh-TW.md +172 -0
- package/docs/configuration.zh.md +49 -49
- package/docs/features-generate-documentation.ja.md +101 -0
- package/docs/features-generate-documentation.zh-TW.md +101 -0
- package/docs/features-generate-documentation.zh.md +17 -17
- package/docs/features-publish-your-docs.ja.md +107 -0
- package/docs/features-publish-your-docs.zh-TW.md +107 -0
- package/docs/features-publish-your-docs.zh.md +22 -22
- package/docs/features-translate-documentation.ja.md +79 -0
- package/docs/features-translate-documentation.zh-TW.md +79 -0
- package/docs/features-translate-documentation.zh.md +12 -12
- package/docs/features-update-and-refine.ja.md +138 -0
- package/docs/features-update-and-refine.zh-TW.md +138 -0
- package/docs/features-update-and-refine.zh.md +21 -21
- package/docs/features.ja.md +52 -0
- package/docs/features.zh-TW.md +52 -0
- package/docs/features.zh.md +8 -8
- package/docs/getting-started.ja.md +123 -0
- package/docs/getting-started.zh-TW.md +123 -0
- package/docs/getting-started.zh.md +24 -24
- package/docs/overview.ja.md +30 -0
- package/docs/overview.zh-TW.md +30 -0
- package/docs/overview.zh.md +8 -8
- package/package.json +19 -11
- package/prompts/common/document/content-rules-core.md +19 -0
- package/prompts/common/document/media-handling-rules.md +9 -0
- package/prompts/common/document/role-and-personality.md +15 -0
- package/prompts/common/document/user-preferences.md +9 -0
- package/prompts/common/document-structure/conflict-resolution-guidance.md +16 -0
- package/prompts/common/document-structure/document-structure-rules.md +45 -0
- package/prompts/common/document-structure/glossary.md +7 -0
- package/prompts/common/document-structure/intj-traits.md +5 -0
- package/prompts/common/document-structure/output-constraints.md +9 -0
- package/prompts/common/document-structure/user-locale-rules.md +10 -0
- package/prompts/common/document-structure/user-preferences.md +9 -0
- package/prompts/detail/custom/custom-components.md +9 -1
- package/prompts/detail/document-rules.md +6 -6
- package/prompts/detail/generate-document.md +5 -45
- package/prompts/detail/update-document.md +145 -0
- package/prompts/evaluate/document-structure.md +94 -0
- package/prompts/evaluate/document.md +149 -0
- package/prompts/structure/document-rules.md +1 -1
- package/prompts/structure/generate-structure-system.md +74 -0
- package/prompts/structure/generate-structure-user.md +41 -0
- package/prompts/structure/update-document-structure.md +118 -0
- package/prompts/translate/translate-document.md +1 -1
- package/prompts/utils/feedback-refiner.md +3 -3
- package/release-please-config.json +1 -7
- package/tests/agents/clear/choose-contents.test.mjs +280 -0
- package/tests/agents/clear/clear-auth-tokens.test.mjs +268 -0
- package/tests/agents/clear/clear-document-config.test.mjs +167 -0
- package/tests/agents/clear/clear-document-structure.test.mjs +374 -0
- package/tests/agents/clear/clear-generated-docs.test.mjs +222 -0
- package/tests/agents/evaluate/code-snippet.test.mjs +163 -0
- package/tests/agents/evaluate/fixtures/api-services.md +87 -0
- package/tests/agents/evaluate/fixtures/js-sdk.md +94 -0
- package/tests/agents/evaluate/generate-report.test.mjs +312 -0
- package/tests/agents/generate/check-document-structure.test.mjs +0 -6
- package/tests/agents/generate/document-structure-tools/add-document.test.mjs +449 -0
- package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +410 -0
- package/tests/agents/generate/document-structure-tools/move-document.test.mjs +476 -0
- package/tests/agents/generate/document-structure-tools/update-document.test.mjs +548 -0
- package/tests/agents/generate/generate-structure.test.mjs +0 -6
- package/tests/agents/generate/user-review-document-structure.test.mjs +9 -9
- package/tests/agents/publish/publish-docs.test.mjs +2 -2
- package/tests/agents/update/check-update-is-single.test.mjs +300 -0
- package/tests/agents/update/document-tools/update-document-content.test.mjs +326 -0
- package/tests/agents/update/user-review-document.test.mjs +561 -0
- package/tests/agents/utils/format-document-structure.test.mjs +100 -0
- package/tests/utils/auth-utils.test.mjs +239 -1
- package/tests/utils/blocklet.test.mjs +9 -7
- package/tests/utils/constants.test.mjs +1 -1
- package/tests/utils/d2-utils.test.mjs +1 -1
- package/tests/utils/deploy.test.mjs +310 -366
- package/tests/utils/kroki-utils.test.mjs +2 -15
- package/tests/utils/linter/fixtures/css/keyword-error.css +1 -0
- package/tests/utils/linter/fixtures/css/missing-semicolon.css +1 -0
- package/tests/utils/linter/fixtures/css/syntax-error.css +1 -0
- package/tests/utils/linter/fixtures/css/undeclare-variable.css +1 -0
- package/tests/utils/linter/fixtures/css/unused-variable.css +2 -0
- package/tests/utils/linter/fixtures/css/valid-code.css +1 -0
- package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +1 -0
- package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +2 -0
- package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +2 -0
- package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +1 -0
- package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +1 -0
- package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +2 -0
- package/tests/utils/linter/fixtures/go/keyword-error.go +5 -0
- package/tests/utils/linter/fixtures/go/missing-semicolon.go +5 -0
- package/tests/utils/linter/fixtures/go/syntax-error.go +6 -0
- package/tests/utils/linter/fixtures/go/undeclare-variable.go +5 -0
- package/tests/utils/linter/fixtures/go/unused-variable.go +5 -0
- package/tests/utils/linter/fixtures/go/valid-code.go +7 -0
- package/tests/utils/linter/fixtures/js/keyword-error.js +3 -0
- package/tests/utils/linter/fixtures/js/missing-semicolon.js +6 -0
- package/tests/utils/linter/fixtures/js/syntax-error.js +4 -0
- package/tests/utils/linter/fixtures/js/undeclare-variable.js +3 -0
- package/tests/utils/linter/fixtures/js/unused-variable.js +7 -0
- package/tests/utils/linter/fixtures/js/valid-code.js +15 -0
- package/tests/utils/linter/fixtures/json/keyword-error.json +1 -0
- package/tests/utils/linter/fixtures/json/missing-semicolon.json +1 -0
- package/tests/utils/linter/fixtures/json/syntax-error.json +1 -0
- package/tests/utils/linter/fixtures/json/undeclare-variable.json +1 -0
- package/tests/utils/linter/fixtures/json/unused-variable.json +1 -0
- package/tests/utils/linter/fixtures/json/valid-code.json +1 -0
- package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +5 -0
- package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +5 -0
- package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +5 -0
- package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +5 -0
- package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +4 -0
- package/tests/utils/linter/fixtures/jsx/valid-code.jsx +5 -0
- package/tests/utils/linter/fixtures/python/keyword-error.py +3 -0
- package/tests/utils/linter/fixtures/python/missing-semicolon.py +2 -0
- package/tests/utils/linter/fixtures/python/syntax-error.py +3 -0
- package/tests/utils/linter/fixtures/python/undeclare-variable.py +3 -0
- package/tests/utils/linter/fixtures/python/unused-variable.py +6 -0
- package/tests/utils/linter/fixtures/python/valid-code.py +12 -0
- package/tests/utils/linter/fixtures/ruby/keyword-error.rb +2 -0
- package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +1 -0
- package/tests/utils/linter/fixtures/ruby/syntax-error.rb +2 -0
- package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +1 -0
- package/tests/utils/linter/fixtures/ruby/unused-variable.rb +2 -0
- package/tests/utils/linter/fixtures/ruby/valid-code.rb +1 -0
- package/tests/utils/linter/fixtures/sass/keyword-error.sass +2 -0
- package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +3 -0
- package/tests/utils/linter/fixtures/sass/syntax-error.sass +3 -0
- package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +2 -0
- package/tests/utils/linter/fixtures/sass/unused-variable.sass +4 -0
- package/tests/utils/linter/fixtures/sass/valid-code.sass +2 -0
- package/tests/utils/linter/fixtures/scss/keyword-error.scss +1 -0
- package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +1 -0
- package/tests/utils/linter/fixtures/scss/syntax-error.scss +1 -0
- package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +1 -0
- package/tests/utils/linter/fixtures/scss/unused-variable.scss +2 -0
- package/tests/utils/linter/fixtures/scss/valid-code.scss +1 -0
- package/tests/utils/linter/fixtures/shell/keyword-error.sh +5 -0
- package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +3 -0
- package/tests/utils/linter/fixtures/shell/syntax-error.sh +4 -0
- package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +3 -0
- package/tests/utils/linter/fixtures/shell/unused-variable.sh +4 -0
- package/tests/utils/linter/fixtures/shell/valid-code.sh +3 -0
- package/tests/utils/linter/fixtures/ts/keyword-error.ts +1 -0
- package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +1 -0
- package/tests/utils/linter/fixtures/ts/syntax-error.ts +1 -0
- package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +1 -0
- package/tests/utils/linter/fixtures/ts/unused-variable.ts +3 -0
- package/tests/utils/linter/fixtures/ts/valid-code.ts +3 -0
- package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +5 -0
- package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +5 -0
- package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +5 -0
- package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +6 -0
- package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +6 -0
- package/tests/utils/linter/fixtures/tsx/valid-code.tsx +5 -0
- package/tests/utils/linter/fixtures/vue/keyword-error.vue +6 -0
- package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +6 -0
- package/tests/utils/linter/fixtures/vue/syntax-error.vue +6 -0
- package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +6 -0
- package/tests/utils/linter/fixtures/vue/unused-variable.vue +7 -0
- package/tests/utils/linter/fixtures/vue/valid-code.vue +6 -0
- package/tests/utils/linter/fixtures/yaml/keyword-error.yml +1 -0
- package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +2 -0
- package/tests/utils/linter/fixtures/yaml/syntax-error.yml +1 -0
- package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +1 -0
- package/tests/utils/linter/fixtures/yaml/unused-variable.yml +2 -0
- package/tests/utils/linter/fixtures/yaml/valid-code.yml +3 -0
- package/tests/utils/linter/index.test.mjs +440 -0
- package/tests/utils/linter/scan-results.mjs +42 -0
- package/tests/utils/markdown/index.test.mjs +478 -0
- package/tests/utils/mermaid-validator.test.mjs +2 -2
- package/tests/utils/utils.test.mjs +3 -1
- package/types/document-schema.mjs +54 -0
- package/types/document-structure-schema.mjs +244 -0
- package/utils/auth-utils.mjs +131 -6
- package/utils/conflict-detector.mjs +5 -1
- package/utils/{constants.mjs → constants/index.mjs} +109 -0
- package/utils/constants/linter.mjs +102 -0
- package/utils/d2-utils.mjs +2 -4
- package/utils/debug.mjs +3 -0
- package/utils/deploy.mjs +81 -385
- package/utils/evaluate/report-utils.mjs +131 -0
- package/utils/file-utils.mjs +36 -1
- package/utils/kroki-utils.mjs +1 -1
- package/utils/linter/index.mjs +50 -0
- package/utils/markdown/index.mjs +26 -0
- package/utils/markdown-checker.mjs +1 -1
- package/utils/utils.mjs +19 -7
- package/prompts/structure/generate-structure.md +0 -161
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
import * as fsPromises from "node:fs/promises";
|
|
3
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import clearDocumentConfig from "../../../agents/clear/clear-document-config.mjs";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
describe("clear-document-config", () => {
|
|
11
|
+
let testDir;
|
|
12
|
+
let configPath;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
// Create a temporary test directory
|
|
16
|
+
testDir = join(__dirname, "test-clear-config");
|
|
17
|
+
await mkdir(testDir, { recursive: true });
|
|
18
|
+
|
|
19
|
+
// Create .aigne/doc-smith directory structure
|
|
20
|
+
const aigneDir = join(testDir, ".aigne", "doc-smith");
|
|
21
|
+
await mkdir(aigneDir, { recursive: true });
|
|
22
|
+
|
|
23
|
+
configPath = join(aigneDir, "config.yaml");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(async () => {
|
|
27
|
+
// Clean up test directory
|
|
28
|
+
try {
|
|
29
|
+
await rm(testDir, { recursive: true, force: true });
|
|
30
|
+
} catch {
|
|
31
|
+
// Ignore cleanup errors since they don't affect test results
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("should clear existing document configuration successfully", async () => {
|
|
36
|
+
// Create a test config file
|
|
37
|
+
const configContent = `
|
|
38
|
+
projectName: "Test Project"
|
|
39
|
+
projectDesc: "Test Description"
|
|
40
|
+
locale: "en"
|
|
41
|
+
documentPurpose: ["API", "Tutorial"]
|
|
42
|
+
`;
|
|
43
|
+
await writeFile(configPath, configContent);
|
|
44
|
+
|
|
45
|
+
const result = await clearDocumentConfig({ workDir: testDir });
|
|
46
|
+
|
|
47
|
+
expect(result.cleared).toBe(true);
|
|
48
|
+
expect(result.message).toContain("Cleared document configuration");
|
|
49
|
+
expect(result.path).toBeDefined();
|
|
50
|
+
expect(result.suggestions).toEqual([
|
|
51
|
+
"Run `aigne doc init` to generate a fresh configuration file.",
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
// Verify file is actually deleted
|
|
55
|
+
const { pathExists } = await import("../../../utils/file-utils.mjs");
|
|
56
|
+
const exists = await pathExists(configPath);
|
|
57
|
+
expect(exists).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("should handle non-existent configuration file", async () => {
|
|
61
|
+
// Don't create the config file
|
|
62
|
+
const result = await clearDocumentConfig({ workDir: testDir });
|
|
63
|
+
|
|
64
|
+
expect(result.cleared).toBe(false);
|
|
65
|
+
expect(result.message).toContain("Document configuration already empty");
|
|
66
|
+
expect(result.path).toBeDefined();
|
|
67
|
+
expect(result.suggestions).toEqual([]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("should use current working directory when workDir not provided", async () => {
|
|
71
|
+
const originalCwd = process.cwd();
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// Change to test directory
|
|
75
|
+
process.chdir(testDir);
|
|
76
|
+
|
|
77
|
+
// Create config in current directory's .aigne structure
|
|
78
|
+
await writeFile(configPath, "test: content");
|
|
79
|
+
|
|
80
|
+
const result = await clearDocumentConfig({});
|
|
81
|
+
|
|
82
|
+
expect(result.cleared).toBe(true);
|
|
83
|
+
expect(result.message).toContain("Cleared document configuration");
|
|
84
|
+
} finally {
|
|
85
|
+
// Restore original working directory
|
|
86
|
+
process.chdir(originalCwd);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("should provide correct return structure", async () => {
|
|
91
|
+
await writeFile(configPath, "test: content");
|
|
92
|
+
|
|
93
|
+
const result = await clearDocumentConfig({ workDir: testDir });
|
|
94
|
+
|
|
95
|
+
expect(result).toHaveProperty("message");
|
|
96
|
+
expect(result).toHaveProperty("cleared");
|
|
97
|
+
expect(result).toHaveProperty("path");
|
|
98
|
+
expect(result).toHaveProperty("suggestions");
|
|
99
|
+
expect(typeof result.message).toBe("string");
|
|
100
|
+
expect(typeof result.cleared).toBe("boolean");
|
|
101
|
+
expect(typeof result.path).toBe("string");
|
|
102
|
+
expect(Array.isArray(result.suggestions)).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("should have correct task metadata", () => {
|
|
106
|
+
expect(clearDocumentConfig.taskTitle).toBe("Clear document configuration");
|
|
107
|
+
expect(clearDocumentConfig.description).toBe("Clear the document configuration file");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("should handle nested directory structures", async () => {
|
|
111
|
+
// Create nested test directory
|
|
112
|
+
const nestedDir = join(testDir, "nested", "project");
|
|
113
|
+
await mkdir(nestedDir, { recursive: true });
|
|
114
|
+
|
|
115
|
+
const nestedAigneDir = join(nestedDir, ".aigne", "doc-smith");
|
|
116
|
+
await mkdir(nestedAigneDir, { recursive: true });
|
|
117
|
+
|
|
118
|
+
const nestedConfigPath = join(nestedAigneDir, "config.yaml");
|
|
119
|
+
await writeFile(nestedConfigPath, "nested: config");
|
|
120
|
+
|
|
121
|
+
const result = await clearDocumentConfig({ workDir: nestedDir });
|
|
122
|
+
|
|
123
|
+
expect(result.cleared).toBe(true);
|
|
124
|
+
expect(result.message).toContain("Cleared document configuration");
|
|
125
|
+
|
|
126
|
+
// Verify nested file is deleted
|
|
127
|
+
const { pathExists } = await import("../../../utils/file-utils.mjs");
|
|
128
|
+
const exists = await pathExists(nestedConfigPath);
|
|
129
|
+
expect(exists).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("should handle path with special characters", async () => {
|
|
133
|
+
// Create directory with spaces and special characters
|
|
134
|
+
const specialDir = join(testDir, "special dir-with_chars");
|
|
135
|
+
await mkdir(specialDir, { recursive: true });
|
|
136
|
+
|
|
137
|
+
const specialAigneDir = join(specialDir, ".aigne", "doc-smith");
|
|
138
|
+
await mkdir(specialAigneDir, { recursive: true });
|
|
139
|
+
|
|
140
|
+
const specialConfigPath = join(specialAigneDir, "config.yaml");
|
|
141
|
+
await writeFile(specialConfigPath, "special: config");
|
|
142
|
+
|
|
143
|
+
const result = await clearDocumentConfig({ workDir: specialDir });
|
|
144
|
+
|
|
145
|
+
expect(result.cleared).toBe(true);
|
|
146
|
+
expect(result.message).toContain("Cleared document configuration");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("should handle file system errors gracefully", async () => {
|
|
150
|
+
// Create a spy on rm to simulate an error
|
|
151
|
+
const rmSpy = spyOn(fsPromises, "rm");
|
|
152
|
+
rmSpy.mockImplementation(() => {
|
|
153
|
+
throw new Error("Permission denied");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const result = await clearDocumentConfig({ workDir: testDir });
|
|
158
|
+
|
|
159
|
+
expect(result.error).toBe(true);
|
|
160
|
+
expect(result.message).toContain("Failed to clear document configuration");
|
|
161
|
+
expect(result.message).toContain("Permission denied");
|
|
162
|
+
expect(result.path).toBeDefined();
|
|
163
|
+
} finally {
|
|
164
|
+
rmSpy.mockRestore();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
import * as fsPromises from "node:fs/promises";
|
|
3
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import clearDocumentStructure from "../../../agents/clear/clear-document-structure.mjs";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
describe("clear-document-structure", () => {
|
|
11
|
+
let testDir;
|
|
12
|
+
let structurePlanPath;
|
|
13
|
+
let docsDir;
|
|
14
|
+
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
// Create a temporary test directory
|
|
17
|
+
testDir = join(__dirname, "test-clear-structure");
|
|
18
|
+
await mkdir(testDir, { recursive: true });
|
|
19
|
+
|
|
20
|
+
// Create .aigne/doc-smith/output directory structure
|
|
21
|
+
const outputDir = join(testDir, ".aigne", "doc-smith", "output");
|
|
22
|
+
await mkdir(outputDir, { recursive: true });
|
|
23
|
+
|
|
24
|
+
structurePlanPath = join(outputDir, "structure-plan.json");
|
|
25
|
+
docsDir = join(testDir, "docs");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(async () => {
|
|
29
|
+
// Clean up test directory
|
|
30
|
+
try {
|
|
31
|
+
await rm(testDir, { recursive: true, force: true });
|
|
32
|
+
} catch {
|
|
33
|
+
// Ignore cleanup errors since they don't affect test results
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("should clear structure plan only when no docsDir provided", async () => {
|
|
38
|
+
// Create a test structure plan file
|
|
39
|
+
const structurePlan = {
|
|
40
|
+
documents: [
|
|
41
|
+
{ path: "/intro", title: "Introduction" },
|
|
42
|
+
{ path: "/guide", title: "User Guide" },
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
await writeFile(structurePlanPath, JSON.stringify(structurePlan, null, 2));
|
|
46
|
+
|
|
47
|
+
const result = await clearDocumentStructure({ workDir: testDir });
|
|
48
|
+
|
|
49
|
+
expect(result.message).toContain("Document structure cleared successfully!");
|
|
50
|
+
expect(result.hasError).toBe(false);
|
|
51
|
+
expect(result.clearedCount).toBe(1);
|
|
52
|
+
|
|
53
|
+
// Verify structure plan file is actually deleted
|
|
54
|
+
const { pathExists } = await import("../../../utils/file-utils.mjs");
|
|
55
|
+
const exists = await pathExists(structurePlanPath);
|
|
56
|
+
expect(exists).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("should clear both structure plan and docs directory when docsDir provided", async () => {
|
|
60
|
+
// Create structure plan
|
|
61
|
+
await writeFile(structurePlanPath, JSON.stringify({ test: "data" }));
|
|
62
|
+
|
|
63
|
+
// Create docs directory with files
|
|
64
|
+
await mkdir(docsDir, { recursive: true });
|
|
65
|
+
await writeFile(join(docsDir, "index.md"), "# Index");
|
|
66
|
+
await writeFile(join(docsDir, "guide.md"), "# Guide");
|
|
67
|
+
|
|
68
|
+
const result = await clearDocumentStructure({ workDir: testDir, docsDir });
|
|
69
|
+
|
|
70
|
+
expect(result.message).toContain("Document structure cleared successfully!");
|
|
71
|
+
expect(result.clearedCount).toBe(2);
|
|
72
|
+
|
|
73
|
+
// Verify both are deleted
|
|
74
|
+
const { pathExists } = await import("../../../utils/file-utils.mjs");
|
|
75
|
+
const structureExists = await pathExists(structurePlanPath);
|
|
76
|
+
const docsExists = await pathExists(docsDir);
|
|
77
|
+
expect(structureExists).toBe(false);
|
|
78
|
+
expect(docsExists).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("should handle non-existent structure plan file", async () => {
|
|
82
|
+
// Don't create the structure plan file
|
|
83
|
+
const result = await clearDocumentStructure({ workDir: testDir });
|
|
84
|
+
|
|
85
|
+
expect(result.message).toContain("Document structure already empty.");
|
|
86
|
+
expect(result.clearedCount).toBe(0);
|
|
87
|
+
expect(result.hasError).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("should handle non-existent docs directory", async () => {
|
|
91
|
+
// Create structure plan but not docs directory
|
|
92
|
+
await writeFile(structurePlanPath, JSON.stringify({ test: "data" }));
|
|
93
|
+
|
|
94
|
+
const nonExistentDocsDir = join(testDir, "non-existent-docs");
|
|
95
|
+
|
|
96
|
+
const result = await clearDocumentStructure({
|
|
97
|
+
workDir: testDir,
|
|
98
|
+
docsDir: nonExistentDocsDir,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(result.message).toContain("Document structure cleared successfully!");
|
|
102
|
+
expect(result.clearedCount).toBe(1); // Only structure plan cleared
|
|
103
|
+
|
|
104
|
+
// Verify structure plan is deleted
|
|
105
|
+
const { pathExists } = await import("../../../utils/file-utils.mjs");
|
|
106
|
+
const exists = await pathExists(structurePlanPath);
|
|
107
|
+
expect(exists).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("should use current working directory when workDir not provided", async () => {
|
|
111
|
+
const originalCwd = process.cwd();
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// Change to test directory
|
|
115
|
+
process.chdir(testDir);
|
|
116
|
+
|
|
117
|
+
// Create structure plan in current directory's structure
|
|
118
|
+
await writeFile(structurePlanPath, JSON.stringify({ test: "data" }));
|
|
119
|
+
|
|
120
|
+
const result = await clearDocumentStructure({});
|
|
121
|
+
|
|
122
|
+
expect(result.message).toContain("Document structure cleared successfully!");
|
|
123
|
+
expect(result.clearedCount).toBe(1);
|
|
124
|
+
} finally {
|
|
125
|
+
// Restore original working directory
|
|
126
|
+
process.chdir(originalCwd);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("should provide correct return structure", async () => {
|
|
131
|
+
await writeFile(structurePlanPath, JSON.stringify({ test: "data" }));
|
|
132
|
+
|
|
133
|
+
const result = await clearDocumentStructure({ workDir: testDir });
|
|
134
|
+
|
|
135
|
+
expect(result).toHaveProperty("message");
|
|
136
|
+
expect(result).toHaveProperty("results");
|
|
137
|
+
expect(result).toHaveProperty("hasError");
|
|
138
|
+
expect(result).toHaveProperty("clearedCount");
|
|
139
|
+
expect(typeof result.message).toBe("string");
|
|
140
|
+
expect(Array.isArray(result.results)).toBe(true);
|
|
141
|
+
expect(typeof result.hasError).toBe("boolean");
|
|
142
|
+
expect(typeof result.clearedCount).toBe("number");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("should have correct input schema", () => {
|
|
146
|
+
expect(clearDocumentStructure.input_schema).toBeDefined();
|
|
147
|
+
expect(clearDocumentStructure.input_schema.type).toBe("object");
|
|
148
|
+
expect(clearDocumentStructure.input_schema.properties.docsDir).toBeDefined();
|
|
149
|
+
expect(clearDocumentStructure.input_schema.properties.docsDir.type).toBe("string");
|
|
150
|
+
expect(clearDocumentStructure.input_schema.properties.docsDir.description).toBe(
|
|
151
|
+
"The documents directory to clear (optional)",
|
|
152
|
+
);
|
|
153
|
+
expect(clearDocumentStructure.input_schema.properties.workDir).toBeDefined();
|
|
154
|
+
expect(clearDocumentStructure.input_schema.properties.workDir.type).toBe("string");
|
|
155
|
+
expect(clearDocumentStructure.input_schema.properties.workDir.description).toBe(
|
|
156
|
+
"The working directory (defaults to current directory)",
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("should have correct task metadata", () => {
|
|
161
|
+
expect(clearDocumentStructure.taskTitle).toBe(
|
|
162
|
+
"Clear document structure and all generated documents",
|
|
163
|
+
);
|
|
164
|
+
expect(clearDocumentStructure.description).toBe(
|
|
165
|
+
"Clear the document structure plan (structure-plan.json) and optionally the documents directory",
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("should handle complex document structures", async () => {
|
|
170
|
+
// Create complex structure plan
|
|
171
|
+
const complexStructure = {
|
|
172
|
+
documents: [
|
|
173
|
+
{
|
|
174
|
+
path: "/introduction",
|
|
175
|
+
title: "Introduction",
|
|
176
|
+
children: [
|
|
177
|
+
{ path: "/introduction/overview", title: "Overview" },
|
|
178
|
+
{ path: "/introduction/getting-started", title: "Getting Started" },
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
path: "/api",
|
|
183
|
+
title: "API Reference",
|
|
184
|
+
children: [
|
|
185
|
+
{ path: "/api/authentication", title: "Authentication" },
|
|
186
|
+
{ path: "/api/endpoints", title: "Endpoints" },
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
metadata: {
|
|
191
|
+
version: "1.0.0",
|
|
192
|
+
generated: new Date().toISOString(),
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
await writeFile(structurePlanPath, JSON.stringify(complexStructure, null, 2));
|
|
197
|
+
|
|
198
|
+
// Create corresponding docs structure
|
|
199
|
+
await mkdir(docsDir, { recursive: true });
|
|
200
|
+
const nestedDirs = [
|
|
201
|
+
join(docsDir, "introduction"),
|
|
202
|
+
join(docsDir, "api"),
|
|
203
|
+
join(docsDir, "tutorials"),
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
for (const dir of nestedDirs) {
|
|
207
|
+
await mkdir(dir, { recursive: true });
|
|
208
|
+
await writeFile(join(dir, "index.md"), `# ${dir} content`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const result = await clearDocumentStructure({ workDir: testDir, docsDir });
|
|
212
|
+
|
|
213
|
+
expect(result.clearedCount).toBe(2);
|
|
214
|
+
expect(result.hasError).toBe(false);
|
|
215
|
+
|
|
216
|
+
// Verify everything is cleaned up
|
|
217
|
+
const { pathExists } = await import("../../../utils/file-utils.mjs");
|
|
218
|
+
const structureExists = await pathExists(structurePlanPath);
|
|
219
|
+
const docsExists = await pathExists(docsDir);
|
|
220
|
+
expect(structureExists).toBe(false);
|
|
221
|
+
expect(docsExists).toBe(false);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("should handle paths with special characters", async () => {
|
|
225
|
+
// Create directory with special characters
|
|
226
|
+
const specialTestDir = join(__dirname, "test-clear-structure with spaces & symbols");
|
|
227
|
+
await mkdir(specialTestDir, { recursive: true });
|
|
228
|
+
|
|
229
|
+
const specialOutputDir = join(specialTestDir, ".aigne", "doc-smith", "output");
|
|
230
|
+
await mkdir(specialOutputDir, { recursive: true });
|
|
231
|
+
|
|
232
|
+
const specialStructurePath = join(specialOutputDir, "structure-plan.json");
|
|
233
|
+
await writeFile(specialStructurePath, JSON.stringify({ special: "test" }));
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
const result = await clearDocumentStructure({ workDir: specialTestDir });
|
|
237
|
+
|
|
238
|
+
expect(result.clearedCount).toBe(1);
|
|
239
|
+
expect(result.hasError).toBe(false);
|
|
240
|
+
|
|
241
|
+
// Verify special path works
|
|
242
|
+
const { pathExists } = await import("../../../utils/file-utils.mjs");
|
|
243
|
+
const exists = await pathExists(specialStructurePath);
|
|
244
|
+
expect(exists).toBe(false);
|
|
245
|
+
} finally {
|
|
246
|
+
// Clean up special directory
|
|
247
|
+
try {
|
|
248
|
+
await rm(specialTestDir, { recursive: true, force: true });
|
|
249
|
+
} catch {
|
|
250
|
+
// Ignore cleanup errors
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("should handle relative and absolute paths for docsDir", async () => {
|
|
256
|
+
await writeFile(structurePlanPath, JSON.stringify({ test: "data" }));
|
|
257
|
+
|
|
258
|
+
// Create docs with relative path reference
|
|
259
|
+
const relativeDocs = join(testDir, "relative-docs");
|
|
260
|
+
await mkdir(relativeDocs, { recursive: true });
|
|
261
|
+
await writeFile(join(relativeDocs, "test.md"), "test content");
|
|
262
|
+
|
|
263
|
+
const originalCwd = process.cwd();
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
process.chdir(testDir);
|
|
267
|
+
const result = await clearDocumentStructure({
|
|
268
|
+
workDir: testDir,
|
|
269
|
+
docsDir: "./relative-docs",
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(result.clearedCount).toBe(2);
|
|
273
|
+
expect(result.hasError).toBe(false);
|
|
274
|
+
} finally {
|
|
275
|
+
process.chdir(originalCwd);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test("should provide detailed results information", async () => {
|
|
280
|
+
await writeFile(structurePlanPath, JSON.stringify({ test: "data" }));
|
|
281
|
+
await mkdir(docsDir, { recursive: true });
|
|
282
|
+
await writeFile(join(docsDir, "test.md"), "test content");
|
|
283
|
+
|
|
284
|
+
const result = await clearDocumentStructure({ workDir: testDir, docsDir });
|
|
285
|
+
|
|
286
|
+
expect(result.results).toHaveLength(2);
|
|
287
|
+
|
|
288
|
+
// Check structure result
|
|
289
|
+
const structureResult = result.results.find((r) => r.type === "structure");
|
|
290
|
+
expect(structureResult).toBeDefined();
|
|
291
|
+
expect(structureResult.cleared).toBe(true);
|
|
292
|
+
expect(structureResult.message).toContain("structure plan");
|
|
293
|
+
|
|
294
|
+
// Check documents result
|
|
295
|
+
const docsResult = result.results.find((r) => r.type === "documents");
|
|
296
|
+
expect(docsResult).toBeDefined();
|
|
297
|
+
expect(docsResult.cleared).toBe(true);
|
|
298
|
+
expect(docsResult.message).toContain("documents directory");
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test("should handle structure plan file removal errors", async () => {
|
|
302
|
+
// Create a spy on rm to simulate an error for structure plan
|
|
303
|
+
const rmSpy = spyOn(fsPromises, "rm");
|
|
304
|
+
rmSpy.mockImplementation((path, _options) => {
|
|
305
|
+
if (path.includes("structure-plan.json")) {
|
|
306
|
+
throw new Error("Permission denied for structure plan");
|
|
307
|
+
}
|
|
308
|
+
return Promise.resolve();
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
const result = await clearDocumentStructure({ workDir: testDir });
|
|
313
|
+
|
|
314
|
+
expect(result.hasError).toBe(true);
|
|
315
|
+
expect(result.message).toContain("Document structure cleanup finished with some issues.");
|
|
316
|
+
|
|
317
|
+
const structureResult = result.results.find((r) => r.type === "structure");
|
|
318
|
+
expect(structureResult.error).toBe(true);
|
|
319
|
+
expect(structureResult.message).toContain("Failed to clear document structure plan");
|
|
320
|
+
expect(structureResult.message).toContain("Permission denied for structure plan");
|
|
321
|
+
} finally {
|
|
322
|
+
rmSpy.mockRestore();
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("should handle documents directory removal errors", async () => {
|
|
327
|
+
// Create structure plan file
|
|
328
|
+
await writeFile(structurePlanPath, JSON.stringify({ test: "data" }));
|
|
329
|
+
|
|
330
|
+
// Create a spy on rm to simulate an error for docs directory
|
|
331
|
+
const rmSpy = spyOn(fsPromises, "rm");
|
|
332
|
+
rmSpy.mockImplementation((path, _options) => {
|
|
333
|
+
if (path === docsDir) {
|
|
334
|
+
throw new Error("Permission denied for docs directory");
|
|
335
|
+
}
|
|
336
|
+
return Promise.resolve();
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
const result = await clearDocumentStructure({ workDir: testDir, docsDir });
|
|
341
|
+
|
|
342
|
+
expect(result.hasError).toBe(true);
|
|
343
|
+
expect(result.message).toContain("Document structure cleanup finished with some issues.");
|
|
344
|
+
|
|
345
|
+
const docsResult = result.results.find((r) => r.type === "documents");
|
|
346
|
+
expect(docsResult.error).toBe(true);
|
|
347
|
+
expect(docsResult.message).toContain("Failed to clear documents directory");
|
|
348
|
+
expect(docsResult.message).toContain("Permission denied for docs directory");
|
|
349
|
+
} finally {
|
|
350
|
+
rmSpy.mockRestore();
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test("should handle both structure and docs errors simultaneously", async () => {
|
|
355
|
+
// Create a spy on rm to simulate errors for both operations
|
|
356
|
+
const rmSpy = spyOn(fsPromises, "rm");
|
|
357
|
+
rmSpy.mockImplementation(() => {
|
|
358
|
+
throw new Error("File system error");
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
const result = await clearDocumentStructure({ workDir: testDir, docsDir });
|
|
363
|
+
|
|
364
|
+
expect(result.hasError).toBe(true);
|
|
365
|
+
expect(result.message).toContain("Document structure cleanup finished with some issues.");
|
|
366
|
+
expect(result.results).toHaveLength(2);
|
|
367
|
+
|
|
368
|
+
// Both operations should have errors
|
|
369
|
+
expect(result.results.every((r) => r.error)).toBe(true);
|
|
370
|
+
} finally {
|
|
371
|
+
rmSpy.mockRestore();
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
});
|