@afterxleep/doc-bot 1.17.0 → 1.19.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 (86) hide show
  1. package/package.json +7 -4
  2. package/src/__tests__/temp-docs-1756129972061/test.md +5 -0
  3. package/src/__tests__/temp-docs-1756129972071/test.md +5 -0
  4. package/src/__tests__/temp-docs-1756129972075/test.md +5 -0
  5. package/src/__tests__/temp-docs-1756129972077/test.md +5 -0
  6. package/src/__tests__/temp-docs-1756129972079/test.md +5 -0
  7. package/src/__tests__/temp-docs-1756130189361/test.md +5 -0
  8. package/src/__tests__/temp-docs-1756130189372/test.md +5 -0
  9. package/src/__tests__/temp-docs-1756130189375/test.md +5 -0
  10. package/src/__tests__/temp-docs-1756130189378/test.md +5 -0
  11. package/src/__tests__/temp-docs-1756130189379/test.md +5 -0
  12. package/src/__tests__/temp-docs-1756130271128/test.md +5 -0
  13. package/src/__tests__/temp-docs-1756130271139/test.md +5 -0
  14. package/src/__tests__/temp-docs-1756130271142/test.md +5 -0
  15. package/src/__tests__/temp-docs-1756130271145/test.md +5 -0
  16. package/src/__tests__/temp-docs-1756130271146/test.md +5 -0
  17. package/src/__tests__/temp-docs-1756130687030/test.md +5 -0
  18. package/src/__tests__/temp-docs-1756130687044/test.md +5 -0
  19. package/src/__tests__/temp-docs-1756130687048/test.md +5 -0
  20. package/src/__tests__/temp-docs-1756130687051/test.md +5 -0
  21. package/src/__tests__/temp-docs-1756130687053/test.md +5 -0
  22. package/src/__tests__/temp-docs-1756131694925/test.md +5 -0
  23. package/src/__tests__/temp-docs-1756131694937/test.md +5 -0
  24. package/src/__tests__/temp-docs-1756131694941/test.md +5 -0
  25. package/src/__tests__/temp-docs-1756131694944/test.md +5 -0
  26. package/src/__tests__/temp-docs-1756131694946/test.md +5 -0
  27. package/src/__tests__/temp-docs-1756133998710/test.md +5 -0
  28. package/src/__tests__/temp-docs-1756133998721/test.md +5 -0
  29. package/src/__tests__/temp-docs-1756133998724/test.md +5 -0
  30. package/src/__tests__/temp-docs-1756133998727/test.md +5 -0
  31. package/src/__tests__/temp-docs-1756133998729/test.md +5 -0
  32. package/src/__tests__/temp-docs-1756134345935/test.md +5 -0
  33. package/src/__tests__/temp-docs-1756134345948/test.md +5 -0
  34. package/src/__tests__/temp-docs-1756134345952/test.md +5 -0
  35. package/src/__tests__/temp-docs-1756134345954/test.md +5 -0
  36. package/src/__tests__/temp-docs-1756134345957/test.md +5 -0
  37. package/src/__tests__/temp-docsets-1756129972079/2e443167/Mock.docset/Contents/Info.plist +10 -0
  38. package/src/__tests__/temp-docsets-1756129972079/2e443167/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  39. package/src/__tests__/temp-docsets-1756129972079/Mock.docset/Contents/Info.plist +10 -0
  40. package/src/__tests__/temp-docsets-1756129972079/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  41. package/src/__tests__/temp-docsets-1756129972079/docsets.json +10 -0
  42. package/src/__tests__/temp-docsets-1756130189379/Mock.docset/Contents/Info.plist +10 -0
  43. package/src/__tests__/temp-docsets-1756130189379/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  44. package/src/__tests__/temp-docsets-1756130189379/a4934c14/Mock.docset/Contents/Info.plist +10 -0
  45. package/src/__tests__/temp-docsets-1756130189379/a4934c14/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  46. package/src/__tests__/temp-docsets-1756130189379/docsets.json +10 -0
  47. package/src/__tests__/temp-docsets-1756130271146/3f8acbb2/Mock.docset/Contents/Info.plist +10 -0
  48. package/src/__tests__/temp-docsets-1756130271146/3f8acbb2/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  49. package/src/__tests__/temp-docsets-1756130271146/Mock.docset/Contents/Info.plist +10 -0
  50. package/src/__tests__/temp-docsets-1756130271146/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  51. package/src/__tests__/temp-docsets-1756130271146/docsets.json +10 -0
  52. package/src/__tests__/temp-docsets-1756130687053/6810e6bd/Mock.docset/Contents/Info.plist +10 -0
  53. package/src/__tests__/temp-docsets-1756130687053/6810e6bd/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  54. package/src/__tests__/temp-docsets-1756130687053/Mock.docset/Contents/Info.plist +10 -0
  55. package/src/__tests__/temp-docsets-1756130687053/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  56. package/src/__tests__/temp-docsets-1756130687053/docsets.json +10 -0
  57. package/src/__tests__/temp-docsets-1756131694946/Mock.docset/Contents/Info.plist +10 -0
  58. package/src/__tests__/temp-docsets-1756131694946/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  59. package/src/__tests__/temp-docsets-1756131694946/dd703046/Mock.docset/Contents/Info.plist +10 -0
  60. package/src/__tests__/temp-docsets-1756131694946/dd703046/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  61. package/src/__tests__/temp-docsets-1756131694946/docsets.json +10 -0
  62. package/src/__tests__/temp-docsets-1756133998729/9e061136/Mock.docset/Contents/Info.plist +10 -0
  63. package/src/__tests__/temp-docsets-1756133998729/9e061136/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  64. package/src/__tests__/temp-docsets-1756133998729/Mock.docset/Contents/Info.plist +10 -0
  65. package/src/__tests__/temp-docsets-1756133998729/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  66. package/src/__tests__/temp-docsets-1756133998729/docsets.json +10 -0
  67. package/src/__tests__/temp-docsets-1756134345957/03e730af/Mock.docset/Contents/Info.plist +10 -0
  68. package/src/__tests__/temp-docsets-1756134345957/03e730af/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  69. package/src/__tests__/temp-docsets-1756134345957/Mock.docset/Contents/Info.plist +10 -0
  70. package/src/__tests__/temp-docsets-1756134345957/Mock.docset/Contents/Resources/docSet.dsidx +0 -0
  71. package/src/__tests__/temp-docsets-1756134345957/docsets.json +10 -0
  72. package/src/index.js +269 -63
  73. package/src/services/DocumentationService.js +26 -1
  74. package/src/services/PaginationService.js +378 -0
  75. package/src/services/__tests__/PaginationService.integration.test.js +185 -0
  76. package/src/services/__tests__/PaginationService.test.js +398 -0
  77. package/src/utils/TokenEstimator.js +134 -0
  78. package/prompts/file-docs.md +0 -69
  79. package/prompts/global-rules.md +0 -142
  80. package/prompts/mandatory-rules.md +0 -90
  81. package/prompts/search-results.md +0 -59
  82. package/prompts/system-prompt.md +0 -270
  83. package/src/__tests__/docset-integration.test.js +0 -146
  84. package/src/services/__tests__/DocumentationService.test.js +0 -318
  85. package/src/services/__tests__/UnifiedSearchService.test.js +0 -302
  86. package/src/services/docset/__tests__/EnhancedDocsetDatabase.test.js +0 -324
