aidex-mcp 1.4.1

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 (76) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/LICENSE +21 -0
  3. package/MCP-API-REFERENCE.md +690 -0
  4. package/README.md +314 -0
  5. package/build/commands/files.d.ts +28 -0
  6. package/build/commands/files.js +124 -0
  7. package/build/commands/index.d.ts +14 -0
  8. package/build/commands/index.js +14 -0
  9. package/build/commands/init.d.ts +24 -0
  10. package/build/commands/init.js +396 -0
  11. package/build/commands/link.d.ts +45 -0
  12. package/build/commands/link.js +167 -0
  13. package/build/commands/note.d.ts +29 -0
  14. package/build/commands/note.js +105 -0
  15. package/build/commands/query.d.ts +36 -0
  16. package/build/commands/query.js +176 -0
  17. package/build/commands/scan.d.ts +25 -0
  18. package/build/commands/scan.js +104 -0
  19. package/build/commands/session.d.ts +52 -0
  20. package/build/commands/session.js +216 -0
  21. package/build/commands/signature.d.ts +52 -0
  22. package/build/commands/signature.js +171 -0
  23. package/build/commands/summary.d.ts +56 -0
  24. package/build/commands/summary.js +324 -0
  25. package/build/commands/update.d.ts +36 -0
  26. package/build/commands/update.js +273 -0
  27. package/build/constants.d.ts +10 -0
  28. package/build/constants.js +10 -0
  29. package/build/db/database.d.ts +69 -0
  30. package/build/db/database.js +126 -0
  31. package/build/db/index.d.ts +7 -0
  32. package/build/db/index.js +6 -0
  33. package/build/db/queries.d.ts +163 -0
  34. package/build/db/queries.js +273 -0
  35. package/build/db/schema.sql +136 -0
  36. package/build/index.d.ts +13 -0
  37. package/build/index.js +74 -0
  38. package/build/parser/extractor.d.ts +41 -0
  39. package/build/parser/extractor.js +249 -0
  40. package/build/parser/index.d.ts +7 -0
  41. package/build/parser/index.js +7 -0
  42. package/build/parser/languages/c.d.ts +28 -0
  43. package/build/parser/languages/c.js +70 -0
  44. package/build/parser/languages/cpp.d.ts +28 -0
  45. package/build/parser/languages/cpp.js +91 -0
  46. package/build/parser/languages/csharp.d.ts +32 -0
  47. package/build/parser/languages/csharp.js +97 -0
  48. package/build/parser/languages/go.d.ts +28 -0
  49. package/build/parser/languages/go.js +83 -0
  50. package/build/parser/languages/index.d.ts +21 -0
  51. package/build/parser/languages/index.js +107 -0
  52. package/build/parser/languages/java.d.ts +28 -0
  53. package/build/parser/languages/java.js +58 -0
  54. package/build/parser/languages/php.d.ts +28 -0
  55. package/build/parser/languages/php.js +75 -0
  56. package/build/parser/languages/python.d.ts +28 -0
  57. package/build/parser/languages/python.js +67 -0
  58. package/build/parser/languages/ruby.d.ts +28 -0
  59. package/build/parser/languages/ruby.js +68 -0
  60. package/build/parser/languages/rust.d.ts +28 -0
  61. package/build/parser/languages/rust.js +73 -0
  62. package/build/parser/languages/typescript.d.ts +28 -0
  63. package/build/parser/languages/typescript.js +82 -0
  64. package/build/parser/tree-sitter.d.ts +30 -0
  65. package/build/parser/tree-sitter.js +132 -0
  66. package/build/server/mcp-server.d.ts +7 -0
  67. package/build/server/mcp-server.js +36 -0
  68. package/build/server/tools.d.ts +18 -0
  69. package/build/server/tools.js +1245 -0
  70. package/build/viewer/git-status.d.ts +25 -0
  71. package/build/viewer/git-status.js +163 -0
  72. package/build/viewer/index.d.ts +5 -0
  73. package/build/viewer/index.js +5 -0
  74. package/build/viewer/server.d.ts +12 -0
  75. package/build/viewer/server.js +1122 -0
  76. package/package.json +66 -0
