@aigne/doc-smith 0.4.5 → 0.6.0

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 (36) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/agents/batch-translate.yaml +3 -0
  3. package/agents/check-detail-result.mjs +2 -1
  4. package/agents/check-detail.mjs +1 -0
  5. package/agents/check-feedback-refiner.mjs +79 -0
  6. package/agents/check-structure-plan.mjs +16 -0
  7. package/agents/detail-generator-and-translate.yaml +3 -0
  8. package/agents/detail-regenerator.yaml +3 -0
  9. package/agents/docs-generator.yaml +3 -0
  10. package/agents/feedback-refiner.yaml +48 -0
  11. package/agents/find-items-by-paths.mjs +5 -1
  12. package/agents/find-user-preferences-by-path.mjs +37 -0
  13. package/agents/input-generator.mjs +8 -9
  14. package/agents/load-sources.mjs +63 -9
  15. package/agents/manage-prefs.mjs +203 -0
  16. package/agents/publish-docs.mjs +3 -1
  17. package/agents/retranslate.yaml +3 -0
  18. package/agents/structure-planning.yaml +3 -0
  19. package/aigne.yaml +4 -0
  20. package/package.json +10 -9
  21. package/prompts/content-detail-generator.md +13 -1
  22. package/prompts/document/detail-generator.md +1 -0
  23. package/prompts/feedback-refiner.md +84 -0
  24. package/prompts/structure-planning.md +8 -0
  25. package/prompts/translator.md +8 -0
  26. package/tests/{test-all-validation-cases.mjs → all-validation-cases.test.mjs} +60 -137
  27. package/tests/check-detail-result.test.mjs +90 -77
  28. package/tests/load-sources.test.mjs +103 -291
  29. package/tests/preferences-utils.test.mjs +369 -0
  30. package/tests/{test-save-docs.mjs → save-docs.test.mjs} +29 -47
  31. package/tests/save-value-to-config.test.mjs +165 -288
  32. package/utils/auth-utils.mjs +1 -1
  33. package/utils/constants.mjs +22 -10
  34. package/utils/markdown-checker.mjs +89 -9
  35. package/utils/preferences-utils.mjs +175 -0
  36. package/utils/utils.mjs +3 -3
@@ -1,3 +1,4 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
1
2
  import { existsSync } from "node:fs";
2
3
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
4
  import { dirname, join } from "node:path";
@@ -44,221 +45,151 @@ async function createInitialConfig(content) {
44
45
  await writeFile(TEST_CONFIG_PATH, content, "utf8");
45
46
  }
46
47
 
