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

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 +15 -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,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
- });