@@ -0,0 +1,324 @@
1
+ /**
2
+ * summary and tree commands
3
+ *
4
+ * - summary: Get project summary with auto-detected info
5
+ * - tree: Get indexed file tree with optional stats
6
+ */
7
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
8
+ import { join, basename } from 'path';
9
+ import { PRODUCT_NAME, INDEX_DIR, TOOL_PREFIX } from '../constants.js';
10
+ import { openDatabase, createQueries } from '../db/index.js';
11
+ // ============================================================
12
+ // Summary implementation
13
+ // ============================================================
14
+ export function summary(params) {
15
+ const { path: projectPath } = params;
16
+ // Validate project path
17
+ const indexDir = join(projectPath, INDEX_DIR);
18
+ const dbPath = join(indexDir, 'index.db');
19
+ if (!existsSync(dbPath)) {
20
+ return {
21
+ success: false,
22
+ name: '',
23
+ content: '',
24
+ autoGenerated: {
25
+ entryPoints: [],
26
+ mainTypes: [],
27
+ fileCount: 0,
28
+ languages: [],
29
+ },
30
+ error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
31
+ };
32
+ }
33
+ // Open database
34
+ const db = openDatabase(dbPath, true);
35
+ const queries = createQueries(db);
36
+ try {
37
+ const projectName = db.getMetadata('project_name') ?? basename(projectPath);
38
+ // Read summary.md if exists
39
+ const summaryPath = join(indexDir, 'summary.md');
40
+ let content = '';
41
+ if (existsSync(summaryPath)) {
42
+ content = readFileSync(summaryPath, 'utf-8');
43
+ }
44
+ // Auto-detect entry points
45
+ const entryPoints = detectEntryPoints(queries);
46
+ // Get main types (most referenced)
47
+ const mainTypes = getMainTypes(queries);
48
+ // Get file count
49
+ const stats = db.getStats();
50
+ // Detect languages from file extensions
51
+ const languages = detectLanguages(queries);
52
+ db.close();
53
+ return {
54
+ success: true,
55
+ name: projectName,
56
+ content,
57
+ autoGenerated: {
58
+ entryPoints,
59
+ mainTypes,
60
+ fileCount: stats.files,
61
+ languages,
62
+ },
63
+ };
64
+ }
65
+ catch (err) {
66
+ db.close();
67
+ return {
68
+ success: false,
69
+ name: '',
70
+ content: '',
71
+ autoGenerated: {
72
+ entryPoints: [],
73
+ mainTypes: [],
74
+ fileCount: 0,
75
+ languages: [],
76
+ },
77
+ error: err instanceof Error ? err.message : String(err),
78
+ };
79
+ }
80
+ }
81
+ /**
82
+ * Detect entry points based on common patterns
83
+ */
84
+ function detectEntryPoints(queries) {
85
+ const files = queries.getAllFiles();
86
+ const entryPatterns = [
87
+ /^(program|main|index|app|application)\.(cs|ts|js|py|rs)$/i,
88
+ /^src\/(program|main|index|app)\.(cs|ts|js|py|rs)$/i,
89
+ /^src\/(main|lib)\.(rs)$/i,
90
+ ];
91
+ const entryPoints = [];
92
+ for (const file of files) {
93
+ const fileName = file.path.replace(/\\/g, '/');
94
+ for (const pattern of entryPatterns) {
95
+ if (pattern.test(fileName) || pattern.test(basename(fileName))) {
96
+ entryPoints.push(file.path);
97
+ break;
98
+ }
99
+ }
100
+ }
101
+ return entryPoints;
102
+ }
103
+ /**
104
+ * Get main types (classes/interfaces with most methods)
105
+ */
106
+ function getMainTypes(queries) {
107
+ const files = queries.getAllFiles();
108
+ const typeMethodCounts = [];
109
+ for (const file of files) {
110
+ const types = queries.getTypesByFile(file.id);
111
+ const methods = queries.getMethodsByFile(file.id);
112
+ for (const type of types) {
113
+ // Count methods that likely belong to this type (same file, after type definition)
114
+ const methodCount = methods.filter(m => m.line_number > type.line_number).length;
115
+ typeMethodCounts.push({
116
+ name: type.name,
117
+ file: file.path,
118
+ methodCount,
119
+ });
120
+ }
121
+ }
122
+ // Sort by method count and return top 5
123
+ typeMethodCounts.sort((a, b) => b.methodCount - a.methodCount);
124
+ return typeMethodCounts.slice(0, 5).map(t => `${t.name} (${t.file})`);
125
+ }
126
+ /**
127
+ * Detect languages from indexed file extensions
128
+ */
129
+ function detectLanguages(queries) {
130
+ const files = queries.getAllFiles();
131
+ const extensionMap = {
132
+ '.cs': 'C#',
133
+ '.ts': 'TypeScript',
134
+ '.tsx': 'TypeScript',
135
+ '.js': 'JavaScript',
136
+ '.jsx': 'JavaScript',
137
+ '.mjs': 'JavaScript',
138
+ '.cjs': 'JavaScript',
139
+ '.rs': 'Rust',
140
+ '.py': 'Python',
141
+ '.pyw': 'Python',
142
+ };
143
+ const languages = new Set();
144
+ for (const file of files) {
145
+ const ext = file.path.substring(file.path.lastIndexOf('.')).toLowerCase();
146
+ if (extensionMap[ext]) {
147
+ languages.add(extensionMap[ext]);
148
+ }
149
+ }
150
+ return [...languages].sort();
151
+ }
152
+ // ============================================================
153
+ // Tree implementation
154
+ // ============================================================
155
+ export function tree(params) {
156
+ const { path: projectPath, subpath, depth, includeStats } = params;
157
+ // Validate project path
158
+ const indexDir = join(projectPath, INDEX_DIR);
159
+ const dbPath = join(indexDir, 'index.db');
160
+ if (!existsSync(dbPath)) {
161
+ return {
162
+ success: false,
163
+ root: '',
164
+ entries: [],
165
+ totalFiles: 0,
166
+ error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
167
+ };
168
+ }
169
+ // Open database
170
+ const db = openDatabase(dbPath, true);
171
+ const queries = createQueries(db);
172
+ try {
173
+ const files = queries.getAllFiles();
174
+ const normalizedSubpath = subpath?.replace(/\\/g, '/').replace(/^\/|\/$/g, '') ?? '';
175
+ // Filter files by subpath
176
+ let filteredFiles = files;
177
+ if (normalizedSubpath) {
178
+ filteredFiles = files.filter(f => {
179
+ const normalizedPath = f.path.replace(/\\/g, '/');
180
+ return normalizedPath.startsWith(normalizedSubpath + '/') ||
181
+ normalizedPath === normalizedSubpath;
182
+ });
183
+ }
184
+ // Build tree structure
185
+ const directories = new Set();
186
+ const entries = [];
187
+ for (const file of filteredFiles) {
188
+ const normalizedPath = file.path.replace(/\\/g, '/');
189
+ const relativePath = normalizedSubpath
190
+ ? normalizedPath.substring(normalizedSubpath.length + 1)
191
+ : normalizedPath;
192
+ // Check depth
193
+ const pathDepth = relativePath.split('/').length;
194
+ if (depth !== undefined && pathDepth > depth) {
195
+ // Just add parent directories up to depth
196
+ const parts = relativePath.split('/');
197
+ for (let i = 0; i < Math.min(depth, parts.length - 1); i++) {
198
+ const dirPath = parts.slice(0, i + 1).join('/');
199
+ directories.add(dirPath);
200
+ }
201
+ continue;
202
+ }
203
+ // Add parent directories
204
+ const parts = relativePath.split('/');
205
+ for (let i = 0; i < parts.length - 1; i++) {
206
+ const dirPath = parts.slice(0, i + 1).join('/');
207
+ directories.add(dirPath);
208
+ }
209
+ // Add file entry
210
+ const entry = {
211
+ path: relativePath,
212
+ type: 'file',
213
+ };
214
+ if (includeStats) {
215
+ const occurrences = queries.getOccurrencesByFile(file.id);
216
+ const methods = queries.getMethodsByFile(file.id);
217
+ const types = queries.getTypesByFile(file.id);
218
+ entry.itemCount = new Set(occurrences.map(o => o.item_id)).size;
219
+ entry.methodCount = methods.length;
220
+ entry.typeCount = types.length;
221
+ }
222
+ entries.push(entry);
223
+ }
224
+ // Add directory entries
225
+ for (const dir of directories) {
226
+ entries.push({
227
+ path: dir,
228
+ type: 'directory',
229
+ });
230
+ }
231
+ // Sort: directories first, then alphabetically
232
+ entries.sort((a, b) => {
233
+ if (a.type !== b.type) {
234
+ return a.type === 'directory' ? -1 : 1;
235
+ }
236
+ return a.path.localeCompare(b.path);
237
+ });
238
+ db.close();
239
+ return {
240
+ success: true,
241
+ root: normalizedSubpath || '.',
242
+ entries,
243
+ totalFiles: filteredFiles.length,
244
+ };
245
+ }
246
+ catch (err) {
247
+ db.close();
248
+ return {
249
+ success: false,
250
+ root: '',
251
+ entries: [],
252
+ totalFiles: 0,
253
+ error: err instanceof Error ? err.message : String(err),
254
+ };
255
+ }
256
+ }
257
+ export function describe(params) {
258
+ const { path: projectPath, section, content, replace = false } = params;
259
+ // Validate project path
260
+ const indexDir = join(projectPath, INDEX_DIR);
261
+ const dbPath = join(indexDir, 'index.db');
262
+ if (!existsSync(dbPath)) {
263
+ return {
264
+ success: false,
265
+ section,
266
+ error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
267
+ };
268
+ }
269
+ const summaryPath = join(indexDir, 'summary.md');
270
+ try {
271
+ // Read existing summary or create new
272
+ let summaryContent = '';
273
+ if (existsSync(summaryPath)) {
274
+ summaryContent = readFileSync(summaryPath, 'utf-8');
275
+ }
276
+ // Section headers
277
+ const sectionHeaders = {
278
+ purpose: '## Purpose',
279
+ architecture: '## Architecture',
280
+ concepts: '## Key Concepts',
281
+ patterns: '## Patterns',
282
+ notes: '## Notes',
283
+ };
284
+ const header = sectionHeaders[section];
285
+ const sectionRegex = new RegExp(`^${header}\\n([\\s\\S]*?)(?=^## |$)`, 'm');
286
+ if (replace) {
287
+ // Replace entire section
288
+ if (sectionRegex.test(summaryContent)) {
289
+ summaryContent = summaryContent.replace(sectionRegex, `${header}\n${content}\n\n`);
290
+ }
291
+ else {
292
+ // Add new section at end
293
+ summaryContent = summaryContent.trimEnd() + `\n\n${header}\n${content}\n`;
294
+ }
295
+ }
296
+ else {
297
+ // Append to section
298
+ const match = summaryContent.match(sectionRegex);
299
+ if (match) {
300
+ const existingContent = match[1].trimEnd();
301
+ const newContent = existingContent ? `${existingContent}\n${content}` : content;
302
+ summaryContent = summaryContent.replace(sectionRegex, `${header}\n${newContent}\n\n`);
303
+ }
304
+ else {
305
+ // Add new section at end
306
+ summaryContent = summaryContent.trimEnd() + `\n\n${header}\n${content}\n`;
307
+ }
308
+ }
309
+ // Write back
310
+ writeFileSync(summaryPath, summaryContent.trimStart());
311
+ return {
312
+ success: true,
313
+ section,
314
+ };
315
+ }
316
+ catch (err) {
317
+ return {
318
+ success: false,
319
+ section,
320
+ error: err instanceof Error ? err.message : String(err),
321
+ };
322
+ }
323
+ }
324
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * update command - Update index for a single file
3
+ *
4
+ * Supports:
5
+ * - Full re-index of a file (no line range specified)
6
+ * - Incremental update of a line range (from_line/to_line specified) - future
7
+ */
8
+ export interface UpdateParams {
9
+ path: string;
10
+ file: string;
11
+ fromLine?: number;
12
+ toLine?: number;
13
+ }
14
+ export interface UpdateResult {
15
+ success: boolean;
16
+ file: string;
17
+ itemsAdded: number;
18
+ itemsRemoved: number;
19
+ methodsUpdated: number;
20
+ typesUpdated: number;
21
+ durationMs: number;
22
+ error?: string;
23
+ }
24
+ export declare function update(params: UpdateParams): UpdateResult;
25
+ export interface RemoveParams {
26
+ path: string;
27
+ file: string;
28
+ }
29
+ export interface RemoveResult {
30
+ success: boolean;
31
+ file: string;
32
+ removed: boolean;
33
+ error?: string;
34
+ }
35
+ export declare function remove(params: RemoveParams): RemoveResult;
36
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1,273 @@
1
+ /**
2
+ * update command - Update index for a single file
3
+ *
4
+ * Supports:
5
+ * - Full re-index of a file (no line range specified)
6
+ * - Incremental update of a line range (from_line/to_line specified) - future
7
+ */
8
+ import { existsSync, readFileSync } from 'fs';
9
+ import { join } from 'path';
10
+ import { createHash } from 'crypto';
11
+ import { PRODUCT_NAME, INDEX_DIR, TOOL_PREFIX } from '../constants.js';
12
+ import { openDatabase, createQueries } from '../db/index.js';
13
+ import { extract } from '../parser/index.js';
14
+ // ============================================================
15
+ // Main update function
16
+ // ============================================================
17
+ export function update(params) {
18
+ const startTime = Date.now();
19
+ const { path: projectPath } = params;
20
+ // Normalize path to forward slashes (consistent with how paths are stored)
21
+ const relativePath = params.file.replace(/\\/g, '/');
22
+ // Validate project path
23
+ const indexDir = join(projectPath, INDEX_DIR);
24
+ const dbPath = join(indexDir, 'index.db');
25
+ if (!existsSync(dbPath)) {
26
+ return {
27
+ success: false,
28
+ file: relativePath,
29
+ itemsAdded: 0,
30
+ itemsRemoved: 0,
31
+ methodsUpdated: 0,
32
+ typesUpdated: 0,
33
+ durationMs: Date.now() - startTime,
34
+ error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
35
+ };
36
+ }
37
+ // Check if file exists
38
+ const absolutePath = join(projectPath, relativePath);
39
+ if (!existsSync(absolutePath)) {
40
+ return {
41
+ success: false,
42
+ file: relativePath,
43
+ itemsAdded: 0,
44
+ itemsRemoved: 0,
45
+ methodsUpdated: 0,
46
+ typesUpdated: 0,
47
+ durationMs: Date.now() - startTime,
48
+ error: `File does not exist: ${relativePath}`,
49
+ };
50
+ }
51
+ // Open database
52
+ const db = openDatabase(dbPath);
53
+ const queries = createQueries(db);
54
+ try {
55
+ // Check if file is already indexed
56
+ const existingFile = queries.getFileByPath(relativePath);
57
+ // Read file content
58
+ let content;
59
+ try {
60
+ content = readFileSync(absolutePath, 'utf-8');
61
+ }
62
+ catch (err) {
63
+ return {
64
+ success: false,
65
+ file: relativePath,
66
+ itemsAdded: 0,
67
+ itemsRemoved: 0,
68
+ methodsUpdated: 0,
69
+ typesUpdated: 0,
70
+ durationMs: Date.now() - startTime,
71
+ error: `Cannot read file: ${err instanceof Error ? err.message : String(err)}`,
72
+ };
73
+ }
74
+ // Calculate new hash
75
+ const newHash = createHash('sha256').update(content).digest('hex').substring(0, 16);
76
+ // Check if file has actually changed
77
+ if (existingFile && existingFile.hash === newHash) {
78
+ return {
79
+ success: true,
80
+ file: relativePath,
81
+ itemsAdded: 0,
82
+ itemsRemoved: 0,
83
+ methodsUpdated: 0,
84
+ typesUpdated: 0,
85
+ durationMs: Date.now() - startTime,
86
+ error: 'File unchanged (hash match)',
87
+ };
88
+ }
89
+ // Extract data from file
90
+ const extraction = extract(content, relativePath);
91
+ if (!extraction) {
92
+ return {
93
+ success: false,
94
+ file: relativePath,
95
+ itemsAdded: 0,
96
+ itemsRemoved: 0,
97
+ methodsUpdated: 0,
98
+ typesUpdated: 0,
99
+ durationMs: Date.now() - startTime,
100
+ error: 'Unsupported file type or parse error',
101
+ };
102
+ }
103
+ // Count old items for comparison
104
+ let oldItemCount = 0;
105
+ let oldMethodCount = 0;
106
+ let oldTypeCount = 0;
107
+ if (existingFile) {
108
+ const oldOccurrences = queries.getOccurrencesByFile(existingFile.id);
109
+ oldItemCount = new Set(oldOccurrences.map(o => o.item_id)).size;
110
+ oldMethodCount = queries.getMethodsByFile(existingFile.id).length;
111
+ oldTypeCount = queries.getTypesByFile(existingFile.id).length;
112
+ }
113
+ // Split content into lines for hashing
114
+ const contentLines = content.split('\n');
115
+ const now = Date.now();
116
+ // Build map of old line hashes to modified timestamps (for diff tracking)
117
+ // Key is the hash, not line_number - so moved lines keep their timestamp
118
+ const oldHashToModified = new Map();
119
+ if (existingFile) {
120
+ const oldLines = queries.getLinesByFile(existingFile.id);
121
+ for (const line of oldLines) {
122
+ if (line.line_hash && line.modified) {
123
+ // If same hash appears multiple times, keep the oldest timestamp
124
+ const existing = oldHashToModified.get(line.line_hash);
125
+ if (!existing || line.modified < existing) {
126
+ oldHashToModified.set(line.line_hash, line.modified);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ // Perform update in transaction
132
+ let fileId;
133
+ let newItemCount = 0;
134
+ db.transaction(() => {
135
+ if (existingFile) {
136
+ // Clear existing data for this file
137
+ queries.clearFileData(existingFile.id);
138
+ // Update hash
139
+ queries.updateFileHash(existingFile.id, newHash);
140
+ fileId = existingFile.id;
141
+ }
142
+ else {
143
+ // Insert new file record
144
+ fileId = queries.insertFile(relativePath, newHash);
145
+ }
146
+ // Insert lines with diff tracking
147
+ let lineId = 1;
148
+ for (const line of extraction.lines) {
149
+ const lineContent = contentLines[line.lineNumber - 1] ?? '';
150
+ const lineHash = createHash('sha256').update(lineContent).digest('hex').substring(0, 16);
151
+ // Check if this hash existed before (regardless of line number)
152
+ const oldModified = oldHashToModified.get(lineHash);
153
+ const modified = oldModified ?? now; // Keep old timestamp if hash existed
154
+ queries.insertLine(fileId, lineId++, line.lineNumber, line.lineType, lineHash, modified);
155
+ }
156
+ // Build line number to line ID mapping
157
+ const lineNumberToId = new Map();
158
+ lineId = 1;
159
+ for (const line of extraction.lines) {
160
+ lineNumberToId.set(line.lineNumber, lineId++);
161
+ }
162
+ // Insert items and occurrences
163
+ const itemsInserted = new Set();
164
+ for (const item of extraction.items) {
165
+ let itemLineId = lineNumberToId.get(item.lineNumber);
166
+ if (itemLineId === undefined) {
167
+ // Line wasn't recorded, add it now
168
+ const newLineId = lineId++;
169
+ const lineContent = contentLines[item.lineNumber - 1] ?? '';
170
+ const lineHash = createHash('sha256').update(lineContent).digest('hex').substring(0, 16);
171
+ const oldModified = oldHashToModified.get(lineHash);
172
+ const modified = oldModified ?? now;
173
+ queries.insertLine(fileId, newLineId, item.lineNumber, item.lineType, lineHash, modified);
174
+ lineNumberToId.set(item.lineNumber, newLineId);
175
+ itemLineId = newLineId;
176
+ }
177
+ const itemId = queries.getOrCreateItem(item.term);
178
+ queries.insertOccurrence(itemId, fileId, itemLineId);
179
+ itemsInserted.add(item.term);
180
+ }
181
+ newItemCount = itemsInserted.size;
182
+ // Insert methods
183
+ for (const method of extraction.methods) {
184
+ queries.insertMethod(fileId, method.name, method.prototype, method.lineNumber, method.visibility, method.isStatic, method.isAsync);
185
+ }
186
+ // Insert types
187
+ for (const type of extraction.types) {
188
+ queries.insertType(fileId, type.name, type.kind, type.lineNumber);
189
+ }
190
+ // Insert signature (header comments)
191
+ if (extraction.headerComments.length > 0) {
192
+ queries.insertSignature(fileId, extraction.headerComments.join('\n'));
193
+ }
194
+ });
195
+ // Cleanup unused items
196
+ queries.deleteUnusedItems();
197
+ db.close();
198
+ return {
199
+ success: true,
200
+ file: relativePath,
201
+ itemsAdded: Math.max(0, newItemCount - oldItemCount),
202
+ itemsRemoved: Math.max(0, oldItemCount - newItemCount),
203
+ methodsUpdated: extraction.methods.length,
204
+ typesUpdated: extraction.types.length,
205
+ durationMs: Date.now() - startTime,
206
+ };
207
+ }
208
+ catch (err) {
209
+ db.close();
210
+ return {
211
+ success: false,
212
+ file: relativePath,
213
+ itemsAdded: 0,
214
+ itemsRemoved: 0,
215
+ methodsUpdated: 0,
216
+ typesUpdated: 0,
217
+ durationMs: Date.now() - startTime,
218
+ error: err instanceof Error ? err.message : String(err),
219
+ };
220
+ }
221
+ }
222
+ export function remove(params) {
223
+ const { path: projectPath } = params;
224
+ // Normalize path to forward slashes
225
+ const relativePath = params.file.replace(/\\/g, '/');
226
+ // Validate project path
227
+ const indexDir = join(projectPath, INDEX_DIR);
228
+ const dbPath = join(indexDir, 'index.db');
229
+ if (!existsSync(dbPath)) {
230
+ return {
231
+ success: false,
232
+ file: relativePath,
233
+ removed: false,
234
+ error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
235
+ };
236
+ }
237
+ // Open database
238
+ const db = openDatabase(dbPath);
239
+ const queries = createQueries(db);
240
+ try {
241
+ const existingFile = queries.getFileByPath(relativePath);
242
+ if (!existingFile) {
243
+ db.close();
244
+ return {
245
+ success: true,
246
+ file: relativePath,
247
+ removed: false,
248
+ error: 'File not found in index',
249
+ };
250
+ }
251
+ // Delete file (CASCADE will handle related data)
252
+ db.transaction(() => {
253
+ queries.deleteFile(existingFile.id);
254
+ queries.deleteUnusedItems();
255
+ });
256
+ db.close();
257
+ return {
258
+ success: true,
259
+ file: relativePath,
260
+ removed: true,
261
+ };
262
+ }
263
+ catch (err) {
264
+ db.close();
265
+ return {
266
+ success: false,
267
+ file: relativePath,
268
+ removed: false,
269
+ error: err instanceof Error ? err.message : String(err),
270
+ };
271
+ }
272
+ }
273
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * AiDex - Global constants
3
+ *
4
+ * Change product name here to rename the entire tool.
5
+ */
6
+ export declare const PRODUCT_NAME = "AiDex";
7
+ export declare const PRODUCT_NAME_LOWER = "aidex";
8
+ export declare const INDEX_DIR = ".aidex";
9
+ export declare const TOOL_PREFIX = "aidex_";
10
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * AiDex - Global constants
3
+ *
4
+ * Change product name here to rename the entire tool.
5
+ */
6
+ export const PRODUCT_NAME = 'AiDex';
7
+ export const PRODUCT_NAME_LOWER = 'aidex';
8
+ export const INDEX_DIR = '.aidex';
9
+ export const TOOL_PREFIX = 'aidex_';
10
+ //# sourceMappingURL=constants.js.map