47
- // Test utilities
48
- function assertContains(content, expected, message) {
49
- if (!content.includes(expected)) {
50
- throw new Error(
51
- `${message}\nExpected content to contain: ${expected}\nActual content:\n${content}`,
52
- );
53
- }
54
- }
48
+ // Test suite
49
+ describe("saveValueToConfig", () => {
50
+ beforeEach(async () => {
51
+ await setupTestDir();
52
+ });
55
53
 
56
- function assertNotContains(content, unexpected, message) {
57
- if (content.includes(unexpected)) {
58
- throw new Error(
59
- `${message}\nExpected content NOT to contain: ${unexpected}\nActual content:\n${content}`,
60
- );
61
- }
62
- }
54
+ afterEach(async () => {
55
+ await teardownTestDir();
56
+ });
63
57
 
64
- function assertEqual(actual, expected, message) {
65
- if (actual !== expected) {
66
- throw new Error(`${message}\nExpected: ${expected}\nActual: ${actual}`);
67
- }
68
- }
58
+ test("Save string value to empty file", async () => {
59
+ await saveValueToConfig("projectName", "test-project");
60
+ const content = await readConfigFile();
61
+
62
+ expect(content).toContain('projectName: "test-project"');
63
+ });
64
+
65
+ test("Save string value with comment to empty file", async () => {
66
+ await saveValueToConfig("projectDesc", "A test project", "Project description");
67
+ const content = await readConfigFile();
68
+
69
+ expect(content).toContain("# Project description");
70
+ expect(content).toContain('projectDesc: "A test project"');
71
+ });
72
+
73
+ test("Save array value to empty file", async () => {
74
+ await saveValueToConfig("translateLanguages", ["zh", "ja", "ko"]);
75
+ const content = await readConfigFile();
76
+
77
+ expect(content).toContain("translateLanguages:");
78
+ expect(content).toContain(" - zh");
79
+ expect(content).toContain(" - ja");
80
+ expect(content).toContain(" - ko");
81
+ });
82
+
83
+ test("Save empty array", async () => {
84
+ await saveValueToConfig("emptyArray", []);
85
+ const content = await readConfigFile();
86
+
87
+ expect(content).toContain("emptyArray: []");
88
+ });
89
+
90
+ test("Save array with comment", async () => {
91
+ await saveValueToConfig("sourcePaths", ["./src", "./lib"], "Source code paths");
92
+ const content = await readConfigFile();
93
+
94
+ expect(content).toContain("# Source code paths");
95
+ expect(content).toContain("sourcePaths:");
96
+ expect(content).toContain(" - ./src");
97
+ expect(content).toContain(" - ./lib");
98
+ });
99
+
100
+ test("Update existing string value", async () => {
101
+ await createInitialConfig('projectName: "old-project"\nversion: "1.0.0"');
102
+
103
+ await saveValueToConfig("projectName", "new-project");
104
+ const content = await readConfigFile();
105
+
106
+ expect(content).toContain('projectName: "new-project"');
107
+ expect(content).toContain('version: "1.0.0"');
108
+ expect(content).not.toContain("old-project");
109
+ });
69
110
 
70
- // Test cases
71
- const tests = [
72
- // Test 1: Save string value to empty file
73
- {
74
- name: "Save string value to empty file",
75
- async run() {
76
- await saveValueToConfig("projectName", "test-project");
77
- const content = await readConfigFile();
78
-
79
- assertContains(
80
- content,
81
- 'projectName: "test-project"',
82
- "Should save string value with quotes",
83
- );
84
- },
85
- },
86
-
87
- // Test 2: Save string value with comment to empty file
88
- {
89
- name: "Save string value with comment to empty file",
90
- async run() {
91
- await saveValueToConfig("projectDesc", "A test project", "Project description");
92
- const content = await readConfigFile();
93
-
94
- assertContains(content, "# Project description", "Should include comment");
95
- assertContains(content, 'projectDesc: "A test project"', "Should save string value");
96
- },
97
- },
98
-
99
- // Test 3: Save array value to empty file
100
- {
101
- name: "Save array value to empty file",
102
- async run() {
103
- await saveValueToConfig("translateLanguages", ["zh", "ja", "ko"]);
104
- const content = await readConfigFile();
105
-
106
- assertContains(content, "translateLanguages:", "Should have array key");
107
- assertContains(content, " - zh", "Should have first array item");
108
- assertContains(content, " - ja", "Should have second array item");
109
- assertContains(content, " - ko", "Should have third array item");
110
- },
111
- },
112
-
113
- // Test 4: Save empty array
114
- {
115
- name: "Save empty array",
116
- async run() {
117
- await saveValueToConfig("emptyArray", []);
118
- const content = await readConfigFile();
119
-
120
- assertContains(content, "emptyArray: []", "Should save empty array as []");
121
- },
122
- },
123
-
124
- // Test 5: Save array with comment
125
- {
126
- name: "Save array with comment",
127
- async run() {
128
- await saveValueToConfig("sourcePaths", ["./src", "./lib"], "Source code paths");
129
- const content = await readConfigFile();
130
-
131
- assertContains(content, "# Source code paths", "Should include comment");
132
- assertContains(content, "sourcePaths:", "Should have array key");
133
- assertContains(content, " - ./src", "Should have first path");
134
- assertContains(content, " - ./lib", "Should have second path");
135
- },
136
- },
137
-
138
- // Test 6: Update existing string value
139
- {
140
- name: "Update existing string value",
141
- async run() {
142
- await createInitialConfig('projectName: "old-project"\nversion: "1.0.0"');
143
-
144
- await saveValueToConfig("projectName", "new-project");
145
- const content = await readConfigFile();
146
-
147
- assertContains(content, 'projectName: "new-project"', "Should update string value");
148
- assertContains(content, 'version: "1.0.0"', "Should preserve other values");
149
- assertNotContains(content, "old-project", "Should not contain old value");
150
- },
151
- },
152
-
153
- // Test 7: Update existing array value
154
- {
155
- name: "Update existing array value",
156
- async run() {
157
- await createInitialConfig(`translateLanguages:
111
+ test("Update existing array value", async () => {
112
+ await createInitialConfig(`translateLanguages:
158
113
  - en
159
114
  - fr
160
115
  version: "1.0.0"`);
161
116
 
162
- await saveValueToConfig("translateLanguages", ["zh", "ja"]);
163
- const content = await readConfigFile();
164
-
165
- assertContains(content, "translateLanguages:", "Should have array key");
166
- assertContains(content, " - zh", "Should have new first item");
167
- assertContains(content, " - ja", "Should have new second item");
168
- assertNotContains(content, " - en", "Should not contain old first item");
169
- assertNotContains(content, " - fr", "Should not contain old second item");
170
- assertContains(content, 'version: "1.0.0"', "Should preserve other values");
171
- },
172
- },
173
-
174
- // Test 8: Update array to empty array
175
- {
176
- name: "Update array to empty array",
177
- async run() {
178
- await createInitialConfig(`translateLanguages:
117
+ await saveValueToConfig("translateLanguages", ["zh", "ja"]);
118
+ const content = await readConfigFile();
119
+
120
+ expect(content).toContain("translateLanguages:");
121
+ expect(content).toContain(" - zh");
122
+ expect(content).toContain(" - ja");
123
+ expect(content).not.toContain(" - en");
124
+ expect(content).not.toContain(" - fr");
125
+ expect(content).toContain('version: "1.0.0"');
126
+ });
127
+
128
+ test("Update array to empty array", async () => {
129
+ await createInitialConfig(`translateLanguages:
179
130
  - en
180
131
  - fr
181
132
  version: "1.0.0"`);
182
133
 
183
- await saveValueToConfig("translateLanguages", []);
184
- const content = await readConfigFile();
134
+ await saveValueToConfig("translateLanguages", []);
135
+ const content = await readConfigFile();
185
136
 
186
- assertContains(content, "translateLanguages: []", "Should update to empty array");
187
- assertNotContains(content, " - en", "Should remove old items");
188
- assertContains(content, 'version: "1.0.0"', "Should preserve other values");
189
- },
190
- },
137
+ expect(content).toContain("translateLanguages: []");
138
+ expect(content).not.toContain(" - en");
139
+ expect(content).toContain('version: "1.0.0"');
140
+ });
191
141
 
192
- // Test 9: Update empty array to populated array
193
- {
194
- name: "Update empty array to populated array",
195
- async run() {
196
- await createInitialConfig(`translateLanguages: []
142
+ test("Update empty array to populated array", async () => {
143
+ await createInitialConfig(`translateLanguages: []
197
144
  version: "1.0.0"`);
198
145
 
199
- await saveValueToConfig("translateLanguages", ["zh", "ja"]);
200
- const content = await readConfigFile();
201
-
202
- assertContains(content, "translateLanguages:", "Should have array key");
203
- assertContains(content, " - zh", "Should have first item");
204
- assertContains(content, " - ja", "Should have second item");
205
- assertNotContains(content, "translateLanguages: []", "Should not contain empty array format");
206
- assertContains(content, 'version: "1.0.0"', "Should preserve other values");
207
- },
208
- },
209
-
210
- // Test 10: Add comment to existing value without comment
211
- {
212
- name: "Add comment to existing value without comment",
213
- async run() {
214
- await createInitialConfig('projectName: "test-project"\nversion: "1.0.0"');
215
-
216
- await saveValueToConfig("projectName", "updated-project", "Updated project name");
217
- const content = await readConfigFile();
218
-
219
- assertContains(content, "# Updated project name", "Should add comment");
220
- assertContains(content, 'projectName: "updated-project"', "Should update value");
221
- },
222
- },
223
-
224
- // Test 11: Update value that already has comment
225
- {
226
- name: "Update value that already has comment",
227
- async run() {
228
- await createInitialConfig(`# Project information
146
+ await saveValueToConfig("translateLanguages", ["zh", "ja"]);
147
+ const content = await readConfigFile();
148
+
149
+ expect(content).toContain("translateLanguages:");
150
+ expect(content).toContain(" - zh");
151
+ expect(content).toContain(" - ja");
152
+ expect(content).not.toContain("translateLanguages: []");
153
+ expect(content).toContain('version: "1.0.0"');
154
+ });
155
+
156
+ test("Add comment to existing value without comment", async () => {
157
+ await createInitialConfig('projectName: "test-project"\nversion: "1.0.0"');
158
+
159
+ await saveValueToConfig("projectName", "updated-project", "Updated project name");
160
+ const content = await readConfigFile();
161
+
162
+ expect(content).toContain("# Updated project name");
163
+ expect(content).toContain('projectName: "updated-project"');
164
+ });
165
+
166
+ test("Update value that already has comment", async () => {
167
+ await createInitialConfig(`# Project information
229
168
  projectName: "old-project"
230
169
  version: "1.0.0"`);
231
170
 
232
- await saveValueToConfig("projectName", "new-project", "Updated project info");
233
- const content = await readConfigFile();
234
-
235
- assertContains(content, "# Project information", "Should preserve existing comment");
236
- assertContains(content, 'projectName: "new-project"', "Should update value");
237
- assertNotContains(content, "# Updated project info", "Should not add duplicate comment");
238
- },
239
- },
240
-
241
- // Test 12: Complex array with various items
242
- {
243
- name: "Complex array with various items",
244
- async run() {
245
- const complexArray = ["./src/components", "./lib/utils", "./modules/auth"];
246
- await saveValueToConfig("sourcePaths", complexArray, "All source paths");
247
- const content = await readConfigFile();
248
-
249
- assertContains(content, "# All source paths", "Should include comment");
250
- assertContains(content, "sourcePaths:", "Should have array key");
251
- assertContains(content, " - ./src/components", "Should have first complex path");
252
- assertContains(content, " - ./lib/utils", "Should have second complex path");
253
- assertContains(content, " - ./modules/auth", "Should have third complex path");
254
- },
255
- },
256
-
257
- // Test 13: Mixed content preservation
258
- {
259
- name: "Mixed content preservation",
260
- async run() {
261
- await createInitialConfig(`# Project configuration
171
+ await saveValueToConfig("projectName", "new-project", "Updated project info");
172
+ const content = await readConfigFile();
173
+
174
+ expect(content).toContain("# Project information");
175
+ expect(content).toContain('projectName: "new-project"');
176
+ expect(content).not.toContain("# Updated project info");
177
+ });
178
+
179
+ test("Complex array with various items", async () => {
180
+ const complexArray = ["./src/components", "./lib/utils", "./modules/auth"];
181
+ await saveValueToConfig("sourcePaths", complexArray, "All source paths");
182
+ const content = await readConfigFile();
183
+
184
+ expect(content).toContain("# All source paths");
185
+ expect(content).toContain("sourcePaths:");
186
+ expect(content).toContain(" - ./src/components");
187
+ expect(content).toContain(" - ./lib/utils");
188
+ expect(content).toContain(" - ./modules/auth");
189
+ });
190
+
191
+ test("Mixed content preservation", async () => {
192
+ await createInitialConfig(`# Project configuration
262
193
  projectName: "original-project"
263
194
  translateLanguages:
264
195
  - en
@@ -267,104 +198,50 @@ translateLanguages:
267
198
  version: "1.0.0"
268
199
  locale: en`);
269
200
 
270
- await saveValueToConfig("translateLanguages", ["zh", "ja", "ko"], "Updated languages");
271
- const content = await readConfigFile();
272
-
273
- assertContains(content, "# Project configuration", "Should preserve file header comment");
274
- assertContains(content, 'projectName: "original-project"', "Should preserve string value");
275
- assertContains(content, "# Updated languages", "Should add new comment");
276
- assertContains(content, "translateLanguages:", "Should have updated array key");
277
- assertContains(content, " - zh", "Should have new array items");
278
- assertContains(content, " - ja", "Should have new array items");
279
- assertContains(content, " - ko", "Should have new array items");
280
- assertContains(content, "# Other settings", "Should preserve other comments");
281
- assertContains(content, 'version: "1.0.0"', "Should preserve other values");
282
- assertContains(content, "locale: en", "Should preserve other values");
283
- assertNotContains(content, " - en", "Should remove old array items");
284
- assertNotContains(content, " - fr", "Should remove old array items");
285
- },
286
- },
287
-
288
- // Test 14: Array in middle of file
289
- {
290
- name: "Array in middle of file",
291
- async run() {
292
- await createInitialConfig(`projectName: "test-project"
201
+ await saveValueToConfig("translateLanguages", ["zh", "ja", "ko"], "Updated languages");
202
+ const content = await readConfigFile();
203
+
204
+ expect(content).toContain("# Project configuration");
205
+ expect(content).toContain('projectName: "original-project"');
206
+ expect(content).toContain("# Updated languages");
207
+ expect(content).toContain("translateLanguages:");
208
+ expect(content).toContain(" - zh");
209
+ expect(content).toContain(" - ja");
210
+ expect(content).toContain(" - ko");
211
+ expect(content).toContain("# Other settings");
212
+ expect(content).toContain('version: "1.0.0"');
213
+ expect(content).toContain("locale: en");
214
+ expect(content).not.toContain(" - en");
215
+ expect(content).not.toContain(" - fr");
216
+ });
217
+
218
+ test("Array in middle of file", async () => {
219
+ await createInitialConfig(`projectName: "test-project"
293
220
  translateLanguages:
294
221
  - en
295
222
  - fr
296
223
  locale: en
297
224
  version: "1.0.0"`);
298
225
 
299
- await saveValueToConfig("translateLanguages", ["zh"]);
300
- const content = await readConfigFile();
301
-
302
- assertContains(content, 'projectName: "test-project"', "Should preserve content before");
303
- assertContains(content, "translateLanguages:", "Should have array key");
304
- assertContains(content, " - zh", "Should have new array item");
305
- assertContains(content, "locale: en", "Should preserve content after");
306
- assertContains(content, 'version: "1.0.0"', "Should preserve content after");
307
- assertNotContains(content, " - en", "Should remove old items");
308
- assertNotContains(content, " - fr", "Should remove old items");
309
- },
310
- },
311
-
312
- // Test 15: Handle undefined values
313
- {
314
- name: "Handle undefined values",
315
- async run() {
316
- const initialContent = 'projectName: "test-project"';
317
- await createInitialConfig(initialContent);
318
-
319
- await saveValueToConfig("undefinedKey", undefined);
320
- const content = await readConfigFile();
321
-
322
- assertEqual(content, initialContent, "Should not modify file when value is undefined");
323
- },
324
- },
325
- ];
326
-
327
- // Run all tests
328
- async function runTests() {
329
- console.log("🧪 Running saveValueToConfig tests...\n");
330
-
331
- let passed = 0;
332
- let failed = 0;
333
-
334
- for (const test of tests) {
335
- try {
336
- await setupTestDir();
337
- await test.run();
338
- console.log(`✅ ${test.name}`);
339
- passed++;
340
- } catch (error) {
341
- console.log(`❌ ${test.name}`);
342
- console.log(` Error: ${error.message}\n`);
343
- failed++;
344
- } finally {
345
- await teardownTestDir();
346
- }
347
- }
226
+ await saveValueToConfig("translateLanguages", ["zh"]);
227
+ const content = await readConfigFile();
348
228
 
349
- console.log(`\n📊 Test Results:`);
350
- console.log(` Passed: ${passed}`);
351
- console.log(` Failed: ${failed}`);
352
- console.log(` Total: ${tests.length}`);
229
+ expect(content).toContain('projectName: "test-project"');
230
+ expect(content).toContain("translateLanguages:");
231
+ expect(content).toContain(" - zh");
232
+ expect(content).toContain("locale: en");
233
+ expect(content).toContain('version: "1.0.0"');
234
+ expect(content).not.toContain(" - en");
235
+ expect(content).not.toContain(" - fr");
236
+ });
353
237
 
354
- if (failed > 0) {
355
- console.log(`\n❌ ${failed} test(s) failed`);
356
- process.exit(1);
357
- } else {
358
- console.log(`\n🎉 All tests passed!`);
359
- }
360
- }
238
+ test("Handle undefined values", async () => {
239
+ const initialContent = 'projectName: "test-project"';
240
+ await createInitialConfig(initialContent);
361
241
 
362
- // Run tests if this file is executed directly
363
- if (import.meta.url === `file://${process.argv[1]}`) {
364
- runTests().catch((error) => {
365
- console.error("Test runner failed:", error);
366
- process.exit(1);
367
- });
368
- }
242
+ await saveValueToConfig("undefinedKey", undefined);
243
+ const content = await readConfigFile();
369
244
 
370
- export { runTests, tests };
245
+ expect(content).toBe(initialContent);
246
+ });
247
+ });
@@ -91,7 +91,7 @@ export async function getAccessToken(appUrl) {
91
91
  source: `AIGNE DocSmith connect to Discuss Kit`,
92
92
  closeOnSuccess: true,
93
93
  appName: "AIGNE DocSmith",
94
- appLogo: "https://www.aigne.io/image-bin/uploads/a7910a71364ee15a27e86f869ad59009.svg",
94
+ appLogo: "https://docsmith.aigne.io/image-bin/uploads/a7910a71364ee15a27e86f869ad59009.svg",
95
95
  openPage: (pageUrl) => open(pageUrl),
96
96
  });
