@aigne/doc-smith 0.8.5 → 0.8.7

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 (126) hide show
  1. package/.aigne/doc-smith/output/structure-plan.json +1 -5
  2. package/CHANGELOG.md +25 -0
  3. package/README.md +3 -3
  4. package/agents/{chat.yaml → chat/index.yaml} +7 -7
  5. package/agents/generate/check-document-structure.yaml +30 -0
  6. package/agents/{check-structure-plan.mjs → generate/check-need-generate-structure.mjs} +21 -21
  7. package/agents/generate/generate-structure.yaml +58 -0
  8. package/agents/{docs-generator.yaml → generate/index.yaml} +15 -16
  9. package/agents/generate/refine-document-structure.yaml +12 -0
  10. package/agents/{input-generator.mjs → init/index.mjs} +34 -27
  11. package/agents/{manage-prefs.mjs → prefs/index.mjs} +16 -16
  12. package/agents/publish/index.yaml +17 -0
  13. package/agents/{publish-docs.mjs → publish/publish-docs.mjs} +15 -16
  14. package/agents/schema/{structure-plan-result.yaml → document-execution-structure.yaml} +3 -3
  15. package/agents/schema/document-structure.yaml +26 -0
  16. package/agents/{language-selector.mjs → translate/choose-language.mjs} +5 -5
  17. package/agents/{retranslate.yaml → translate/index.yaml} +17 -18
  18. package/agents/translate/translate-document.yaml +32 -0
  19. package/agents/{batch-translate.yaml → translate/translate-multilingual.yaml} +5 -5
  20. package/agents/update/batch-generate-document.yaml +19 -0
  21. package/agents/{check-detail.mjs → update/check-document.mjs} +16 -16
  22. package/agents/{detail-generator-and-translate.yaml → update/generate-and-translate-document.yaml} +23 -23
  23. package/agents/update/generate-document.yaml +50 -0
  24. package/agents/{detail-regenerator.yaml → update/index.yaml} +16 -17
  25. package/agents/{action-success.mjs → utils/action-success.mjs} +2 -2
  26. package/agents/{check-detail-result.mjs → utils/check-detail-result.mjs} +3 -3
  27. package/agents/{check-feedback-refiner.mjs → utils/check-feedback-refiner.mjs} +6 -6
  28. package/agents/{find-items-by-paths.mjs → utils/choose-docs.mjs} +25 -10
  29. package/agents/{docs-fs.yaml → utils/docs-fs-actor.yaml} +3 -1
  30. package/agents/utils/feedback-refiner.yaml +50 -0
  31. package/agents/{find-item-by-path.mjs → utils/find-item-by-path.mjs} +17 -7
  32. package/agents/{find-user-preferences-by-path.mjs → utils/find-user-preferences-by-path.mjs} +1 -1
  33. package/agents/utils/format-document-structure.mjs +25 -0
  34. package/agents/{load-sources.mjs → utils/load-sources.mjs} +41 -28
  35. package/agents/{save-docs.mjs → utils/save-docs.mjs} +16 -16
  36. package/agents/{save-single-doc.mjs → utils/save-single-doc.mjs} +2 -2
  37. package/agents/{transform-detail-datasources.mjs → utils/transform-detail-datasources.mjs} +1 -1
  38. package/aigne.yaml +35 -35
  39. package/docs/cli-reference.md +1 -1
  40. package/docs/features-generate-documentation.md +1 -1
  41. package/docs/features-update-and-refine.md +2 -2
  42. package/docs-mcp/analyze-docs-relevance.yaml +10 -10
  43. package/docs-mcp/docs-search.yaml +5 -3
  44. package/package.json +10 -8
  45. package/prompts/{document → detail/custom}/custom-code-block.md +6 -6
  46. package/prompts/detail/custom/custom-components.md +172 -0
  47. package/prompts/{document → detail}/d2-chart/rules.md +95 -1
  48. package/prompts/{document → detail}/detail-example.md +80 -61
  49. package/prompts/{document/detail-generator.md → detail/document-rules.md} +4 -8
  50. package/prompts/{content-detail-generator.md → detail/generate-document.md} +48 -25
  51. package/prompts/{check-structure-planning-result.md → structure/check-document-structure.md} +23 -17
  52. package/prompts/{document/structure-planning.md → structure/document-rules.md} +0 -2
  53. package/prompts/{structure-planning.md → structure/generate-structure.md} +51 -30
  54. package/prompts/{document → structure}/structure-example.md +2 -2
  55. package/prompts/{document → structure}/structure-getting-started.md +2 -2
  56. package/prompts/translate/glossary.md +6 -0
  57. package/prompts/{translator.md → translate/translate-document.md} +29 -10
  58. package/prompts/{feedback-refiner.md → utils/feedback-refiner.md} +8 -8
  59. package/tests/agents/chat/chat.test.mjs +46 -0
  60. package/tests/agents/generate/check-document-structure.test.mjs +51 -0
  61. package/tests/agents/generate/check-need-generate-structure.test.mjs +292 -0
  62. package/tests/agents/generate/generate-structure.test.mjs +51 -0
  63. package/tests/{input-generator.test.mjs → agents/init/init.test.mjs} +19 -17
  64. package/tests/agents/prefs/prefs.test.mjs +431 -0
  65. package/tests/agents/publish/publish-docs.test.mjs +642 -0
  66. package/tests/agents/translate/choose-language.test.mjs +311 -0
  67. package/tests/agents/translate/translate-document.test.mjs +51 -0
  68. package/tests/agents/update/check-document.test.mjs +523 -0
  69. package/tests/agents/update/generate-document.test.mjs +51 -0
  70. package/tests/agents/utils/action-success.test.mjs +54 -0
  71. package/tests/{check-detail-result.test.mjs → agents/utils/check-detail-result.test.mjs} +98 -98
  72. package/tests/agents/utils/check-feedback-refiner.test.mjs +478 -0
  73. package/tests/agents/utils/choose-docs.test.mjs +417 -0
  74. package/tests/agents/utils/exit.test.mjs +70 -0
  75. package/tests/agents/utils/feedback-refiner.test.mjs +51 -0
  76. package/tests/agents/utils/find-item-by-path.test.mjs +526 -0
  77. package/tests/agents/utils/find-user-preferences-by-path.test.mjs +382 -0
  78. package/tests/agents/utils/format-document-structure.test.mjs +264 -0
  79. package/tests/agents/utils/fs.test.mjs +267 -0
  80. package/tests/{load-sources.test.mjs → agents/utils/load-sources.test.mjs} +153 -25
  81. package/tests/{save-docs.test.mjs → agents/utils/save-docs.test.mjs} +11 -5
  82. package/tests/agents/utils/save-output.test.mjs +315 -0
  83. package/tests/agents/utils/save-single-doc.test.mjs +364 -0
  84. package/tests/agents/utils/transform-detail-datasources.test.mjs +363 -0
  85. package/tests/utils/auth-utils.test.mjs +358 -0
  86. package/tests/utils/blocklet.test.mjs +334 -0
  87. package/tests/{conflict-resolution.test.mjs → utils/conflict-detector.test.mjs} +3 -3
  88. package/tests/utils/constants.test.mjs +295 -0
  89. package/tests/utils/d2-utils.test.mjs +423 -0
  90. package/tests/utils/deploy.test.mjs +365 -0
  91. package/tests/utils/docs-finder-utils.test.mjs +625 -0
  92. package/tests/utils/file-utils.test.mjs +213 -0
  93. package/tests/{kroki-utils.test.mjs → utils/kroki-utils.test.mjs} +2 -2
  94. package/tests/utils/load-config.test.mjs +141 -0
  95. package/tests/{mermaid-validation.test.mjs → utils/mermaid-validator.test.mjs} +2 -2
  96. package/tests/utils/mock-chat-model.mjs +12 -0
  97. package/tests/{preferences-utils.test.mjs → utils/preferences-utils.test.mjs} +1 -1
  98. package/tests/{save-value-to-config.test.mjs → utils/save-value-to-config.test.mjs} +61 -4
  99. package/tests/utils/utils.test.mjs +939 -0
  100. package/utils/auth-utils.mjs +1 -1
  101. package/utils/conflict-detector.mjs +1 -1
  102. package/utils/constants.mjs +5 -3
  103. package/utils/d2-utils.mjs +194 -0
  104. package/utils/deploy.mjs +3 -3
  105. package/utils/docs-finder-utils.mjs +26 -26
  106. package/utils/icon-map.mjs +26 -0
  107. package/{agents → utils}/load-config.mjs +2 -18
  108. package/utils/markdown-checker.mjs +5 -5
  109. package/agents/batch-docs-detail-generator.yaml +0 -19
  110. package/agents/check-structure-planning-result.yaml +0 -30
  111. package/agents/content-detail-generator.yaml +0 -50
  112. package/agents/feedback-refiner.yaml +0 -52
  113. package/agents/format-structure-plan.mjs +0 -25
  114. package/agents/reflective-structure-planner.yaml +0 -12
  115. package/agents/schema/structure-plan.yaml +0 -26
  116. package/agents/structure-planning.yaml +0 -58
  117. package/agents/team-publish-docs.yaml +0 -18
  118. package/agents/translate.yaml +0 -31
  119. package/prompts/document/custom-components.md +0 -104
  120. package/tests/README.md +0 -93
  121. package/tests/utils.test.mjs +0 -2067
  122. /package/agents/{exit.mjs → utils/exit.mjs} +0 -0
  123. /package/agents/{fs.mjs → utils/fs.mjs} +0 -0
  124. /package/agents/{save-output.mjs → utils/save-output.mjs} +0 -0
  125. /package/prompts/{document → detail}/d2-chart/official-examples.md +0 -0
  126. /package/prompts/{document → detail}/jsx/rules.md +0 -0
