@aigne/doc-smith 0.8.12-beta.8 → 0.8.12-beta.9

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 (264) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/agents/publish/index.yaml +4 -0
  3. package/agents/publish/publish-docs.mjs +77 -5
  4. package/agents/publish/translate-meta.mjs +103 -0
  5. package/agents/update/generate-document.yaml +30 -28
  6. package/agents/update/update-document-detail.yaml +3 -1
  7. package/agents/utils/update-branding.mjs +69 -0
  8. package/package.json +16 -2
  9. package/prompts/common/document/role-and-personality.md +3 -1
  10. package/prompts/detail/d2-diagram/guide.md +7 -1
  11. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  12. package/prompts/detail/generate/system-prompt.md +6 -7
  13. package/prompts/detail/generate/user-prompt.md +12 -3
  14. package/prompts/detail/update/user-prompt.md +0 -2
  15. package/prompts/structure/update/user-prompt.md +0 -4
  16. package/utils/file-utils.mjs +69 -24
  17. package/utils/markdown-checker.mjs +0 -20
  18. package/utils/request.mjs +7 -0
  19. package/utils/upload-files.mjs +231 -0
  20. package/utils/utils.mjs +11 -1
  21. package/.aigne/doc-smith/config.yaml +0 -77
  22. package/.aigne/doc-smith/history.yaml +0 -37
  23. package/.aigne/doc-smith/media-description.yaml +0 -91
  24. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  25. package/.aigne/doc-smith/preferences.yml +0 -97
  26. package/.aigne/doc-smith/upload-cache.yaml +0 -1830
  27. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  28. package/.github/workflows/ci.yml +0 -54
  29. package/.github/workflows/create-release-pr.yaml +0 -21
  30. package/.github/workflows/publish-docs.yml +0 -65
  31. package/.github/workflows/release.yml +0 -49
  32. package/.github/workflows/reviewer.yml +0 -54
  33. package/.release-please-manifest.json +0 -3
  34. package/RELEASE.md +0 -9
  35. package/assets/screenshots/doc-complete-setup.png +0 -0
  36. package/assets/screenshots/doc-generate-docs.png +0 -0
  37. package/assets/screenshots/doc-generate.png +0 -0
  38. package/assets/screenshots/doc-generated-successfully.png +0 -0
  39. package/assets/screenshots/doc-publish.png +0 -0
  40. package/assets/screenshots/doc-regenerate.png +0 -0
  41. package/assets/screenshots/doc-translate-langs.png +0 -0
  42. package/assets/screenshots/doc-translate.png +0 -0
  43. package/assets/screenshots/doc-update.png +0 -0
  44. package/biome.json +0 -73
  45. package/codecov.yml +0 -15
  46. package/docs/_sidebar.md +0 -15
  47. package/docs/configuration-initial-setup.ja.md +0 -179
  48. package/docs/configuration-initial-setup.md +0 -198
  49. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  50. package/docs/configuration-initial-setup.zh.md +0 -179
  51. package/docs/configuration-managing-preferences.ja.md +0 -100
  52. package/docs/configuration-managing-preferences.md +0 -100
  53. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  54. package/docs/configuration-managing-preferences.zh.md +0 -100
  55. package/docs/configuration.ja.md +0 -69
  56. package/docs/configuration.md +0 -69
  57. package/docs/configuration.zh-TW.md +0 -69
  58. package/docs/configuration.zh.md +0 -69
  59. package/docs/getting-started.ja.md +0 -107
  60. package/docs/getting-started.md +0 -107
  61. package/docs/getting-started.zh-TW.md +0 -107
  62. package/docs/getting-started.zh.md +0 -107
  63. package/docs/guides-cleaning-up.ja.md +0 -51
  64. package/docs/guides-cleaning-up.md +0 -52
  65. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  66. package/docs/guides-cleaning-up.zh.md +0 -51
  67. package/docs/guides-evaluating-documents.ja.md +0 -66
  68. package/docs/guides-evaluating-documents.md +0 -107
  69. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  70. package/docs/guides-evaluating-documents.zh.md +0 -66
  71. package/docs/guides-generating-documentation.ja.md +0 -151
  72. package/docs/guides-generating-documentation.md +0 -89
  73. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  74. package/docs/guides-generating-documentation.zh.md +0 -151
  75. package/docs/guides-interactive-chat.ja.md +0 -85
  76. package/docs/guides-interactive-chat.md +0 -93
  77. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  78. package/docs/guides-interactive-chat.zh.md +0 -85
  79. package/docs/guides-managing-history.ja.md +0 -48
  80. package/docs/guides-managing-history.md +0 -53
  81. package/docs/guides-managing-history.zh-TW.md +0 -48
  82. package/docs/guides-managing-history.zh.md +0 -48
  83. package/docs/guides-publishing-your-docs.ja.md +0 -78
  84. package/docs/guides-publishing-your-docs.md +0 -83
  85. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  86. package/docs/guides-publishing-your-docs.zh.md +0 -78
  87. package/docs/guides-translating-documentation.ja.md +0 -95
  88. package/docs/guides-translating-documentation.md +0 -100
  89. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  90. package/docs/guides-translating-documentation.zh.md +0 -95
  91. package/docs/guides-updating-documentation.ja.md +0 -77
  92. package/docs/guides-updating-documentation.md +0 -79
  93. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  94. package/docs/guides-updating-documentation.zh.md +0 -77
  95. package/docs/guides.ja.md +0 -32
  96. package/docs/guides.md +0 -32
  97. package/docs/guides.zh-TW.md +0 -32
  98. package/docs/guides.zh.md +0 -32
  99. package/docs/overview.ja.md +0 -61
  100. package/docs/overview.md +0 -61
  101. package/docs/overview.zh-TW.md +0 -61
  102. package/docs/overview.zh.md +0 -61
  103. package/docs/release-notes.ja.md +0 -255
  104. package/docs/release-notes.md +0 -288
  105. package/docs/release-notes.zh-TW.md +0 -255
  106. package/docs/release-notes.zh.md +0 -255
  107. package/prompts/common/afs/afs-tools-usage.md +0 -5
  108. package/prompts/common/afs/use-afs-instruction.md +0 -1
  109. package/release-please-config.json +0 -14
  110. package/tests/agents/chat/chat.test.mjs +0 -46
  111. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  112. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  113. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  114. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  115. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  116. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  117. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  118. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  119. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  120. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  121. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  122. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  123. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  124. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  125. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  126. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  127. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  128. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  129. package/tests/agents/history/view.test.mjs +0 -97
  130. package/tests/agents/init/init.test.mjs +0 -1657
  131. package/tests/agents/prefs/prefs.test.mjs +0 -431
  132. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  133. package/tests/agents/translate/choose-language.test.mjs +0 -311
  134. package/tests/agents/translate/translate-document.test.mjs +0 -51
  135. package/tests/agents/update/check-document.test.mjs +0 -463
  136. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  137. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  138. package/tests/agents/update/generate-document.test.mjs +0 -51
  139. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  140. package/tests/agents/update/user-review-document.test.mjs +0 -582
  141. package/tests/agents/utils/action-success.test.mjs +0 -54
  142. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  143. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  144. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  145. package/tests/agents/utils/exit.test.mjs +0 -70
  146. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  147. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  148. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  149. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  150. package/tests/agents/utils/fs.test.mjs +0 -267
  151. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  152. package/tests/agents/utils/save-docs.test.mjs +0 -109
  153. package/tests/agents/utils/save-output.test.mjs +0 -315
  154. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  155. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  156. package/tests/utils/auth-utils.test.mjs +0 -596
  157. package/tests/utils/blocklet.test.mjs +0 -336
  158. package/tests/utils/conflict-detector.test.mjs +0 -355
  159. package/tests/utils/constants.test.mjs +0 -295
  160. package/tests/utils/d2-utils.test.mjs +0 -437
  161. package/tests/utils/deploy.test.mjs +0 -399
  162. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  163. package/tests/utils/file-utils.test.mjs +0 -521
  164. package/tests/utils/history-utils.test.mjs +0 -206
  165. package/tests/utils/kroki-utils.test.mjs +0 -646
  166. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  167. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  168. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  169. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  170. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  171. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  172. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  173. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  174. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  175. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  176. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  177. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  178. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  179. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  180. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  181. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  182. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  183. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  184. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  185. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  186. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  187. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  188. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  189. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  190. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  191. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  192. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  193. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  194. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  195. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  196. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  197. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  198. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  199. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  200. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  201. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  202. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  203. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  204. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  205. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  206. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  207. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  208. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  209. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  210. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  211. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  212. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  213. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  214. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  215. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  216. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  217. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  218. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  219. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  220. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  221. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  222. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  223. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  224. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  225. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  226. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  227. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  228. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  229. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  230. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  231. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  232. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  233. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  234. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  235. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  236. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  237. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  238. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  239. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  240. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  241. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  242. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  243. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  244. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  245. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  246. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  247. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  248. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  249. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  250. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  251. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  252. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  253. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  254. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  255. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  256. package/tests/utils/linter/index.test.mjs +0 -440
  257. package/tests/utils/linter/scan-results.mjs +0 -42
  258. package/tests/utils/load-config.test.mjs +0 -141
  259. package/tests/utils/markdown/index.test.mjs +0 -478
  260. package/tests/utils/mermaid-validator.test.mjs +0 -541
  261. package/tests/utils/mock-chat-model.mjs +0 -12
  262. package/tests/utils/preferences-utils.test.mjs +0 -465
  263. package/tests/utils/save-value-to-config.test.mjs +0 -483
  264. package/tests/utils/utils.test.mjs +0 -941