97
97
 
@@ -86,15 +86,27 @@ export const DEFAULT_INCLUDE_PATTERNS = [
86
86
  "*.yml",
87
87
  "*Dockerfile",
88
88
  "*Makefile",
89
+ // Media files
90
+ "*.jpg",
91
+ "*.jpeg",
92
+ "*.png",
93
+ "*.gif",
94
+ "*.bmp",
95
+ "*.webp",
96
+ "*.svg",
97
+ "*.mp4",
98
+ "*.mov",
99
+ "*.avi",
100
+ "*.mkv",
101
+ "*.webm",
102
+ "*.m4v",
89
103
  ];
90
104
 
91
105
  export const DEFAULT_EXCLUDE_PATTERNS = [
92
106
  "**/aigne-docs/**",
93
107
  "**/doc-smith/**",
94
108
  "**/.aigne/**",
95
- "**/assets/**",
96
109
  "**/data/**",
97
- "**/images/**",
98
110
  "**/public/**",
99
111
  "**/static/**",
100
112
  "**/vendor/**",
@@ -176,13 +188,13 @@ export const DOCUMENT_STYLES = {
176
188
  "Optimizes for: Architecture, concepts, decision rationale.\nSkips: Quick wins, copy-paste solutions.",
177
189
  },
178
190
  solveProblems: {
179
- name: "Solve problems",
191
+ name: "Troubleshoot common issues",
180
192
  description: "Help users troubleshoot and fix issues",
181
193
  content:
182
194
  "Optimizes for: Error scenarios, diagnostics, solutions.\nSkips: Happy path tutorials, feature overviews.",
183
195
  },
184
196
  mixedPurpose: {
185
- name: "Mix of above",
197
+ name: "Serve multiple purposes",
186
198
  description: "Comprehensive documentation covering multiple needs",
187
199
  content:
188
200
  "Optimizes for: Balanced coverage, multiple entry points.\nTrade-off: Longer, requires good navigation.",
@@ -198,13 +210,13 @@ export const TARGET_AUDIENCES = {
198
210
  "Writing: Plain language, UI-focused, avoid technical terms.\nExamples: Screenshots, step-by-step clicks, business outcomes.",
199
211
  },
200
212
  developers: {
201
- name: "Developers integrating",
213
+ name: "Developers integrating your product/API",
202
214
  description: "Engineers adding this to their projects",
203
215
  content:
204
216
  "Writing: Code-first, copy-paste ready, technical accuracy.\nExamples: SDK usage, API calls, configuration snippets.",
205
217
  },
206
218
  devops: {
207
- name: "DevOps/Infrastructure",
219
+ name: "DevOps / SRE / Infrastructure teams",
208
220
  description: "Teams deploying, monitoring, maintaining systems",
209
221
  content:
210
222
  "Writing: Operations-focused, troubleshooting emphasis.\nExamples: Deployment configs, monitoring setup, scaling guides.",
@@ -232,19 +244,19 @@ export const TARGET_AUDIENCES = {
232
244
  // Reader knowledge level - what do readers typically know when they arrive?
233
245
  export const READER_KNOWLEDGE_LEVELS = {
234
246
  completeBeginners: {
235
- name: "Complete beginners",
247
+ name: "Is a total beginner, starting from scratch",
236
248
  description: "New to this domain/technology entirely",
237
249
  content:
238
250
  "Content: Define terms, explain concepts, assume nothing.\nStructure: Linear progression, prerequisite checks.\nTone: Patient, educational, confidence-building.",
239
251
  },
240
252
  domainFamiliar: {
241
- name: "Domain-familiar, tool-new",
253
+ name: "Has used similar tools before",
242
254
  description: "Know the problem space, new to this specific solution",
243
255
  content:
244
256
  'Content: Focus on differences, migration, unique features.\nStructure: Comparison-heavy, "coming from X" sections.\nTone: Efficient, highlight advantages, skip basics.',
245
257
  },
246
258
  experiencedUsers: {
247
- name: "Experienced users",
259
+ name: "Is an expert trying to do something specific",
248
260
  description: "Regular users needing reference/advanced topics",
249
261
  content:
250
262
  "Content: Dense information, edge cases, performance tips.\nStructure: Reference-style, searchable, task-oriented.\nTone: Concise, technical precision, assume competence.",
@@ -256,7 +268,7 @@ export const READER_KNOWLEDGE_LEVELS = {
256
268
  "Content: Symptom → diagnosis → solution format.\nStructure: Problem-first, solution-prominent, escalation paths.\nTone: Clear, actionable, confidence-inspiring.",
257
269
  },
258
270
  exploringEvaluating: {
259
- name: "Exploring/evaluating",
271
+ name: "Is evaluating this tool against others",
260
272
  description: "Trying to understand if this fits their needs",
261
273
  content:
262
274
  "Content: Use cases, comparisons, getting started quickly.\nStructure: Multiple entry points, progressive commitment.\nTone: Persuasive but honest, show value quickly.",