@aigne/doc-smith 0.8.12-beta.7 → 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 (284) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/agents/clear/choose-contents.mjs +14 -1
  3. package/agents/clear/clear-media-description.mjs +129 -0
  4. package/agents/clear/index.yaml +3 -1
  5. package/agents/evaluate/code-snippet.mjs +28 -24
  6. package/agents/evaluate/document-structure.yaml +0 -4
  7. package/agents/evaluate/document.yaml +1 -5
  8. package/agents/generate/index.yaml +1 -0
  9. package/agents/init/index.mjs +10 -0
  10. package/agents/media/batch-generate-media-description.yaml +44 -0
  11. package/agents/media/generate-media-description.yaml +47 -0
  12. package/agents/media/load-media-description.mjs +238 -0
  13. package/agents/publish/index.yaml +4 -0
  14. package/agents/publish/publish-docs.mjs +77 -5
  15. package/agents/publish/translate-meta.mjs +103 -0
  16. package/agents/update/generate-document.yaml +30 -28
  17. package/agents/update/index.yaml +1 -0
  18. package/agents/update/update-document-detail.yaml +3 -1
  19. package/agents/utils/load-sources.mjs +103 -53
  20. package/agents/utils/update-branding.mjs +69 -0
  21. package/aigne.yaml +6 -0
  22. package/assets/report-template/report.html +34 -34
  23. package/package.json +17 -2
  24. package/prompts/common/document/role-and-personality.md +3 -1
  25. package/prompts/detail/d2-diagram/guide.md +7 -1
  26. package/prompts/detail/d2-diagram/user-prompt.md +3 -0
  27. package/prompts/detail/generate/system-prompt.md +6 -7
  28. package/prompts/detail/generate/user-prompt.md +12 -3
  29. package/prompts/detail/update/user-prompt.md +0 -2
  30. package/prompts/evaluate/document-structure.md +6 -7
  31. package/prompts/evaluate/document.md +16 -25
  32. package/prompts/media/media-description/system-prompt.md +35 -0
  33. package/prompts/media/media-description/user-prompt.md +8 -0
  34. package/prompts/structure/update/user-prompt.md +0 -4
  35. package/utils/constants/index.mjs +0 -107
  36. package/utils/file-utils.mjs +86 -0
  37. package/utils/markdown-checker.mjs +0 -20
  38. package/utils/request.mjs +7 -0
  39. package/utils/upload-files.mjs +231 -0
  40. package/utils/utils.mjs +11 -1
  41. package/.aigne/doc-smith/config.yaml +0 -77
  42. package/.aigne/doc-smith/history.yaml +0 -37
  43. package/.aigne/doc-smith/output/structure-plan.json +0 -162
  44. package/.aigne/doc-smith/preferences.yml +0 -97
  45. package/.aigne/doc-smith/upload-cache.yaml +0 -1893
  46. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  47. package/.github/workflows/ci.yml +0 -54
  48. package/.github/workflows/create-release-pr.yaml +0 -21
  49. package/.github/workflows/publish-docs.yml +0 -65
  50. package/.github/workflows/release.yml +0 -49
  51. package/.github/workflows/reviewer.yml +0 -54
  52. package/.release-please-manifest.json +0 -3
  53. package/RELEASE.md +0 -9
  54. package/assets/screenshots/doc-complete-setup.png +0 -0
  55. package/assets/screenshots/doc-generate-docs.png +0 -0
  56. package/assets/screenshots/doc-generate.png +0 -0
  57. package/assets/screenshots/doc-generated-successfully.png +0 -0
  58. package/assets/screenshots/doc-publish.png +0 -0
  59. package/assets/screenshots/doc-regenerate.png +0 -0
  60. package/assets/screenshots/doc-translate-langs.png +0 -0
  61. package/assets/screenshots/doc-translate.png +0 -0
  62. package/assets/screenshots/doc-update.png +0 -0
  63. package/biome.json +0 -73
  64. package/codecov.yml +0 -15
  65. package/docs/_sidebar.md +0 -15
  66. package/docs/configuration-initial-setup.ja.md +0 -179
  67. package/docs/configuration-initial-setup.md +0 -179
  68. package/docs/configuration-initial-setup.zh-TW.md +0 -179
  69. package/docs/configuration-initial-setup.zh.md +0 -179
  70. package/docs/configuration-managing-preferences.ja.md +0 -100
  71. package/docs/configuration-managing-preferences.md +0 -100
  72. package/docs/configuration-managing-preferences.zh-TW.md +0 -100
  73. package/docs/configuration-managing-preferences.zh.md +0 -100
  74. package/docs/configuration.ja.md +0 -96
  75. package/docs/configuration.md +0 -96
  76. package/docs/configuration.zh-TW.md +0 -96
  77. package/docs/configuration.zh.md +0 -96
  78. package/docs/getting-started.ja.md +0 -88
  79. package/docs/getting-started.md +0 -88
  80. package/docs/getting-started.zh-TW.md +0 -88
  81. package/docs/getting-started.zh.md +0 -88
  82. package/docs/guides-cleaning-up.ja.md +0 -51
  83. package/docs/guides-cleaning-up.md +0 -51
  84. package/docs/guides-cleaning-up.zh-TW.md +0 -51
  85. package/docs/guides-cleaning-up.zh.md +0 -51
  86. package/docs/guides-evaluating-documents.ja.md +0 -66
  87. package/docs/guides-evaluating-documents.md +0 -66
  88. package/docs/guides-evaluating-documents.zh-TW.md +0 -66
  89. package/docs/guides-evaluating-documents.zh.md +0 -66
  90. package/docs/guides-generating-documentation.ja.md +0 -151
  91. package/docs/guides-generating-documentation.md +0 -151
  92. package/docs/guides-generating-documentation.zh-TW.md +0 -151
  93. package/docs/guides-generating-documentation.zh.md +0 -151
  94. package/docs/guides-interactive-chat.ja.md +0 -85
  95. package/docs/guides-interactive-chat.md +0 -85
  96. package/docs/guides-interactive-chat.zh-TW.md +0 -85
  97. package/docs/guides-interactive-chat.zh.md +0 -85
  98. package/docs/guides-managing-history.ja.md +0 -48
  99. package/docs/guides-managing-history.md +0 -48
  100. package/docs/guides-managing-history.zh-TW.md +0 -48
  101. package/docs/guides-managing-history.zh.md +0 -48
  102. package/docs/guides-publishing-your-docs.ja.md +0 -78
  103. package/docs/guides-publishing-your-docs.md +0 -78
  104. package/docs/guides-publishing-your-docs.zh-TW.md +0 -78
  105. package/docs/guides-publishing-your-docs.zh.md +0 -78
  106. package/docs/guides-translating-documentation.ja.md +0 -95
  107. package/docs/guides-translating-documentation.md +0 -95
  108. package/docs/guides-translating-documentation.zh-TW.md +0 -95
  109. package/docs/guides-translating-documentation.zh.md +0 -95
  110. package/docs/guides-updating-documentation.ja.md +0 -77
  111. package/docs/guides-updating-documentation.md +0 -77
  112. package/docs/guides-updating-documentation.zh-TW.md +0 -77
  113. package/docs/guides-updating-documentation.zh.md +0 -77
  114. package/docs/guides.ja.md +0 -32
  115. package/docs/guides.md +0 -32
  116. package/docs/guides.zh-TW.md +0 -32
  117. package/docs/guides.zh.md +0 -32
  118. package/docs/overview.ja.md +0 -61
  119. package/docs/overview.md +0 -61
  120. package/docs/overview.zh-TW.md +0 -61
  121. package/docs/overview.zh.md +0 -61
  122. package/docs/release-notes.ja.md +0 -255
  123. package/docs/release-notes.md +0 -255
  124. package/docs/release-notes.zh-TW.md +0 -255
  125. package/docs/release-notes.zh.md +0 -255
  126. package/media.md +0 -19
  127. package/prompts/common/afs/afs-tools-usage.md +0 -5
  128. package/prompts/common/afs/use-afs-instruction.md +0 -1
  129. package/release-please-config.json +0 -14
  130. package/tests/agents/chat/chat.test.mjs +0 -46
  131. package/tests/agents/clear/choose-contents.test.mjs +0 -284
  132. package/tests/agents/clear/clear-auth-tokens.test.mjs +0 -268
  133. package/tests/agents/clear/clear-document-config.test.mjs +0 -167
  134. package/tests/agents/clear/clear-document-structure.test.mjs +0 -380
  135. package/tests/agents/clear/clear-generated-docs.test.mjs +0 -222
  136. package/tests/agents/evaluate/code-snippet.test.mjs +0 -163
  137. package/tests/agents/evaluate/fixtures/api-services.md +0 -87
  138. package/tests/agents/evaluate/fixtures/js-sdk.md +0 -94
  139. package/tests/agents/evaluate/generate-report.test.mjs +0 -312
  140. package/tests/agents/generate/check-document-structure.test.mjs +0 -45
  141. package/tests/agents/generate/check-need-generate-structure.test.mjs +0 -279
  142. package/tests/agents/generate/document-structure-tools/add-document.test.mjs +0 -449
  143. package/tests/agents/generate/document-structure-tools/delete-document.test.mjs +0 -410
  144. package/tests/agents/generate/document-structure-tools/generate-sub-structure.test.mjs +0 -277
  145. package/tests/agents/generate/document-structure-tools/move-document.test.mjs +0 -476
  146. package/tests/agents/generate/document-structure-tools/update-document.test.mjs +0 -548
  147. package/tests/agents/generate/generate-structure.test.mjs +0 -45
  148. package/tests/agents/generate/user-review-document-structure.test.mjs +0 -319
  149. package/tests/agents/history/view.test.mjs +0 -97
  150. package/tests/agents/init/init.test.mjs +0 -1657
  151. package/tests/agents/prefs/prefs.test.mjs +0 -431
  152. package/tests/agents/publish/publish-docs.test.mjs +0 -787
  153. package/tests/agents/translate/choose-language.test.mjs +0 -311
  154. package/tests/agents/translate/translate-document.test.mjs +0 -51
  155. package/tests/agents/update/check-document.test.mjs +0 -463
  156. package/tests/agents/update/check-update-is-single.test.mjs +0 -300
  157. package/tests/agents/update/document-tools/update-document-content.test.mjs +0 -329
  158. package/tests/agents/update/generate-document.test.mjs +0 -51
  159. package/tests/agents/update/save-and-translate-document.test.mjs +0 -369
  160. package/tests/agents/update/user-review-document.test.mjs +0 -582
  161. package/tests/agents/utils/action-success.test.mjs +0 -54
  162. package/tests/agents/utils/check-detail-result.test.mjs +0 -743
  163. package/tests/agents/utils/check-feedback-refiner.test.mjs +0 -478
  164. package/tests/agents/utils/choose-docs.test.mjs +0 -406
  165. package/tests/agents/utils/exit.test.mjs +0 -70
  166. package/tests/agents/utils/feedback-refiner.test.mjs +0 -51
  167. package/tests/agents/utils/find-item-by-path.test.mjs +0 -517
  168. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +0 -382
  169. package/tests/agents/utils/format-document-structure.test.mjs +0 -364
  170. package/tests/agents/utils/fs.test.mjs +0 -267
  171. package/tests/agents/utils/load-sources.test.mjs +0 -1470
  172. package/tests/agents/utils/save-docs.test.mjs +0 -109
  173. package/tests/agents/utils/save-output.test.mjs +0 -315
  174. package/tests/agents/utils/save-single-doc.test.mjs +0 -364
  175. package/tests/agents/utils/transform-detail-datasources.test.mjs +0 -320
  176. package/tests/utils/auth-utils.test.mjs +0 -596
  177. package/tests/utils/blocklet.test.mjs +0 -336
  178. package/tests/utils/conflict-detector.test.mjs +0 -355
  179. package/tests/utils/constants.test.mjs +0 -295
  180. package/tests/utils/d2-utils.test.mjs +0 -437
  181. package/tests/utils/deploy.test.mjs +0 -399
  182. package/tests/utils/docs-finder-utils.test.mjs +0 -650
  183. package/tests/utils/file-utils.test.mjs +0 -521
  184. package/tests/utils/history-utils.test.mjs +0 -206
  185. package/tests/utils/kroki-utils.test.mjs +0 -646
  186. package/tests/utils/linter/fixtures/css/keyword-error.css +0 -1
  187. package/tests/utils/linter/fixtures/css/missing-semicolon.css +0 -1
  188. package/tests/utils/linter/fixtures/css/syntax-error.css +0 -1
  189. package/tests/utils/linter/fixtures/css/undeclare-variable.css +0 -1
  190. package/tests/utils/linter/fixtures/css/unused-variable.css +0 -2
  191. package/tests/utils/linter/fixtures/css/valid-code.css +0 -1
  192. package/tests/utils/linter/fixtures/dockerfile/keyword-error.dockerfile +0 -1
  193. package/tests/utils/linter/fixtures/dockerfile/missing-semicolon.dockerfile +0 -2
  194. package/tests/utils/linter/fixtures/dockerfile/syntax-error.dockerfile +0 -2
  195. package/tests/utils/linter/fixtures/dockerfile/undeclare-variable.dockerfile +0 -1
  196. package/tests/utils/linter/fixtures/dockerfile/unused-variable.dockerfile +0 -1
  197. package/tests/utils/linter/fixtures/dockerfile/valid-code.dockerfile +0 -2
  198. package/tests/utils/linter/fixtures/go/keyword-error.go +0 -5
  199. package/tests/utils/linter/fixtures/go/missing-semicolon.go +0 -5
  200. package/tests/utils/linter/fixtures/go/syntax-error.go +0 -6
  201. package/tests/utils/linter/fixtures/go/undeclare-variable.go +0 -5
  202. package/tests/utils/linter/fixtures/go/unused-variable.go +0 -5
  203. package/tests/utils/linter/fixtures/go/valid-code.go +0 -7
  204. package/tests/utils/linter/fixtures/js/keyword-error.js +0 -3
  205. package/tests/utils/linter/fixtures/js/missing-semicolon.js +0 -6
  206. package/tests/utils/linter/fixtures/js/syntax-error.js +0 -4
  207. package/tests/utils/linter/fixtures/js/undeclare-variable.js +0 -3
  208. package/tests/utils/linter/fixtures/js/unused-variable.js +0 -7
  209. package/tests/utils/linter/fixtures/js/valid-code.js +0 -15
  210. package/tests/utils/linter/fixtures/json/keyword-error.json +0 -1
  211. package/tests/utils/linter/fixtures/json/missing-semicolon.json +0 -1
  212. package/tests/utils/linter/fixtures/json/syntax-error.json +0 -1
  213. package/tests/utils/linter/fixtures/json/undeclare-variable.json +0 -1
  214. package/tests/utils/linter/fixtures/json/unused-variable.json +0 -1
  215. package/tests/utils/linter/fixtures/json/valid-code.json +0 -1
  216. package/tests/utils/linter/fixtures/jsx/keyword-error.jsx +0 -5
  217. package/tests/utils/linter/fixtures/jsx/missing-semicolon.jsx +0 -5
  218. package/tests/utils/linter/fixtures/jsx/syntax-error.jsx +0 -5
  219. package/tests/utils/linter/fixtures/jsx/undeclare-variable.jsx +0 -5
  220. package/tests/utils/linter/fixtures/jsx/unused-variable.jsx +0 -4
  221. package/tests/utils/linter/fixtures/jsx/valid-code.jsx +0 -5
  222. package/tests/utils/linter/fixtures/python/keyword-error.py +0 -3
  223. package/tests/utils/linter/fixtures/python/missing-semicolon.py +0 -2
  224. package/tests/utils/linter/fixtures/python/syntax-error.py +0 -3
  225. package/tests/utils/linter/fixtures/python/undeclare-variable.py +0 -3
  226. package/tests/utils/linter/fixtures/python/unused-variable.py +0 -6
  227. package/tests/utils/linter/fixtures/python/valid-code.py +0 -12
  228. package/tests/utils/linter/fixtures/ruby/keyword-error.rb +0 -2
  229. package/tests/utils/linter/fixtures/ruby/missing-semicolon.rb +0 -1
  230. package/tests/utils/linter/fixtures/ruby/syntax-error.rb +0 -2
  231. package/tests/utils/linter/fixtures/ruby/undeclare-variable.rb +0 -1
  232. package/tests/utils/linter/fixtures/ruby/unused-variable.rb +0 -2
  233. package/tests/utils/linter/fixtures/ruby/valid-code.rb +0 -1
  234. package/tests/utils/linter/fixtures/sass/keyword-error.sass +0 -2
  235. package/tests/utils/linter/fixtures/sass/missing-semicolon.sass +0 -3
  236. package/tests/utils/linter/fixtures/sass/syntax-error.sass +0 -3
  237. package/tests/utils/linter/fixtures/sass/undeclare-variable.sass +0 -2
  238. package/tests/utils/linter/fixtures/sass/unused-variable.sass +0 -4
  239. package/tests/utils/linter/fixtures/sass/valid-code.sass +0 -2
  240. package/tests/utils/linter/fixtures/scss/keyword-error.scss +0 -1
  241. package/tests/utils/linter/fixtures/scss/missing-semicolon.scss +0 -1
  242. package/tests/utils/linter/fixtures/scss/syntax-error.scss +0 -1
  243. package/tests/utils/linter/fixtures/scss/undeclare-variable.scss +0 -1
  244. package/tests/utils/linter/fixtures/scss/unused-variable.scss +0 -2
  245. package/tests/utils/linter/fixtures/scss/valid-code.scss +0 -1
  246. package/tests/utils/linter/fixtures/shell/keyword-error.sh +0 -5
  247. package/tests/utils/linter/fixtures/shell/missing-semicolon.sh +0 -3
  248. package/tests/utils/linter/fixtures/shell/syntax-error.sh +0 -4
  249. package/tests/utils/linter/fixtures/shell/undeclare-variable.sh +0 -3
  250. package/tests/utils/linter/fixtures/shell/unused-variable.sh +0 -4
  251. package/tests/utils/linter/fixtures/shell/valid-code.sh +0 -3
  252. package/tests/utils/linter/fixtures/ts/keyword-error.ts +0 -1
  253. package/tests/utils/linter/fixtures/ts/missing-semicolon.ts +0 -1
  254. package/tests/utils/linter/fixtures/ts/syntax-error.ts +0 -1
  255. package/tests/utils/linter/fixtures/ts/undeclare-variable.ts +0 -1
  256. package/tests/utils/linter/fixtures/ts/unused-variable.ts +0 -3
  257. package/tests/utils/linter/fixtures/ts/valid-code.ts +0 -3
  258. package/tests/utils/linter/fixtures/tsx/keyword-error.tsx +0 -5
  259. package/tests/utils/linter/fixtures/tsx/missing-semicolon.tsx +0 -5
  260. package/tests/utils/linter/fixtures/tsx/syntax-error.tsx +0 -5
  261. package/tests/utils/linter/fixtures/tsx/undeclare-variable.tsx +0 -6
  262. package/tests/utils/linter/fixtures/tsx/unused-variable.tsx +0 -6
  263. package/tests/utils/linter/fixtures/tsx/valid-code.tsx +0 -5
  264. package/tests/utils/linter/fixtures/vue/keyword-error.vue +0 -6
  265. package/tests/utils/linter/fixtures/vue/missing-semicolon.vue +0 -6
  266. package/tests/utils/linter/fixtures/vue/syntax-error.vue +0 -6
  267. package/tests/utils/linter/fixtures/vue/undeclare-variable.vue +0 -6
  268. package/tests/utils/linter/fixtures/vue/unused-variable.vue +0 -7
  269. package/tests/utils/linter/fixtures/vue/valid-code.vue +0 -6
  270. package/tests/utils/linter/fixtures/yaml/keyword-error.yml +0 -1
  271. package/tests/utils/linter/fixtures/yaml/missing-semicolon.yml +0 -2
  272. package/tests/utils/linter/fixtures/yaml/syntax-error.yml +0 -1
  273. package/tests/utils/linter/fixtures/yaml/undeclare-variable.yml +0 -1
  274. package/tests/utils/linter/fixtures/yaml/unused-variable.yml +0 -2
  275. package/tests/utils/linter/fixtures/yaml/valid-code.yml +0 -3
  276. package/tests/utils/linter/index.test.mjs +0 -440
  277. package/tests/utils/linter/scan-results.mjs +0 -42
  278. package/tests/utils/load-config.test.mjs +0 -141
  279. package/tests/utils/markdown/index.test.mjs +0 -478
  280. package/tests/utils/mermaid-validator.test.mjs +0 -541
  281. package/tests/utils/mock-chat-model.mjs +0 -12
  282. package/tests/utils/preferences-utils.test.mjs +0 -465
  283. package/tests/utils/save-value-to-config.test.mjs +0 -483
  284. package/tests/utils/utils.test.mjs +0 -941