@@ -0,0 +1,365 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
2
+ import * as openModule from "open";
3
+ import * as blockletModule from "../../utils/blocklet.mjs";
4
+
5
+ // Import the real utils module and deploy function
6
+ import { deploy } from "../../utils/deploy.mjs";
7
+ import * as utils from "../../utils/utils.mjs";
8
+
9
+ describe("deploy", () => {
10
+ let originalFetch;
11
+ let originalConsole;
12
+ let consoleOutput;
13
+ let saveValueToConfigSpy;
14
+ let originalSetTimeout;
15
+ let getComponentInfoWithMountPointSpy;
16
+ let getComponentInfoSpy;
17
+ let openDefaultSpy;
18
+
19
+ beforeEach(async () => {
20
+ // Reset environment
21
+ process.env.DOC_SMITH_BASE_URL = "https://test.example.com";
22
+ process.env.NODE_ENV = "test";
23
+
24
+ // Mock console to capture output
25
+ consoleOutput = [];
26
+ originalConsole = {
27
+ log: console.log,
28
+ error: console.error,
29
+ };
30
+ console.log = (...args) => consoleOutput.push({ type: "log", args });
31
+ console.error = (...args) => consoleOutput.push({ type: "error", args });
32
+
33
+ // Mock setTimeout to make tests run instantly
34
+ originalSetTimeout = global.setTimeout;
35
+ global.setTimeout = (callback, _delay) => {
36
+ // Call immediately in tests
37
+ return originalSetTimeout(callback, 0);
38
+ };
39
+
40
+ // Mock fetch
41
+ originalFetch = global.fetch;
42
+
43
+ // Use spyOn to mock saveValueToConfig without affecting other tests
44
+ saveValueToConfigSpy = spyOn(utils, "saveValueToConfig").mockResolvedValue();
45
+
46
+ // Spy on blocklet module functions
47
+ getComponentInfoWithMountPointSpy = spyOn(
48
+ blockletModule,
49
+ "getComponentInfoWithMountPoint",
50
+ ).mockResolvedValue({
51
+ mountPoint: "/payment",
52
+ PAYMENT_LINK_ID: "test-payment-id",
53
+ });
54
+
55
+ getComponentInfoSpy = spyOn(blockletModule, "getComponentInfo").mockResolvedValue({
56
+ status: "running",
57
+ });
58
+
59
+ // Spy on open module
60
+ openDefaultSpy = spyOn(openModule, "default").mockResolvedValue();
61
+ });
62
+
63
+ afterEach(() => {
64
+ // Restore originals
65
+ global.fetch = originalFetch;
66
+ global.setTimeout = originalSetTimeout;
67
+ console.log = originalConsole.log;
68
+ console.error = originalConsole.error;
69
+
70
+ // Restore all spies
71
+ saveValueToConfigSpy?.mockRestore();
72
+ getComponentInfoWithMountPointSpy?.mockRestore();
73
+ getComponentInfoSpy?.mockRestore();
74
+ openDefaultSpy?.mockRestore();
75
+
76
+ // Reset environment
77
+ delete process.env.NODE_ENV;
78
+ });
79
+
80
+ test("successful deployment flow", async () => {
81
+ // Mock API responses for the complete flow
82
+ let callCount = 0;
83
+ global.fetch = mock(async (url) => {
84
+ callCount++;
85
+
86
+ // Step 1: Create payment session
87
+ if (url.includes("/api/checkout-sessions/start")) {
88
+ return {
89
+ ok: true,
90
+ status: 200,
91
+ json: async () => ({
92
+ checkoutSession: { id: "checkout-123" },
93
+ paymentUrl: "https://payment.test/checkout-123",
94
+ }),
95
+ };
96
+ }
97
+
98
+ // Step 2-4: Poll payment/installation/service status
99
+ if (url.includes("/api/vendors/order/checkout-123/status")) {
100
+ if (callCount <= 2) {
101
+ // First call: payment completed, installation in progress
102
+ return {
103
+ ok: true,
104
+ status: 200,
105
+ json: async () => ({
106
+ payment_status: "paid",
107
+ vendors: [{ id: "vendor-1", progress: 50, appUrl: null }],
108
+ }),
109
+ };
110
+ } else {
111
+ // Subsequent calls: installation complete
112
+ return {
113
+ ok: true,
114
+ status: 200,
115
+ json: async () => ({
116
+ payment_status: "paid",
117
+ vendors: [{ id: "vendor-1", progress: 100, appUrl: "https://app.test" }],
118
+ }),
119
+ };
120
+ }
121
+ }
122
+
123
+ // Step 5: Get order details
124
+ if (url.includes("/api/vendors/order/checkout-123/detail")) {
125
+ return {
126
+ ok: true,
127
+ status: 200,
128
+ json: async () => ({
129
+ vendors: [
130
+ {
131
+ appUrl: "https://app.test",
132
+ dashboardUrl: "https://dashboard.test",
133
+ homeUrl: "https://home.test",
134
+ token: "auth-token-123",
135
+ },
136
+ ],
137
+ }),
138
+ };
139
+ }
140
+
141
+ throw new Error(`Unexpected URL: ${url}`);
142
+ });
143
+
144
+ const result = await deploy();
145
+
146
+ // Verify result
147
+ expect(result).toEqual({
148
+ appUrl: "https://app.test",
149
+ homeUrl: "https://home.test",
150
+ token: "auth-token-123",
151
+ });
152
+
153
+ // Verify saveValueToConfig was called
154
+ expect(saveValueToConfigSpy).toHaveBeenCalledWith(
155
+ "checkoutId",
156
+ "checkout-123",
157
+ "Checkout ID for document deployment service",
158
+ );
159
+ expect(saveValueToConfigSpy).toHaveBeenCalledWith(
160
+ "paymentUrl",
161
+ expect.stringContaining("payment"),
162
+ "Payment URL for document deployment service",
163
+ );
164
+
165
+ // Verify console output shows progress
166
+ const logs = consoleOutput.filter((o) => o.type === "log").map((o) => o.args.join(" "));
167
+ expect(logs.some((log) => log.includes("Step 1/4: Waiting for payment"))).toBe(true);
168
+ expect(logs.some((log) => log.includes("Step 2/4: Installing service"))).toBe(true);
169
+ expect(logs.some((log) => log.includes("Step 3/4: Starting service"))).toBe(true);
170
+ expect(logs.some((log) => log.includes("Step 4/4: Getting service URL"))).toBe(true);
171
+ expect(logs.some((log) => log.includes("Your website is available at"))).toBe(true);
172
+ });
173
+
174
+ test("handles missing payment link ID", async () => {
175
+ getComponentInfoWithMountPointSpy.mockResolvedValue({
176
+ mountPoint: "/payment",
177
+ PAYMENT_LINK_ID: null,
178
+ });
179
+
180
+ await expect(deploy()).rejects.toThrow("Payment link ID not found");
181
+ });
182
+
183
+ test("handles payment session creation failure", async () => {
184
+ global.fetch = mock(async (url) => {
185
+ if (url.includes("/api/checkout-sessions/start")) {
186
+ return {
187
+ ok: false,
188
+ status: 400,
189
+ json: async () => ({ error: "Payment creation failed" }),
190
+ };
191
+ }
192
+ });
193
+
194
+ await expect(deploy()).rejects.toThrow("Failed to create payment session");
195
+
196
+ const errors = consoleOutput.filter((o) => o.type === "error");
197
+ expect(errors.length).toBeGreaterThan(0);
198
+ });
199
+
200
+ test("handles network errors gracefully", async () => {
201
+ global.fetch = mock(async () => {
202
+ throw new Error("Network connection failed");
203
+ });
204
+
205
+ await expect(deploy()).rejects.toThrow("Failed to create payment session");
206
+ });
207
+
208
+ test("handles browser opening failure gracefully", async () => {
209
+ // Mock successful API flow
210
+ global.fetch = mock(async (url) => {
211
+ if (url.includes("/api/checkout-sessions/start")) {
212
+ return {
213
+ ok: true,
214
+ status: 200,
215
+ json: async () => ({
216
+ checkoutSession: { id: "checkout-123" },
217
+ paymentUrl: "https://payment.test/checkout-123",
218
+ }),
219
+ };
220
+ }
221
+
222
+ if (url.includes("/status")) {
223
+ return {
224
+ ok: true,
225
+ status: 200,
226
+ json: async () => ({
227
+ payment_status: "paid",
228
+ vendors: [{ id: "vendor-1", progress: 100, appUrl: "https://app.test" }],
229
+ }),
230
+ };
231
+ }
232
+
233
+ if (url.includes("/detail")) {
234
+ return {
235
+ ok: true,
236
+ status: 200,
237
+ json: async () => ({
238
+ vendors: [
239
+ {
240
+ appUrl: "https://app.test",
241
+ homeUrl: "https://home.test",
242
+ token: "auth-token-123",
243
+ },
244
+ ],
245
+ }),
246
+ };
247
+ }
248
+ });
249
+
250
+ // Mock open to fail
251
+ openDefaultSpy.mockRejectedValue(new Error("Cannot open browser"));
252
+
253
+ // Call deploy without cached parameters - should still succeed
254
+ const result = await deploy();
255
+
256
+ // Should still complete successfully despite browser opening failure
257
+ expect(result.appUrl).toBe("https://app.test");
258
+ expect(result.homeUrl).toBe("https://home.test");
259
+ expect(result.token).toBe("auth-token-123");
260
+ });
261
+
262
+ test("handles cached checkout ID", async () => {
263
+ // Mock successful status check for cached ID
264
+ global.fetch = mock(async (url) => {
265
+ if (url.includes("/status")) {
266
+ return {
267
+ ok: true,
268
+ status: 200,
269
+ json: async () => ({
270
+ payment_status: "paid",
271
+ vendors: [{ id: "vendor-1", progress: 100, appUrl: "https://app.test" }],
272
+ }),
273
+ };
274
+ }
275
+
276
+ if (url.includes("/detail")) {
277
+ return {
278
+ ok: true,
279
+ status: 200,
280
+ json: async () => ({
281
+ vendors: [
282
+ {
283
+ appUrl: "https://app.test",
284
+ homeUrl: "https://home.test",
285
+ token: "auth-token-123",
286
+ },
287
+ ],
288
+ }),
289
+ };
290
+ }
291
+ });
292
+
293
+ const result = await deploy("existing-checkout-id", "https://cached-payment.url");
294
+
295
+ expect(result.appUrl).toBe("https://app.test");
296
+
297
+ // Should not call open since using cached checkout
298
+ expect(openDefaultSpy).not.toHaveBeenCalled();
299
+ });
300
+
301
+ test("clears checkout ID when cache check fails", async () => {
302
+ // Mock successful responses for the complete flow after cache check fails
303
+ let callCount = 0;
304
+ global.fetch = mock(async (url) => {
305
+ callCount++;
306
+
307
+ // First call: cache check fails
308
+ if (callCount === 1 && url.includes("/status")) {
309
+ throw new Error("Network error during cache check");
310
+ }
311
+
312
+ // Create payment session
313
+ if (url.includes("/api/checkout-sessions/start")) {
314
+ return {
315
+ ok: true,
316
+ status: 200,
317
+ json: async () => ({
318
+ checkoutSession: { id: "new-checkout-123" },
319
+ paymentUrl: "https://payment.test/new-checkout-123",
320
+ }),
321
+ };
322
+ }
323
+
324
+ // Subsequent status checks and detail calls
325
+ if (url.includes("/status")) {
326
+ return {
327
+ ok: true,
328
+ status: 200,
329
+ json: async () => ({
330
+ payment_status: "paid",
331
+ vendors: [{ id: "vendor-1", progress: 100, appUrl: "https://app.test" }],
332
+ }),
333
+ };
334
+ }
335
+
336
+ if (url.includes("/detail")) {
337
+ return {
338
+ ok: true,
339
+ status: 200,
340
+ json: async () => ({
341
+ vendors: [
342
+ {
343
+ appUrl: "https://app.test",
344
+ homeUrl: "https://home.test",
345
+ token: "auth-token-123",
346
+ },
347
+ ],
348
+ }),
349
+ };
350
+ }
351
+ });
352
+
353
+ // Call deploy with invalid cached checkout ID - should clear it and create new one
354
+ const result = await deploy("invalid-checkout-id");
355
+
356
+ expect(result.appUrl).toBe("https://app.test");
357
+
358
+ // Verify that checkoutId was cleared due to cache check failure
359
+ expect(saveValueToConfigSpy).toHaveBeenCalledWith(
360
+ "checkoutId",
361
+ "",
362
+ "Checkout ID for document deployment service",
363
+ );
364
+ });
365
+ });