@@ -1,300 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
2
- import checkUpdateIsSingle from "../../../agents/update/check-update-is-single.mjs";
3
-
4
- describe("check-update-is-single", () => {
5
- let mockOptions;
6
- let consoleSpy;
7
-
8
- beforeEach(() => {
9
- mockOptions = {
10
- context: {
11
- agents: {
12
- updateSingleDocument: { mockSingleAgent: true },
13
- batchUpdateDocument: { mockBatchAgent: true },
14
- },
15
- invoke: mock(async () => ({ mockResult: true })),
16
- },
17
- };
18
-
19
- consoleSpy = spyOn(console, "error").mockImplementation(() => {});
20
-
21
- // Clear context mock call history
22
- mockOptions.context.invoke.mockClear();
23
- });
24
-
25
- afterEach(() => {
26
- consoleSpy?.mockRestore();
27
- });
28
-
29
- // INPUT VALIDATION TESTS
30
- test("should throw error when selectedDocs is not provided", async () => {
31
- await expect(checkUpdateIsSingle({}, mockOptions)).rejects.toThrow(
32
- "selectedDocs must be provided as an array",
33
- );
34
- });
35
-
36
- test("should throw error when selectedDocs is not an array", async () => {
37
- await expect(checkUpdateIsSingle({ selectedDocs: "not-array" }, mockOptions)).rejects.toThrow(
38
- "selectedDocs must be provided as an array",
39
- );
40
- });
41
-
42
- test("should throw error when selectedDocs is empty", async () => {
43
- await expect(checkUpdateIsSingle({ selectedDocs: [] }, mockOptions)).rejects.toThrow(
44
- "selectedDocs cannot be empty",
45
- );
46
- });
47
-
48
- test("should throw error when selectedDocs is null", async () => {
49
- await expect(checkUpdateIsSingle({ selectedDocs: null }, mockOptions)).rejects.toThrow(
50
- "selectedDocs must be provided as an array",
51
- );
52
- });
53
-
54
- test("should throw error when selectedDocs is undefined", async () => {
55
- await expect(checkUpdateIsSingle({ selectedDocs: undefined }, mockOptions)).rejects.toThrow(
56
- "selectedDocs must be provided as an array",
57
- );
58
- });
59
-
60
- // AGENT AVAILABILITY TESTS
61
- test("should throw error when updateSingleDocument agent is not available", async () => {
62
- const optionsWithoutSingleAgent = {
63
- context: {
64
- agents: {
65
- batchUpdateDocument: { mockBatchAgent: true },
66
- },
67
- invoke: mock(),
68
- },
69
- };
70
-
71
- await expect(
72
- checkUpdateIsSingle({ selectedDocs: ["doc1"] }, optionsWithoutSingleAgent),
73
- ).rejects.toThrow('Agent "updateSingleDocument" is not available');
74
- });
75
-
76
- test("should throw error when batchUpdateDocument agent is not available", async () => {
77
- const optionsWithoutBatchAgent = {
78
- context: {
79
- agents: {
80
- updateSingleDocument: { mockSingleAgent: true },
81
- },
82
- invoke: mock(),
83
- },
84
- };
85
-
86
- await expect(
87
- checkUpdateIsSingle({ selectedDocs: ["doc1", "doc2"] }, optionsWithoutBatchAgent),
88
- ).rejects.toThrow('Agent "batchUpdateDocument" is not available');
89
- });
90
-
91
- test("should throw error when no agents are available", async () => {
92
- const optionsWithoutAgents = {
93
- context: {
94
- agents: {},
95
- invoke: mock(),
96
- },
97
- };
98
-
99
- await expect(
100
- checkUpdateIsSingle({ selectedDocs: ["doc1"] }, optionsWithoutAgents),
101
- ).rejects.toThrow('Agent "updateSingleDocument" is not available');
102
- });
103
-
104
- // SINGLE DOCUMENT ROUTING TESTS
105
- test("should route to updateSingleDocument when selectedDocs has one item", async () => {
106
- const result = await checkUpdateIsSingle(
107
- {
108
- selectedDocs: ["doc1"],
109
- customParam: "test",
110
- },
111
- mockOptions,
112
- );
113
-
114
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
115
- { mockSingleAgent: true },
116
- {
117
- selectedDocs: ["doc1"],
118
- customParam: "test",
119
- },
120
- );
121
- expect(result).toEqual({ mockResult: true });
122
- });
123
-
124
- test("should pass through all parameters to single document agent", async () => {
125
- await checkUpdateIsSingle(
126
- {
127
- selectedDocs: [{ path: "/doc1", content: "content" }],
128
- docsDir: "./docs",
129
- forceRegenerate: true,
130
- customData: { key: "value" },
131
- },
132
- mockOptions,
133
- );
134
-
135
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
136
- { mockSingleAgent: true },
137
- {
138
- selectedDocs: [{ path: "/doc1", content: "content" }],
139
- docsDir: "./docs",
140
- forceRegenerate: true,
141
- customData: { key: "value" },
142
- },
143
- );
144
- });
145
-
146
- // BATCH DOCUMENT ROUTING TESTS
147
- test("should route to batchUpdateDocument when selectedDocs has multiple items", async () => {
148
- const result = await checkUpdateIsSingle(
149
- {
150
- selectedDocs: ["doc1", "doc2"],
151
- customParam: "test",
152
- },
153
- mockOptions,
154
- );
155
-
156
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
157
- { mockBatchAgent: true },
158
- {
159
- selectedDocs: ["doc1", "doc2"],
160
- customParam: "test",
161
- },
162
- );
163
- expect(result).toEqual({ mockResult: true });
164
- });
165
-
166
- test("should route to batchUpdateDocument when selectedDocs has three items", async () => {
167
- await checkUpdateIsSingle(
168
- {
169
- selectedDocs: ["doc1", "doc2", "doc3"],
170
- },
171
- mockOptions,
172
- );
173
-
174
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
175
- { mockBatchAgent: true },
176
- {
177
- selectedDocs: ["doc1", "doc2", "doc3"],
178
- },
179
- );
180
- });
181
-
182
- test("should pass through all parameters to batch document agent", async () => {
183
- await checkUpdateIsSingle(
184
- {
185
- selectedDocs: [
186
- { path: "/doc1", content: "content1" },
187
- { path: "/doc2", content: "content2" },
188
- ],
189
- docsDir: "./docs",
190
- forceRegenerate: false,
191
- batchSize: 10,
192
- customSettings: { parallel: true },
193
- },
194
- mockOptions,
195
- );
196
-
197
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
198
- { mockBatchAgent: true },
199
- {
200
- selectedDocs: [
201
- { path: "/doc1", content: "content1" },
202
- { path: "/doc2", content: "content2" },
203
- ],
204
- docsDir: "./docs",
205
- forceRegenerate: false,
206
- batchSize: 10,
207
- customSettings: { parallel: true },
208
- },
209
- );
210
- });
211
-
212
- // ERROR HANDLING TESTS
213
- test("should handle and re-throw agent invocation errors for single document", async () => {
214
- const mockError = new Error("Agent execution failed");
215
- mockOptions.context.invoke.mockRejectedValue(mockError);
216
-
217
- await expect(checkUpdateIsSingle({ selectedDocs: ["doc1"] }, mockOptions)).rejects.toThrow(
218
- "Agent execution failed",
219
- );
220
-
221
- expect(consoleSpy).toHaveBeenCalledWith(
222
- "Error invoking updateSingleDocument:",
223
- "Agent execution failed",
224
- );
225
- });
226
-
227
- test("should handle and re-throw agent invocation errors for batch documents", async () => {
228
- const mockError = new Error("Batch processing failed");
229
- mockOptions.context.invoke.mockRejectedValue(mockError);
230
-
231
- await expect(
232
- checkUpdateIsSingle({ selectedDocs: ["doc1", "doc2"] }, mockOptions),
233
- ).rejects.toThrow("Batch processing failed");
234
-
235
- expect(consoleSpy).toHaveBeenCalledWith(
236
- "Error invoking batchUpdateDocument:",
237
- "Batch processing failed",
238
- );
239
- });
240
-
241
- test("should log specific error message for single document failures", async () => {
242
- const mockError = new Error("Network timeout");
243
- mockOptions.context.invoke.mockRejectedValue(mockError);
244
-
245
- try {
246
- await checkUpdateIsSingle({ selectedDocs: ["doc1"] }, mockOptions);
247
- } catch {
248
- // Expected to throw
249
- }
250
-
251
- expect(consoleSpy).toHaveBeenCalledWith(
252
- "Error invoking updateSingleDocument:",
253
- "Network timeout",
254
- );
255
- });
256
-
257
- test("should log specific error message for batch document failures", async () => {
258
- const mockError = new Error("Memory limit exceeded");
259
- mockOptions.context.invoke.mockRejectedValue(mockError);
260
-
261
- try {
262
- await checkUpdateIsSingle({ selectedDocs: ["doc1", "doc2", "doc3"] }, mockOptions);
263
- } catch {
264
- // Expected to throw
265
- }
266
-
267
- expect(consoleSpy).toHaveBeenCalledWith(
268
- "Error invoking batchUpdateDocument:",
269
- "Memory limit exceeded",
270
- );
271
- });
272
-
273
- // RESULT PASSING TESTS
274
- test("should return result from single document agent unchanged", async () => {
275
- const mockResult = {
276
- success: true,
277
- processedDocs: ["doc1"],
278
- metadata: { timestamp: "2023-01-01" },
279
- };
280
- mockOptions.context.invoke.mockResolvedValue(mockResult);
281
-
282
- const result = await checkUpdateIsSingle({ selectedDocs: ["doc1"] }, mockOptions);
283
-
284
- expect(result).toEqual(mockResult);
285
- });
286
-
287
- test("should return result from batch document agent unchanged", async () => {
288
- const mockResult = {
289
- success: true,
290
- processedDocs: ["doc1", "doc2"],
291
- errors: [],
292
- summary: "All documents processed successfully",
293
- };
294
- mockOptions.context.invoke.mockResolvedValue(mockResult);
295
-
296
- const result = await checkUpdateIsSingle({ selectedDocs: ["doc1", "doc2"] }, mockOptions);
297
-
298
- expect(result).toEqual(mockResult);
299
- });
300
- });
@@ -1,329 +0,0 @@
1
- import { beforeEach, describe, expect, test } from "bun:test";
2
- import updateDocumentContent from "../../../../agents/update/document-tools/update-document-content.mjs";
3
-
4
- describe("update-document-content", () => {
5
- let mockOptions;
6
-
7
- beforeEach(() => {
8
- mockOptions = {
9
- context: {
10
- userContext: {
11
- currentContent: "",
12
- },
13
- },
14
- };
15
- });
16
-
17
- // Helper function to extract content from page_content wrapper
18
- function extractContent(wrappedContent) {
19
- const match = wrappedContent.match(/<page_content>\s*([\s\S]*?)\s*<\/page_content>/);
20
- return match ? match[1] : wrappedContent;
21
- }
22
-
23
- // INPUT VALIDATION TESTS
24
- test("should return error when diffPatch is not provided", async () => {
25
- mockOptions.context.userContext.currentContent = "original content";
26
- const result = await updateDocumentContent({}, mockOptions);
27
- expect(result.success).toBe(false);
28
- expect(result.error.message).toContain("diffPatch");
29
- });
30
-
31
- test("should return error when diffPatch is not a string", async () => {
32
- mockOptions.context.userContext.currentContent = "original content";
33
- const result = await updateDocumentContent({ diffPatch: null }, mockOptions);
34
- expect(result.success).toBe(false);
35
- expect(result.error.message).toContain("diffPatch");
36
- });
37
-
38
- test("should return error when diffPatch is empty string", async () => {
39
- mockOptions.context.userContext.currentContent = "original content";
40
- const result = await updateDocumentContent({ diffPatch: "" }, mockOptions);
41
- expect(result.success).toBe(false);
42
- expect(result.error.message).toContain("Diff patch is required");
43
- });
44
-
45
- // SUCCESSFUL PATCH APPLICATION TESTS
46
- test("should successfully apply simple diff patch", async () => {
47
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3";
48
- const diffPatch = "@@ -1,3 +1,3 @@\n line 1\n-line 2\n+updated line 2\n line 3";
49
-
50
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
51
-
52
- expect(result.success).toBe(true);
53
- expect(extractContent(result.updatedContent)).toBe("line 1\nupdated line 2\nline 3");
54
- expect(result.message).toContain("Document content updated successfully");
55
- });
56
-
57
- test("should handle diff with multiple hunks", async () => {
58
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3\nline 4\nline 5";
59
- const diffPatch =
60
- "@@ -1,2 +1,2 @@\n-line 1\n+updated line 1\n line 2\n@@ -4,2 +4,2 @@\n line 4\n-line 5\n+updated line 5";
61
-
62
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
63
-
64
- expect(result.success).toBe(true);
65
- expect(extractContent(result.updatedContent)).toBe(
66
- "updated line 1\nline 2\nline 3\nline 4\nupdated line 5",
67
- );
68
- });
69
-
70
- test("should handle diff with additions only", async () => {
71
- mockOptions.context.userContext.currentContent = "line 1\nline 2";
72
- const diffPatch = "@@ -2,0 +3,2 @@\n line 2\n+new line 3\n+new line 4";
73
-
74
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
75
-
76
- expect(result.success).toBe(true);
77
- expect(extractContent(result.updatedContent)).toBe("line 1\nline 2\nnew line 3\nnew line 4");
78
- });
79
-
80
- test("should handle diff with deletions only", async () => {
81
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3\nline 4";
82
- const diffPatch = "@@ -2,2 +2,0 @@\n line 1\n-line 2\n-line 3\n line 4";
83
-
84
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
85
-
86
- expect(result.success).toBe(true);
87
- expect(extractContent(result.updatedContent)).toBe("line 1\nline 4");
88
- });
89
-
90
- test("should handle diff with context lines", async () => {
91
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3\nline 4\nline 5";
92
- const diffPatch =
93
- "@@ -2,3 +2,3 @@\n line 1\n line 2\n-line 3\n+updated line 3\n line 4\n line 5";
94
-
95
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
96
-
97
- expect(result.success).toBe(true);
98
- expect(extractContent(result.updatedContent)).toBe(
99
- "line 1\nline 2\nupdated line 3\nline 4\nline 5",
100
- );
101
- });
102
-
103
- // DIFF PATCH PARSING TESTS
104
- test("should return error for invalid diff format", async () => {
105
- mockOptions.context.userContext.currentContent = "line 1\nline 2";
106
- const diffPatch = "invalid diff format";
107
-
108
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
109
-
110
- expect(result).toEqual({
111
- success: false,
112
- error: { message: "No valid hunks found in diff" },
113
- });
114
- });
115
-
116
- test("should return error for empty diff", async () => {
117
- mockOptions.context.userContext.currentContent = "line 1\nline 2";
118
- const diffPatch = "\n\n";
119
-
120
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
121
-
122
- expect(result).toEqual({
123
- success: false,
124
- error: { message: "No valid hunks found in diff" },
125
- });
126
- });
127
-
128
- test("should handle malformed hunk headers gracefully", async () => {
129
- mockOptions.context.userContext.currentContent = "line 1\nline 2";
130
- const diffPatch = "@@malformed header@@\n-line 1\n+updated line 1";
131
-
132
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
133
-
134
- expect(result.success).toBe(false);
135
- expect(result.error.message).toContain("No valid hunks found");
136
- });
137
-
138
- // LINE NUMBER FIXING TESTS
139
- test("should fix line numbers when patch position is off", async () => {
140
- mockOptions.context.userContext.currentContent = "prefix line\nline 1\nline 2\nline 3";
141
- // This diff patch expects to find "line 1" at line 1, but it's actually at line 2
142
- const diffPatch = "@@ -1,2 +1,2 @@\n-line 1\n+updated line 1\n line 2";
143
-
144
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
145
-
146
- expect(result.success).toBe(true);
147
- expect(extractContent(result.updatedContent)).toBe(
148
- "prefix line\nupdated line 1\nline 2\nline 3",
149
- );
150
- });
151
-
152
- test("should use fuzzy matching when exact match fails", async () => {
153
- mockOptions.context.userContext.currentContent =
154
- "similar line 1\nsimilar line 2\ndifferent content\nsimilar line 3";
155
- // This patch refers to lines that are similar but not exactly matching
156
- const diffPatch = "@@ -10,2 +10,2 @@\n-similar line 1\n+updated line 1\n similar line 2";
157
-
158
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
159
-
160
- expect(result.success).toBe(true);
161
- expect(extractContent(result.updatedContent)).toBe(
162
- "updated line 1\nsimilar line 2\ndifferent content\nsimilar line 3",
163
- );
164
- });
165
-
166
- test("should return error when no matching context found", async () => {
167
- mockOptions.context.userContext.currentContent =
168
- "completely different content\nnothing matches";
169
- const diffPatch =
170
- "@@ -1,2 +1,2 @@\n-line that doesn't exist\n+updated line\n another nonexistent line";
171
-
172
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
173
-
174
- expect(result.success).toBe(false);
175
- expect(result.error.message).toContain("Cannot find matching context");
176
- });
177
-
178
- // COMPLEX DIFF SCENARIOS
179
- test("should handle diff with no context lines", async () => {
180
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3";
181
- const diffPatch = "@@ -2,1 +2,1 @@\n-line 2\n+updated line 2";
182
-
183
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
184
-
185
- expect(result.success).toBe(true);
186
- expect(extractContent(result.updatedContent)).toBe("line 1\nupdated line 2\nline 3");
187
- });
188
-
189
- test("should handle diff with single line count (implicit 1)", async () => {
190
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3";
191
- const diffPatch = "@@ -2 +2 @@\n-line 2\n+updated line 2";
192
-
193
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
194
-
195
- expect(result.success).toBe(true);
196
- expect(extractContent(result.updatedContent)).toBe("line 1\nupdated line 2\nline 3");
197
- });
198
-
199
- test("should handle multiple changes in single hunk", async () => {
200
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3\nline 4\nline 5";
201
- const diffPatch =
202
- "@@ -2,3 +2,4 @@\n line 1\n-line 2\n-line 3\n+updated line 2\n+new line\n+updated line 3\n line 4";
203
-
204
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
205
-
206
- expect(result.success).toBe(true);
207
- expect(extractContent(result.updatedContent)).toBe(
208
- "line 1\nupdated line 2\nnew line\nupdated line 3\nline 4\nline 5",
209
- );
210
- });
211
-
212
- // EDGE CASES
213
- test("should handle empty lines in diff", async () => {
214
- mockOptions.context.userContext.currentContent = "line 1\n\nline 3";
215
- const diffPatch = "@@ -1,3 +1,3 @@\n line 1\n \n-line 3\n+updated line 3";
216
-
217
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
218
-
219
- expect(result.success).toBe(true);
220
- expect(extractContent(result.updatedContent)).toBe("line 1\n\nupdated line 3");
221
- });
222
-
223
- test("should handle diff with trailing newlines", async () => {
224
- mockOptions.context.userContext.currentContent = "line 1\nline 2\n";
225
- const diffPatch = "@@ -1,2 +1,2 @@\n-line 1\n+updated line 1\n line 2";
226
-
227
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
228
-
229
- expect(result.success).toBe(true);
230
- // Note: applyPatch may normalize trailing newlines
231
- const content = extractContent(result.updatedContent);
232
- expect(content).toContain("updated line 1");
233
- expect(content).toContain("line 2");
234
- });
235
-
236
- // REALISTIC DOCUMENTATION UPDATE SCENARIOS
237
- test("should handle updating code blocks", async () => {
238
- mockOptions.context.userContext.currentContent =
239
- "# API Reference\n\n```javascript\nfunction oldFunction() {\n return 'old';\n}\n```\n\nDescription here.";
240
- const diffPatch =
241
- "@@ -3,3 +3,3 @@\n # API Reference\n \n ```javascript\n-function oldFunction() {\n- return 'old';\n+function newFunction() {\n+ return 'new';\n }\n ```";
242
-
243
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
244
-
245
- expect(result.success).toBe(true);
246
- const content = extractContent(result.updatedContent);
247
- expect(content).toContain("function newFunction()");
248
- expect(content).toContain("return 'new';");
249
- });
250
-
251
- test("should handle adding new sections", async () => {
252
- mockOptions.context.userContext.currentContent =
253
- "# Documentation\n\n## Section 1\n\nContent 1\n\n## Section 3\n\nContent 3";
254
- const diffPatch =
255
- "@@ -4,0 +5,3 @@\n Content 1\n \n+## Section 2\n+\n+Content 2\n+\n ## Section 3";
256
-
257
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
258
-
259
- expect(result.success).toBe(true);
260
- const content = extractContent(result.updatedContent);
261
- expect(content).toContain("## Section 2");
262
- expect(content).toContain("Content 2");
263
- });
264
-
265
- test("should handle removing outdated content", async () => {
266
- mockOptions.context.userContext.currentContent =
267
- "# Guide\n\n## Current Feature\n\nThis is current.\n\n## Deprecated Feature\n\nThis is deprecated.\n\n## Another Feature\n\nThis is also current.";
268
- const diffPatch =
269
- "@@ -5,4 +5,0 @@\n This is current.\n \n-## Deprecated Feature\n-\n-This is deprecated.\n-\n ## Another Feature";
270
-
271
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
272
-
273
- expect(result.success).toBe(true);
274
- const content = extractContent(result.updatedContent);
275
- expect(content).not.toContain("Deprecated Feature");
276
- expect(content).toContain("Current Feature");
277
- expect(content).toContain("Another Feature");
278
- });
279
-
280
- // ERROR SCENARIOS WITH REALISTIC CONTENT
281
- test("should handle conflicting patches gracefully", async () => {
282
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3";
283
- // This patch tries to modify content that doesn't match exactly
284
- const diffPatch =
285
- "@@ -1,3 +1,3 @@\n-different line 1\n-different line 2\n+updated line 1\n+updated line 2\n line 3";
286
-
287
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
288
-
289
- expect(result.success).toBe(false);
290
- expect(result.error.message).toContain("Cannot find matching context");
291
- });
292
-
293
- test("should handle patches with incorrect line counts", async () => {
294
- mockOptions.context.userContext.currentContent = "line 1\nline 2\nline 3\nline 4";
295
- // Incorrect line count in hunk header (says 5 lines but content has 4)
296
- const diffPatch = "@@ -1,5 +1,3 @@\n-line 1\n-line 2\n line 3\n line 4";
297
-
298
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
299
-
300
- expect(result.success).toBe(true);
301
- expect(extractContent(result.updatedContent)).toBe("line 3\nline 4");
302
- });
303
-
304
- // FUZZY MATCHING EDGE CASES
305
- test("should succeed fuzzy matching with high similarity", async () => {
306
- mockOptions.context.userContext.currentContent =
307
- "function calculateTotal(items) {\n let total = 0;\n for (item of items) {\n total += item.price;\n }\n return total;\n}";
308
- // Patch has slight differences but should match with fuzzy matching
309
- const diffPatch =
310
- "@@ -2,2 +2,2 @@\n function calculateTotal(items) {\n- let total = 0;\n+ let sum = 0;\n for (item of items) {";
311
-
312
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
313
-
314
- expect(result.success).toBe(true);
315
- expect(extractContent(result.updatedContent)).toContain("let sum = 0;");
316
- });
317
-
318
- test("should fail fuzzy matching with low similarity", async () => {
319
- mockOptions.context.userContext.currentContent =
320
- "completely different content\nwith nothing similar\nat all";
321
- const diffPatch =
322
- "@@ -1,2 +1,2 @@\n-some totally different text\n+updated text\n that has no relation";
323
-
324
- const result = await updateDocumentContent({ diffPatch }, mockOptions);
325
-
326
- expect(result.success).toBe(false);
327
- expect(result.error.message).toContain("Cannot find matching context");
328
- });
329
- });
@@ -1,51 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
- import { join } from "node:path";
3
- import { AIAgent } from "@aigne/core";
4
- import { loadAgent } from "@aigne/core/loader/index.js";
5
- import { loadModel } from "../../utils/mock-chat-model.mjs";
6
-
7
- describe("generateDocument Agent", () => {
8
- beforeAll(() => {
9
- process.env.AIGNE_OBSERVABILITY_DISABLED = "true";
10
- });
11
-
12
- afterAll(() => {
13
- delete process.env.AIGNE_OBSERVABILITY_DISABLED;
14
- });
15
- test("should load agent correctly with proper configuration", async () => {
16
- const agent = await loadAgent(
17
- join(import.meta.dirname, "../../../agents/update/generate-document.yaml"),
18
- {
19
- model: loadModel,
20
- },
21
- );
22
-
23
- expect(agent).toBeDefined();
24
-
25
- // Verify agent exists and is correct type
26
- expect(agent).toBeDefined();
27
- expect(agent).toBeInstanceOf(AIAgent);
28
- expect(agent.name).toBe("generateDocument");
29
- });
30
-
31
- test("should have instructions loaded from file", async () => {
32
- const agent = await loadAgent(
33
- join(import.meta.dirname, "../../../agents/update/generate-document.yaml"),
34
- {
35
- model: loadModel,
36
- },
37
- );
38
-
39
- expect(agent).toBeDefined();
40
-
41
- // Verify instructions are loaded
42
- expect(agent.instructions).toBeDefined();
43
- const instructions = await agent.instructions.build({});
44
- expect(instructions.messages).toBeDefined();
45
- expect(instructions.messages.length).toBeGreaterThan(0);
46
-
47
- // The instructions should contain content from the prompt file
48
- const systemMessage = instructions.messages.find((m) => m.role === "system");
49
- expect(systemMessage).toBeDefined();
50
- });
51
- });