@@ -1,582 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
2
- import * as markedModule from "marked";
3
- import userReviewDocument from "../../../agents/update/user-review-document.mjs";
4
- import * as preferencesUtils from "../../../utils/preferences-utils.mjs";
5
-
6
- describe("user-review-document", () => {
7
- let mockOptions;
8
- let mockContent;
9
-
10
- // Spies for internal utils
11
- let getActiveRulesForScopeSpy;
12
- let consoleSpy;
13
- let consoleErrorSpy;
14
- let consoleWarnSpy;
15
- let markedLexerSpy;
16
- let markedSpy;
17
-
18
- beforeEach(() => {
19
- // Reset all mocks
20
- mock.restore();
21
-
22
- mockContent =
23
- "# Getting Started\n\n## Installation\n\nThis is a test document.\n\n### Prerequisites\n\nSome prerequisites here.";
24
-
25
- mockOptions = {
26
- prompts: {
27
- select: mock(async () => "finish"),
28
- input: mock(async () => ""),
29
- },
30
- context: {
31
- agents: {
32
- updateDocumentDetail: {},
33
- checkFeedbackRefiner: {},
34
- },
35
- invoke: mock(async () => ({
36
- updatedContent: "# Updated Content\n\nThis is updated content.",
37
- operationSummary: "Document updated successfully",
38
- })),
39
- userContext: {
40
- currentContent: "",
41
- },
42
- },
43
- };
44
-
45
- // Set up spies for internal utils
46
- getActiveRulesForScopeSpy = spyOn(preferencesUtils, "getActiveRulesForScope").mockReturnValue(
47
- [],
48
- );
49
- consoleSpy = spyOn(console, "log").mockImplementation(() => {});
50
- consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});
51
- consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
52
-
53
- // Mock marked library
54
- markedLexerSpy = spyOn(markedModule.marked, "lexer").mockImplementation(() => [
55
- { type: "heading", depth: 1, text: "Getting Started" },
56
- { type: "heading", depth: 2, text: "Installation" },
57
- { type: "heading", depth: 3, text: "Prerequisites" },
58
- ]);
59
- markedSpy = spyOn(markedModule.marked, "setOptions").mockImplementation(() => {});
60
-
61
- // Clear context mock call history
62
- mockOptions.prompts.select.mockClear();
63
- mockOptions.prompts.input.mockClear();
64
- mockOptions.context.invoke.mockClear();
65
- });
66
-
67
- afterEach(() => {
68
- // Restore all spies
69
- getActiveRulesForScopeSpy?.mockRestore();
70
- consoleSpy?.mockRestore();
71
- consoleErrorSpy?.mockRestore();
72
- consoleWarnSpy?.mockRestore();
73
- markedLexerSpy?.mockRestore();
74
- markedSpy?.mockRestore();
75
- });
76
-
77
- // CONTENT VALIDATION TESTS
78
- test("should return original content when no content provided", async () => {
79
- const result = await userReviewDocument({}, mockOptions);
80
-
81
- expect(result).toBeDefined();
82
- expect(result.content).toBeUndefined();
83
- expect(mockOptions.prompts.select).not.toHaveBeenCalled();
84
- expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
85
- });
86
-
87
- test("should return original content when empty content provided", async () => {
88
- const result = await userReviewDocument({ content: "" }, mockOptions);
89
-
90
- expect(result).toBeDefined();
91
- expect(result.content).toBe("");
92
- expect(mockOptions.prompts.select).not.toHaveBeenCalled();
93
- expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
94
- });
95
-
96
- test("should return original content when only whitespace provided", async () => {
97
- const result = await userReviewDocument({ content: " \n\t " }, mockOptions);
98
-
99
- expect(result).toBeDefined();
100
- expect(result.content).toBe(" \n\t ");
101
- expect(mockOptions.prompts.select).not.toHaveBeenCalled();
102
- expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
103
- });
104
-
105
- // HEADING EXTRACTION TESTS
106
- test("should extract markdown headings correctly", async () => {
107
- mockOptions.prompts.select.mockImplementation(async () => "finish");
108
-
109
- const result = await userReviewDocument(
110
- { content: mockContent, title: "Test Doc" },
111
- mockOptions,
112
- );
113
-
114
- expect(result).toBeDefined();
115
- expect(result.content).toBe(mockContent);
116
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Current Document: Test Doc"));
117
- expect(markedLexerSpy).toHaveBeenCalledWith(mockContent);
118
- });
119
-
120
- test("should handle markdown parsing errors with fallback", async () => {
121
- markedLexerSpy.mockImplementation(() => {
122
- throw new Error("Parsing error");
123
- });
124
-
125
- mockOptions.prompts.select.mockImplementation(async () => "finish");
126
-
127
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
128
-
129
- expect(result).toBeDefined();
130
- expect(result.content).toBe(mockContent);
131
- expect(consoleWarnSpy).toHaveBeenCalledWith(
132
- "Failed to parse markdown with marked library, falling back to regex:",
133
- "Parsing error",
134
- );
135
- });
136
-
137
- test("should handle empty content in heading extraction", async () => {
138
- const emptyContent = "";
139
- mockOptions.prompts.select.mockImplementation(async () => "finish");
140
-
141
- markedLexerSpy.mockReturnValue([]);
142
-
143
- const result = await userReviewDocument({ content: emptyContent }, mockOptions);
144
-
145
- expect(result.content).toBe(emptyContent);
146
- expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
147
- });
148
-
149
- // USER INTERACTION TESTS
150
- test("should finish immediately when user selects finish", async () => {
151
- mockOptions.prompts.select.mockImplementation(async () => "finish");
152
-
153
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
154
-
155
- expect(result.content).toBe(mockContent);
156
- expect(mockOptions.prompts.select).toHaveBeenCalledTimes(1);
157
- expect(mockOptions.prompts.input).not.toHaveBeenCalled();
158
- expect(mockOptions.context.invoke).not.toHaveBeenCalled();
159
- });
160
-
161
- test("should show document details when user selects view", async () => {
162
- mockOptions.prompts.select.mockImplementation(async () => "view");
163
- mockOptions.prompts.input.mockImplementation(async () => ""); // Empty feedback after view
164
-
165
- // Mock the marked function directly
166
- const markedFunctionSpy = spyOn(markedModule, "marked").mockReturnValue(
167
- "Rendered markdown content",
168
- );
169
-
170
- const result = await userReviewDocument(
171
- { content: mockContent, title: "Test Doc" },
172
- mockOptions,
173
- );
174
-
175
- expect(result.content).toBe(mockContent);
176
- expect(mockOptions.prompts.select).toHaveBeenCalledTimes(1);
177
- expect(mockOptions.prompts.input).toHaveBeenCalledTimes(1);
178
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Document: Test Doc"));
179
-
180
- markedFunctionSpy?.mockRestore();
181
- });
182
-
183
- test("should handle marked-terminal rendering errors gracefully", async () => {
184
- mockOptions.prompts.select.mockImplementation(async () => "view");
185
- mockOptions.prompts.input.mockImplementation(async () => ""); // Empty feedback after view
186
-
187
- // Mock the marked function to throw error
188
- const markedFunctionSpy = spyOn(markedModule, "marked").mockImplementation(() => {
189
- throw new Error("Rendering error");
190
- });
191
-
192
- const result = await userReviewDocument(
193
- { content: mockContent, title: "Test Doc" },
194
- mockOptions,
195
- );
196
-
197
- expect(result.content).toBe(mockContent);
198
- expect(consoleSpy).toHaveBeenCalledWith(
199
- expect.stringContaining("Falling back to plain text display"),
200
- );
201
-
202
- markedFunctionSpy?.mockRestore();
203
- });
204
-
205
- // FEEDBACK PROCESSING TESTS
206
- test("should process user feedback and update content", async () => {
207
- const feedback = "Please add more examples";
208
- const updatedContent = "# Updated Content\n\nThis has more examples.";
209
-
210
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
211
- mockOptions.prompts.input
212
- .mockImplementationOnce(async () => feedback)
213
- .mockImplementationOnce(async () => ""); // Exit loop
214
-
215
- mockOptions.context.invoke.mockImplementation(async () => {
216
- // Simulate the agent updating the shared context
217
- mockOptions.context.userContext.currentContent = updatedContent;
218
- return {
219
- updatedContent,
220
- operationSummary: "Added examples successfully",
221
- };
222
- });
223
-
224
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
225
-
226
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
227
- mockOptions.context.agents.updateDocumentDetail,
228
- expect.objectContaining({
229
- originalContent: mockContent,
230
- feedback: feedback,
231
- userPreferences: "",
232
- }),
233
- );
234
- expect(result.content).toBe(updatedContent);
235
- });
236
-
237
- test("should handle empty feedback by exiting loop", async () => {
238
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
239
- mockOptions.prompts.input.mockImplementation(async () => "");
240
-
241
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
242
-
243
- expect(result.content).toBe(mockContent);
244
- expect(mockOptions.context.invoke).not.toHaveBeenCalled();
245
- });
246
-
247
- test("should handle whitespace-only feedback by exiting loop", async () => {
248
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
249
- mockOptions.prompts.input.mockImplementation(async () => " \n\t ");
250
-
251
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
252
-
253
- expect(result.content).toBe(mockContent);
254
- expect(mockOptions.context.invoke).not.toHaveBeenCalled();
255
- });
256
-
257
- // USER PREFERENCES TESTS
258
- test("should include user preferences in update call", async () => {
259
- const feedback = "Improve clarity";
260
- const mockRules = [{ rule: "Keep sections concise" }, { rule: "Use clear headings" }];
261
- const expectedPreferences = "Keep sections concise\n\nUse clear headings";
262
-
263
- getActiveRulesForScopeSpy
264
- .mockImplementationOnce(() => mockRules) // document rules
265
- .mockImplementationOnce(() => []); // global rules
266
-
267
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
268
- mockOptions.prompts.input
269
- .mockImplementationOnce(async () => feedback)
270
- .mockImplementationOnce(async () => "");
271
-
272
- await userReviewDocument({ content: mockContent, path: "/test-doc" }, mockOptions);
273
-
274
- expect(getActiveRulesForScopeSpy).toHaveBeenCalledWith("document", ["/test-doc"]);
275
- expect(getActiveRulesForScopeSpy).toHaveBeenCalledWith("global");
276
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
277
- mockOptions.context.agents.updateDocumentDetail,
278
- expect.objectContaining({
279
- userPreferences: expectedPreferences,
280
- }),
281
- );
282
- });
283
-
284
- test("should combine document and global rules correctly", async () => {
285
- const feedback = "Add examples";
286
- const documentRules = [{ rule: "Document rule 1" }];
287
- const globalRules = [{ rule: "Global rule 1" }, { rule: "Global rule 2" }];
288
- const expectedPreferences = "Document rule 1\n\nGlobal rule 1\n\nGlobal rule 2";
289
-
290
- getActiveRulesForScopeSpy
291
- .mockImplementationOnce(() => documentRules)
292
- .mockImplementationOnce(() => globalRules);
293
-
294
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
295
- mockOptions.prompts.input
296
- .mockImplementationOnce(async () => feedback)
297
- .mockImplementationOnce(async () => "");
298
-
299
- await userReviewDocument({ content: mockContent, path: "/test-doc" }, mockOptions);
300
-
301
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
302
- mockOptions.context.agents.updateDocumentDetail,
303
- expect.objectContaining({
304
- userPreferences: expectedPreferences,
305
- }),
306
- );
307
- });
308
-
309
- // AGENT ERROR HANDLING TESTS
310
- test("should handle missing updateDocumentDetail agent", async () => {
311
- const feedback = "Some feedback";
312
- mockOptions.context.agents = {}; // No updateDocumentDetail agent
313
-
314
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
315
- mockOptions.prompts.input.mockImplementation(async () => feedback);
316
-
317
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
318
-
319
- expect(result.content).toBe(mockContent);
320
- expect(consoleSpy).toHaveBeenCalledWith(
321
- "We can't process your feedback right now. The document update feature is temporarily unavailable.",
322
- );
323
- expect(consoleSpy).toHaveBeenCalledWith(
324
- "Please try again later or contact support if this continues.",
325
- );
326
- });
327
-
328
- test("should handle updateDocumentDetail agent errors", async () => {
329
- const feedback = "Some feedback";
330
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
331
- mockOptions.prompts.input
332
- .mockImplementationOnce(async () => feedback)
333
- .mockImplementationOnce(async () => "");
334
-
335
- mockOptions.context.invoke.mockImplementation(async () => {
336
- const error = new Error("Agent failed");
337
- error.name = "AgentError";
338
- error.stack = "Stack trace here";
339
- throw error;
340
- });
341
-
342
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
343
-
344
- expect(result.content).toBe(mockContent);
345
- expect(consoleErrorSpy).toHaveBeenCalledWith("Error processing your feedback:");
346
- expect(consoleErrorSpy).toHaveBeenCalledWith("Type: AgentError");
347
- expect(consoleErrorSpy).toHaveBeenCalledWith("Message: Agent failed");
348
- expect(consoleErrorSpy).toHaveBeenCalledWith("Stack: Stack trace here");
349
- });
350
-
351
- test("should handle updateDocumentDetail agent returning no content", async () => {
352
- const feedback = "Some feedback";
353
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
354
- mockOptions.prompts.input
355
- .mockImplementationOnce(async () => feedback)
356
- .mockImplementationOnce(async () => "");
357
-
358
- // Agent doesn't update the shared context (simulating failure)
359
- mockOptions.context.invoke.mockImplementation(async () => ({})); // No updatedContent
360
-
361
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
362
-
363
- // Content should remain unchanged since agent didn't update it
364
- expect(result.content).toBe(mockContent);
365
- });
366
-
367
- // FEEDBACK REFINER TESTS
368
- test("should call checkFeedbackRefiner agent when available", async () => {
369
- const feedback = "Improve examples";
370
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
371
- mockOptions.prompts.input
372
- .mockImplementationOnce(async () => feedback)
373
- .mockImplementationOnce(async () => "");
374
-
375
- mockOptions.context.invoke
376
- .mockImplementationOnce(async () => ({
377
- updatedContent: "Updated content",
378
- operationSummary: "Updated successfully",
379
- })) // updateDocumentDetail
380
- .mockImplementationOnce(async () => ({})); // checkFeedbackRefiner
381
-
382
- await userReviewDocument({ content: mockContent }, mockOptions);
383
-
384
- expect(mockOptions.context.invoke).toHaveBeenCalledWith(
385
- mockOptions.context.agents.checkFeedbackRefiner,
386
- expect.objectContaining({
387
- documentContentFeedback: feedback,
388
- stage: "document_refine",
389
- }),
390
- );
391
- });
392
-
393
- test("should handle missing checkFeedbackRefiner agent gracefully", async () => {
394
- const feedback = "Some feedback";
395
- const updatedContent = "# Updated Content\n\nThis is updated content.";
396
- mockOptions.context.agents = { updateDocumentDetail: {} }; // No checkFeedbackRefiner
397
-
398
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
399
- mockOptions.prompts.input
400
- .mockImplementationOnce(async () => feedback)
401
- .mockImplementationOnce(async () => "");
402
-
403
- mockOptions.context.invoke.mockImplementation(async () => {
404
- mockOptions.context.userContext.currentContent = updatedContent;
405
- return { updatedContent, operationSummary: "Updated" };
406
- });
407
-
408
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
409
-
410
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(1); // Only updateDocumentDetail called
411
- expect(result.content).toBe(updatedContent);
412
- });
413
-
414
- test("should handle checkFeedbackRefiner errors gracefully", async () => {
415
- const feedback = "Some feedback";
416
- const updatedContent = "Updated content";
417
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
418
- mockOptions.prompts.input
419
- .mockImplementationOnce(async () => feedback)
420
- .mockImplementationOnce(async () => "");
421
-
422
- mockOptions.context.invoke
423
- .mockImplementationOnce(async () => {
424
- mockOptions.context.userContext.currentContent = updatedContent;
425
- return {
426
- updatedContent,
427
- operationSummary: "Updated successfully",
428
- };
429
- }) // updateDocumentDetail
430
- .mockImplementationOnce(async () => {
431
- throw new Error("Refiner failed");
432
- }); // checkFeedbackRefiner
433
-
434
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
435
-
436
- expect(result.content).toBe(updatedContent);
437
- expect(consoleWarnSpy).toHaveBeenCalledWith(
438
- "We couldn't save your feedback as a preference:",
439
- "Refiner failed",
440
- );
441
- expect(consoleWarnSpy).toHaveBeenCalledWith(
442
- "Your feedback was applied, but we couldn't save it as a preference.",
443
- );
444
- });
445
-
446
- // MULTIPLE ROUNDS TESTS
447
- test("should handle multiple feedback rounds", async () => {
448
- const firstFeedback = "Add more examples";
449
- const secondFeedback = "Improve clarity";
450
- const firstUpdate = "# Content with examples";
451
- const secondUpdate = "# Clear content with examples";
452
-
453
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
454
- mockOptions.prompts.input
455
- .mockImplementationOnce(async () => firstFeedback)
456
- .mockImplementationOnce(async () => secondFeedback)
457
- .mockImplementationOnce(async () => ""); // Exit loop
458
-
459
- let invokeCount = 0;
460
- mockOptions.context.invoke.mockImplementation(async () => {
461
- invokeCount++;
462
- if (invokeCount === 1) {
463
- // First update
464
- mockOptions.context.userContext.currentContent = firstUpdate;
465
- return { updatedContent: firstUpdate, operationSummary: "Added examples" };
466
- } else if (invokeCount === 2) {
467
- // First refiner
468
- return {};
469
- } else if (invokeCount === 3) {
470
- // Second update
471
- mockOptions.context.userContext.currentContent = secondUpdate;
472
- return { updatedContent: secondUpdate, operationSummary: "Improved clarity" };
473
- } else {
474
- // Second refiner
475
- return {};
476
- }
477
- });
478
-
479
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
480
-
481
- expect(mockOptions.context.invoke).toHaveBeenCalledTimes(4);
482
- expect(result.content).toBe(secondUpdate);
483
- });
484
-
485
- test("should stop at maximum iterations to prevent infinite loops", async () => {
486
- mockOptions.prompts.select.mockImplementation(async () => "feedback");
487
- mockOptions.prompts.input.mockImplementation(async () => "Keep giving feedback");
488
-
489
- // Mock a long running process
490
- let callCount = 0;
491
- mockOptions.context.invoke.mockImplementation(async () => {
492
- callCount++;
493
- return {
494
- updatedContent: `Updated content ${callCount}`,
495
- operationSummary: `Update ${callCount}`,
496
- };
497
- });
498
-
499
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
500
-
501
- // Should have stopped due to MAX_ITERATIONS (100)
502
- expect(mockOptions.prompts.input).toHaveBeenCalledTimes(100);
503
- expect(result.content).toBeDefined();
504
- });
505
-
506
- // EDGE CASES
507
- test("should handle document with no title", async () => {
508
- mockOptions.prompts.select.mockImplementation(async () => "finish");
509
-
510
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
511
-
512
- expect(result.content).toBe(mockContent);
513
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Untitled Document"));
514
- });
515
-
516
- test("should handle nested tokens in marked parsing", async () => {
517
- const tokensWithNested = [
518
- {
519
- type: "heading",
520
- depth: 1,
521
- text: "Main Heading",
522
- },
523
- {
524
- type: "list",
525
- items: [],
526
- tokens: [
527
- {
528
- type: "heading",
529
- depth: 2,
530
- text: "Nested Heading",
531
- },
532
- ],
533
- },
534
- ];
535
-
536
- markedLexerSpy.mockReturnValue(tokensWithNested);
537
- mockOptions.prompts.select.mockImplementation(async () => "finish");
538
-
539
- const result = await userReviewDocument({ content: mockContent }, mockOptions);
540
-
541
- expect(result.content).toBe(mockContent);
542
- // Should process both the main heading and nested heading
543
- expect(markedLexerSpy).toHaveBeenCalledWith(mockContent);
544
- });
545
-
546
- test("should handle non-string content gracefully", async () => {
547
- const result = await userReviewDocument({ content: null }, mockOptions);
548
-
549
- expect(result.content).toBeNull();
550
- expect(consoleSpy).toHaveBeenCalledWith("Please provide document content to review.");
551
- });
552
-
553
- // FALLBACK HEADING EXTRACTION TESTS
554
- test("should use fallback regex extraction when marked fails", async () => {
555
- const contentWithHeadings = "# Title\n## Section\n### Subsection\nContent here.";
556
- markedLexerSpy.mockImplementation(() => {
557
- throw new Error("Marked failed");
558
- });
559
-
560
- mockOptions.prompts.select.mockImplementation(async () => "finish");
561
-
562
- const result = await userReviewDocument({ content: contentWithHeadings }, mockOptions);
563
-
564
- expect(result.content).toBe(contentWithHeadings);
565
- expect(consoleWarnSpy).toHaveBeenCalledWith(
566
- "Failed to parse markdown with marked library, falling back to regex:",
567
- "Marked failed",
568
- );
569
- });
570
-
571
- test("should handle content with no headings", async () => {
572
- const contentNoHeadings = "Just some plain text content without any headings.";
573
- markedLexerSpy.mockReturnValue([]);
574
-
575
- mockOptions.prompts.select.mockImplementation(async () => "finish");
576
-
577
- const result = await userReviewDocument({ content: contentNoHeadings }, mockOptions);
578
-
579
- expect(result.content).toBe(contentNoHeadings);
580
- expect(consoleSpy).toHaveBeenCalledWith(" This document has no headings.");
581
- });
582
- });
@@ -1,54 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import actionSuccess from "../../../agents/utils/action-success.mjs";
3
-
4
- describe("action-success", () => {
5
- test("should return success message with action name", async () => {
6
- const result = await actionSuccess({ action: "✅ Document generation successfully" });
7
-
8
- expect(result).toBeDefined();
9
- expect(result).toHaveProperty("message");
10
- expect(result.message).toBe("✅ Document generation successfully");
11
- });
12
-
13
- test("should handle different action names", async () => {
14
- const actions = [
15
- "Configuration setup",
16
- "File processing",
17
- "Translation generation",
18
- "Markdown validation",
19
- ];
20
-
21
- for (const action of actions) {
22
- const result = await actionSuccess({ action });
23
-
24
- expect(result).toBeDefined();
25
- expect(result.message).toBe(`${action}`);
26
- }
27
- });
28
-
29
- test("should handle empty action name", async () => {
30
- const result = await actionSuccess({ action: "" });
31
-
32
- expect(result).toBeDefined();
33
- expect(result.message).toBe("");
34
- });
35
-
36
- test("should handle undefined action", async () => {
37
- const result = await actionSuccess({ action: undefined });
38
-
39
- expect(result).toBeDefined();
40
- expect(result.message).toBe("undefined");
41
- });
42
-
43
- test("should have task_render_mode property", () => {
44
- expect(actionSuccess.task_render_mode).toBe("hide");
45
- });
46
-
47
- test("should handle mermaid worker pool shutdown gracefully", async () => {
48
- // This test ensures the function doesn't throw even if worker pool fails
49
- const result = await actionSuccess({ action: "Test action" });
50
-
51
- expect(result).toBeDefined();
52
- expect(result.message).toBe("Test action");
53
- });
54
- });