@@ -1,324 +0,0 @@
1
- import { DocsetDatabase, MultiDocsetDatabase } from '../database.js';
2
- import Database from 'better-sqlite3';
3
- import path from 'path';
4
- import fs from 'fs-extra';
5
- import { fileURLToPath } from 'url';
6
- import { dirname } from 'path';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = dirname(__filename);
10
-
11
- describe('Enhanced DocsetDatabase', () => {
12
- let tempDir;
13
- let docsetInfo;
14
- let docsetDb;
15
- let sqliteDb;
16
-
17
- beforeEach(async () => {
18
- // Create temporary docset structure
19
- tempDir = path.join(__dirname, 'temp-docset-' + Date.now());
20
- const resourcesPath = path.join(tempDir, 'Contents', 'Resources');
21
- await fs.ensureDir(resourcesPath);
22
-
23
- // Create SQLite database
24
- const dbPath = path.join(resourcesPath, 'docSet.dsidx');
25
- sqliteDb = new Database(dbPath);
26
- sqliteDb.exec(`
27
- CREATE TABLE searchIndex(
28
- id INTEGER PRIMARY KEY,
29
- name TEXT,
30
- type TEXT,
31
- path TEXT
32
- );
33
- `);
34
-
35
- // Insert test data
36
- const stmt = sqliteDb.prepare('INSERT INTO searchIndex (name, type, path) VALUES (?, ?, ?)');
37
- stmt.run('AlarmKit', 'Framework', 'alarmkit.html');
38
- stmt.run('AlarmKit.Alarm', 'Class', 'alarmkit/alarm.html');
39
- stmt.run('AlarmKit.AlarmManager', 'Class', 'alarmkit/manager.html');
40
- stmt.run('URLSession', 'Class', 'urlsession.html');
41
- stmt.run('URLSession.shared', 'Property', 'urlsession/shared.html');
42
- stmt.run('URLSessionConfiguration', 'Class', 'urlsessionconfig.html');
43
- stmt.run('TestFramework', 'Framework', 'test.html');
44
- sqliteDb.close();
45
-
46
- docsetInfo = {
47
- id: 'test-docset',
48
- name: 'Test Docset',
49
- path: tempDir
50
- };
51
-
52
- docsetDb = new DocsetDatabase(docsetInfo);
53
- });
54
-
55
- afterEach(async () => {
56
- docsetDb.close();
57
- await fs.remove(tempDir);
58
- });
59
-
60
- describe('searchWithTerms', () => {
61
- it('should find exact phrase matches with high score', () => {
62
- const results = docsetDb.searchWithTerms(['alarmkit', 'alarm'], null, 10);
63
-
64
- const exactMatch = results.find(r => r.name === 'AlarmKit.Alarm');
65
- expect(exactMatch).toBeDefined();
66
- expect(exactMatch.isExactPhrase).toBe(true);
67
- expect(exactMatch.relevanceScore).toBeGreaterThan(90);
68
- });
69
-
70
- it('should find entries containing all search terms', () => {
71
- const results = docsetDb.searchWithTerms(['urlsession', 'configuration'], null, 10);
72
-
73
- // Should find URLSessionConfiguration since it contains both terms
74
- const configResult = results.find(r => r.name === 'URLSessionConfiguration');
75
- expect(configResult).toBeDefined();
76
- expect(configResult.matchedTerms).toBe(2);
77
- });
78
-
79
- it('should prioritize entries with all terms over partial matches', () => {
80
- const results = docsetDb.searchWithTerms(['urlsession', 'shared'], null, 10);
81
-
82
- // URLSession.shared should rank first as it contains both terms
83
- expect(results[0].name).toBe('URLSession.shared');
84
- expect(results[0].matchedTerms).toBe(2);
85
- });
86
-
87
- it('should handle single term searches', () => {
88
- const results = docsetDb.searchWithTerms(['alarmkit'], null, 10);
89
-
90
- expect(results.length).toBeGreaterThan(0);
91
- const frameworkResult = results.find(r => r.name === 'AlarmKit' && r.type === 'Framework');
92
- expect(frameworkResult).toBeDefined();
93
- });
94
-
95
- it('should respect type filter', () => {
96
- const results = docsetDb.searchWithTerms(['alarmkit'], 'Class', 10);
97
-
98
- expect(results.every(r => r.type === 'Class')).toBe(true);
99
- expect(results.some(r => r.name.includes('AlarmKit'))).toBe(true);
100
- });
101
-
102
- it('should prefer shorter names for equal relevance', () => {
103
- const results = docsetDb.searchWithTerms(['test'], null, 10);
104
-
105
- if (results.length > 1 && results[0].relevanceScore === results[1].relevanceScore) {
106
- expect(results[0].name.length).toBeLessThanOrEqual(results[1].name.length);
107
- }
108
- });
109
-
110
- it('should score exact name matches highest', () => {
111
- const results = docsetDb.searchWithTerms(['urlsession'], null, 10);
112
-
113
- const exactMatch = results.find(r => r.name.toLowerCase() === 'urlsession');
114
- if (exactMatch) {
115
- expect(results.indexOf(exactMatch)).toBeLessThan(3); // Should be in top 3
116
- }
117
- });
118
-
119
- it('should handle no matches gracefully', () => {
120
- const results = docsetDb.searchWithTerms(['nonexistent', 'terms'], null, 10);
121
-
122
- expect(results).toEqual([]);
123
- });
124
- });
125
- });
126
-
127
- describe('MultiDocsetDatabase enhanced features', () => {
128
- let multiDb;
129
- let tempDirs;
130
-
131
- beforeEach(async () => {
132
- multiDb = new MultiDocsetDatabase();
133
- tempDirs = [];
134
-
135
- // Create multiple mock docsets
136
- for (let i = 0; i < 2; i++) {
137
- const tempDir = path.join(__dirname, `temp-docset-${i}-${Date.now()}`);
138
- tempDirs.push(tempDir);
139
-
140
- const resourcesPath = path.join(tempDir, 'Contents', 'Resources');
141
- await fs.ensureDir(resourcesPath);
142
-
143
- const dbPath = path.join(resourcesPath, 'docSet.dsidx');
144
- const db = new Database(dbPath);
145
- db.exec(`
146
- CREATE TABLE searchIndex(
147
- id INTEGER PRIMARY KEY,
148
- name TEXT,
149
- type TEXT,
150
- path TEXT
151
- );
152
- `);
153
-
154
- // Insert different data in each docset
155
- const stmt = db.prepare('INSERT INTO searchIndex (name, type, path) VALUES (?, ?, ?)');
156
- if (i === 0) {
157
- stmt.run('AlarmKit', 'Framework', 'alarmkit.html?language=swift');
158
- stmt.run('AlarmKit', 'Framework', 'alarmkit.html'); // Duplicate without Swift
159
- stmt.run('AlarmKit.Alarm', 'Class', 'alarm.html');
160
- } else {
161
- stmt.run('NotificationKit', 'Framework', 'notifkit.html');
162
- stmt.run('AlarmKit.Schedule', 'Class', 'schedule.html');
163
- }
164
- db.close();
165
-
166
- multiDb.addDocset({
167
- id: `docset-${i}`,
168
- name: `Docset ${i}`,
169
- path: tempDir
170
- });
171
- }
172
- });
173
-
174
- afterEach(async () => {
175
- multiDb.closeAll();
176
- for (const dir of tempDirs) {
177
- await fs.remove(dir);
178
- }
179
- });
180
-
181
- describe('searchWithTerms across multiple docsets', () => {
182
- it('should search all docsets and combine results', () => {
183
- const results = multiDb.searchWithTerms(['alarmkit'], { limit: 10 });
184
-
185
- expect(results.length).toBeGreaterThan(0);
186
- // Should find entries from both docsets
187
- const docsetIds = new Set(results.map(r => r.docsetId));
188
- expect(docsetIds.size).toBe(2);
189
- });
190
-
191
- it('should deduplicate results preferring Swift entries', () => {
192
- const results = multiDb.searchWithTerms(['alarmkit'], { limit: 10 });
193
-
194
- // Count AlarmKit Framework entries
195
- const alarmKitFrameworks = results.filter(r =>
196
- r.name === 'AlarmKit' && r.type === 'Framework'
197
- );
198
-
199
- // Should only have one after deduplication
200
- expect(alarmKitFrameworks.length).toBe(1);
201
- // And it should be the Swift version
202
- expect(alarmKitFrameworks[0].url).toContain('language=swift');
203
- });
204
-
205
- it('should respect docsetId filter', () => {
206
- const results = multiDb.searchWithTerms(['alarmkit'], {
207
- docsetId: 'docset-0',
208
- limit: 10
209
- });
210
-
211
- expect(results.every(r => r.docsetId === 'docset-0')).toBe(true);
212
- });
213
-
214
- it('should sort by relevance score', () => {
215
- const results = multiDb.searchWithTerms(['alarmkit'], { limit: 10 });
216
-
217
- for (let i = 1; i < results.length; i++) {
218
- expect(results[i].relevanceScore).toBeLessThanOrEqual(results[i-1].relevanceScore);
219
- }
220
- });
221
- });
222
-
223
- describe('exploreAPI', () => {
224
- it('should find framework and related entries', () => {
225
- const exploration = multiDb.exploreAPI('AlarmKit');
226
-
227
- expect(exploration.framework).toBeDefined();
228
- expect(exploration.framework.name).toBe('AlarmKit');
229
- expect(exploration.classes.length).toBeGreaterThan(0);
230
- expect(exploration.classes.some(c => c.name === 'AlarmKit.Alarm')).toBe(true);
231
- });
232
-
233
- it('should categorize entries by type', () => {
234
- const exploration = multiDb.exploreAPI('AlarmKit');
235
-
236
- // Check that entries are properly categorized
237
- expect(exploration.classes.every(e => e.type === 'Class')).toBe(true);
238
- expect(exploration.framework?.type).toBe('Framework');
239
- });
240
-
241
- it('should search across all docsets', () => {
242
- const exploration = multiDb.exploreAPI('AlarmKit');
243
-
244
- // Should find AlarmKit.Schedule from second docset
245
- expect(exploration.classes.some(c => c.name === 'AlarmKit.Schedule')).toBe(true);
246
- });
247
-
248
- it('should respect docsetId option', () => {
249
- const exploration = multiDb.exploreAPI('AlarmKit', { docsetId: 'docset-0' });
250
-
251
- // Should not find AlarmKit.Schedule which is only in docset-1
252
- expect(exploration.classes.some(c => c.name === 'AlarmKit.Schedule')).toBe(false);
253
- });
254
-
255
- it('should handle entries without exact framework match', () => {
256
- const exploration = multiDb.exploreAPI('URLSession');
257
-
258
- // Even without a Framework entry, should find related classes
259
- expect(exploration.framework).toBeNull();
260
- expect(exploration.classes.length).toBe(0); // No URLSession in our test data
261
- });
262
-
263
- it('should include only specified types', () => {
264
- const exploration = multiDb.exploreAPI('AlarmKit', {
265
- includeTypes: ['Framework', 'Class']
266
- });
267
-
268
- // Should only have frameworks and classes
269
- const allEntries = [
270
- exploration.framework,
271
- ...exploration.classes,
272
- ...exploration.methods,
273
- ...exploration.properties
274
- ].filter(Boolean);
275
-
276
- expect(allEntries.every(e => ['Framework', 'Class'].includes(e.type))).toBe(true);
277
- });
278
- });
279
-
280
- describe('ParallelSearchManager integration', () => {
281
- beforeEach(async () => {
282
- // Add more docsets to trigger parallel search
283
- for (let i = 2; i < 5; i++) {
284
- const tempDir = path.join(__dirname, `temp-docset-${i}-${Date.now()}`);
285
- tempDirs.push(tempDir);
286
-
287
- const resourcesPath = path.join(tempDir, 'Contents', 'Resources');
288
- await fs.ensureDir(resourcesPath);
289
-
290
- const dbPath = path.join(resourcesPath, 'docSet.dsidx');
291
- const db = new Database(dbPath);
292
- db.exec(`
293
- CREATE TABLE searchIndex(
294
- id INTEGER PRIMARY KEY,
295
- name TEXT,
296
- type TEXT,
297
- path TEXT
298
- );
299
- `);
300
-
301
- db.prepare('INSERT INTO searchIndex (name, type, path) VALUES (?, ?, ?)')
302
- .run(`TestClass${i}`, 'Class', `test${i}.html`);
303
- db.close();
304
-
305
- multiDb.addDocset({
306
- id: `docset-${i}`,
307
- name: `Docset ${i}`,
308
- path: tempDir
309
- });
310
- }
311
- });
312
-
313
- it('should use parallel search for multiple docsets', async () => {
314
- // With 5 docsets, should trigger parallel search (threshold is >3)
315
- expect(multiDb.databases.size).toBe(5);
316
-
317
- const results = await multiDb.searchWithTerms(['test'], { limit: 20 });
318
-
319
- // Should find results from multiple docsets
320
- const docsetIds = new Set(results.map(r => r.docsetId));
321
- expect(docsetIds.size).toBeGreaterThanOrEqual(3);
322
- });
323
- });
324
- });