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.
- package/CHANGELOG.md +128 -0
- package/LICENSE +21 -0
- package/MCP-API-REFERENCE.md +690 -0
- package/README.md +314 -0
- package/build/commands/files.d.ts +28 -0
- package/build/commands/files.js +124 -0
- package/build/commands/index.d.ts +14 -0
- package/build/commands/index.js +14 -0
- package/build/commands/init.d.ts +24 -0
- package/build/commands/init.js +396 -0
- package/build/commands/link.d.ts +45 -0
- package/build/commands/link.js +167 -0
- package/build/commands/note.d.ts +29 -0
- package/build/commands/note.js +105 -0
- package/build/commands/query.d.ts +36 -0
- package/build/commands/query.js +176 -0
- package/build/commands/scan.d.ts +25 -0
- package/build/commands/scan.js +104 -0
- package/build/commands/session.d.ts +52 -0
- package/build/commands/session.js +216 -0
- package/build/commands/signature.d.ts +52 -0
- package/build/commands/signature.js +171 -0
- package/build/commands/summary.d.ts +56 -0
- package/build/commands/summary.js +324 -0
- package/build/commands/update.d.ts +36 -0
- package/build/commands/update.js +273 -0
- package/build/constants.d.ts +10 -0
- package/build/constants.js +10 -0
- package/build/db/database.d.ts +69 -0
- package/build/db/database.js +126 -0
- package/build/db/index.d.ts +7 -0
- package/build/db/index.js +6 -0
- package/build/db/queries.d.ts +163 -0
- package/build/db/queries.js +273 -0
- package/build/db/schema.sql +136 -0
- package/build/index.d.ts +13 -0
- package/build/index.js +74 -0
- package/build/parser/extractor.d.ts +41 -0
- package/build/parser/extractor.js +249 -0
- package/build/parser/index.d.ts +7 -0
- package/build/parser/index.js +7 -0
- package/build/parser/languages/c.d.ts +28 -0
- package/build/parser/languages/c.js +70 -0
- package/build/parser/languages/cpp.d.ts +28 -0
- package/build/parser/languages/cpp.js +91 -0
- package/build/parser/languages/csharp.d.ts +32 -0
- package/build/parser/languages/csharp.js +97 -0
- package/build/parser/languages/go.d.ts +28 -0
- package/build/parser/languages/go.js +83 -0
- package/build/parser/languages/index.d.ts +21 -0
- package/build/parser/languages/index.js +107 -0
- package/build/parser/languages/java.d.ts +28 -0
- package/build/parser/languages/java.js +58 -0
- package/build/parser/languages/php.d.ts +28 -0
- package/build/parser/languages/php.js +75 -0
- package/build/parser/languages/python.d.ts +28 -0
- package/build/parser/languages/python.js +67 -0
- package/build/parser/languages/ruby.d.ts +28 -0
- package/build/parser/languages/ruby.js +68 -0
- package/build/parser/languages/rust.d.ts +28 -0
- package/build/parser/languages/rust.js +73 -0
- package/build/parser/languages/typescript.d.ts +28 -0
- package/build/parser/languages/typescript.js +82 -0
- package/build/parser/tree-sitter.d.ts +30 -0
- package/build/parser/tree-sitter.js +132 -0
- package/build/server/mcp-server.d.ts +7 -0
- package/build/server/mcp-server.js +36 -0
- package/build/server/tools.d.ts +18 -0
- package/build/server/tools.js +1245 -0
- package/build/viewer/git-status.d.ts +25 -0
- package/build/viewer/git-status.js +163 -0
- package/build/viewer/index.d.ts +5 -0
- package/build/viewer/index.js +5 -0
- package/build/viewer/server.d.ts +12 -0
- package/build/viewer/server.js +1122 -0
- package/package.json +66 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* init command - Initialize AiDex for a project
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, statSync } from 'fs';
|
|
5
|
+
import { join, basename, extname } from 'path';
|
|
6
|
+
import { glob } from 'glob';
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
import { minimatch } from 'minimatch';
|
|
9
|
+
import { INDEX_DIR } from '../constants.js';
|
|
10
|
+
import { createDatabase, createQueries } from '../db/index.js';
|
|
11
|
+
import { extract, getSupportedExtensions } from '../parser/index.js';
|
|
12
|
+
// ============================================================
|
|
13
|
+
// Default patterns
|
|
14
|
+
// ============================================================
|
|
15
|
+
const DEFAULT_EXCLUDE = [
|
|
16
|
+
// Package managers
|
|
17
|
+
'**/node_modules/**',
|
|
18
|
+
'**/packages/**',
|
|
19
|
+
'**/vendor/**', // PHP Composer, Go
|
|
20
|
+
'**/vendor/bundle/**', // Ruby Bundler
|
|
21
|
+
// Build output
|
|
22
|
+
'**/bin/**',
|
|
23
|
+
'**/obj/**',
|
|
24
|
+
'**/bld/**', // Alternative build folder
|
|
25
|
+
'**/build/**',
|
|
26
|
+
'**/dist/**',
|
|
27
|
+
'**/out/**', // VS Code, some TS configs
|
|
28
|
+
'**/target/**', // Rust, Maven
|
|
29
|
+
'**/Debug/**', // Visual Studio
|
|
30
|
+
'**/Release/**', // Visual Studio
|
|
31
|
+
'**/x64/**', // Visual Studio
|
|
32
|
+
'**/x86/**', // Visual Studio
|
|
33
|
+
'**/[Aa][Rr][Mm]/**', // Visual Studio ARM
|
|
34
|
+
'**/[Aa][Rr][Mm]64/**', // Visual Studio ARM64
|
|
35
|
+
'**/__pycache__/**', // Python
|
|
36
|
+
'**/.pyc', // Python bytecode
|
|
37
|
+
'**/venv/**', // Python virtual env
|
|
38
|
+
'**/.venv/**', // Python virtual env
|
|
39
|
+
'**/env/**', // Python virtual env
|
|
40
|
+
'**/*.egg-info/**', // Python package metadata
|
|
41
|
+
// IDE/Editor
|
|
42
|
+
'**/.git/**',
|
|
43
|
+
'**/.vs/**',
|
|
44
|
+
'**/.idea/**',
|
|
45
|
+
'**/.vscode/**',
|
|
46
|
+
// Framework-specific
|
|
47
|
+
'**/.next/**', // Next.js
|
|
48
|
+
'**/coverage/**', // Test coverage
|
|
49
|
+
'**/tmp/**', // Ruby, temp files
|
|
50
|
+
// Generated files
|
|
51
|
+
'**/*.min.js',
|
|
52
|
+
'**/*.generated.*',
|
|
53
|
+
'**/*.g.cs', // C# source generators
|
|
54
|
+
'**/*.Designer.cs', // WinForms designer
|
|
55
|
+
];
|
|
56
|
+
// ============================================================
|
|
57
|
+
// .gitignore support
|
|
58
|
+
// ============================================================
|
|
59
|
+
function readGitignore(projectPath) {
|
|
60
|
+
const gitignorePath = join(projectPath, '.gitignore');
|
|
61
|
+
if (!existsSync(gitignorePath))
|
|
62
|
+
return [];
|
|
63
|
+
const content = readFileSync(gitignorePath, 'utf-8');
|
|
64
|
+
return content
|
|
65
|
+
.split('\n')
|
|
66
|
+
.map(line => line.trim())
|
|
67
|
+
.filter(line => line && !line.startsWith('#')) // Keine Kommentare/Leerzeilen
|
|
68
|
+
.map(pattern => {
|
|
69
|
+
// Glob-kompatibel machen
|
|
70
|
+
if (pattern.endsWith('/')) {
|
|
71
|
+
return `**/${pattern}**`; // Verzeichnis: foo/ → **/foo/**
|
|
72
|
+
}
|
|
73
|
+
if (!pattern.includes('/') && !pattern.startsWith('*')) {
|
|
74
|
+
return `**/${pattern}`; // Datei/Ordner: foo → **/foo
|
|
75
|
+
}
|
|
76
|
+
return pattern;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// ============================================================
|
|
80
|
+
// File type detection
|
|
81
|
+
// ============================================================
|
|
82
|
+
const CODE_EXTENSIONS = new Set([
|
|
83
|
+
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
|
|
84
|
+
'.cs', '.rs', '.py', '.pyw',
|
|
85
|
+
'.c', '.h', '.cpp', '.cc', '.cxx', '.hpp', '.hxx',
|
|
86
|
+
'.java', '.go', '.php', '.rb', '.rake'
|
|
87
|
+
]);
|
|
88
|
+
const CONFIG_EXTENSIONS = new Set([
|
|
89
|
+
'.json', '.yaml', '.yml', '.toml', '.xml', '.ini', '.env', '.config',
|
|
90
|
+
'.eslintrc', '.prettierrc', '.babelrc', '.editorconfig'
|
|
91
|
+
]);
|
|
92
|
+
const DOC_EXTENSIONS = new Set([
|
|
93
|
+
'.md', '.txt', '.rst', '.adoc', '.doc', '.docx', '.pdf'
|
|
94
|
+
]);
|
|
95
|
+
const ASSET_EXTENSIONS = new Set([
|
|
96
|
+
'.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.webp',
|
|
97
|
+
'.woff', '.woff2', '.ttf', '.eot', '.otf',
|
|
98
|
+
'.mp3', '.mp4', '.wav', '.ogg', '.webm',
|
|
99
|
+
'.zip', '.tar', '.gz', '.rar'
|
|
100
|
+
]);
|
|
101
|
+
function detectFileType(filePath) {
|
|
102
|
+
const ext = extname(filePath).toLowerCase();
|
|
103
|
+
const lowerPath = filePath.toLowerCase();
|
|
104
|
+
// Check for test files first (before code check)
|
|
105
|
+
if (lowerPath.includes('.test.') || lowerPath.includes('.spec.') ||
|
|
106
|
+
lowerPath.includes('_test.') || lowerPath.includes('_spec.') ||
|
|
107
|
+
lowerPath.includes('/test/') || lowerPath.includes('/tests/') ||
|
|
108
|
+
lowerPath.includes('/__tests__/')) {
|
|
109
|
+
return 'test';
|
|
110
|
+
}
|
|
111
|
+
if (CODE_EXTENSIONS.has(ext))
|
|
112
|
+
return 'code';
|
|
113
|
+
if (CONFIG_EXTENSIONS.has(ext))
|
|
114
|
+
return 'config';
|
|
115
|
+
if (DOC_EXTENSIONS.has(ext))
|
|
116
|
+
return 'doc';
|
|
117
|
+
if (ASSET_EXTENSIONS.has(ext))
|
|
118
|
+
return 'asset';
|
|
119
|
+
return 'other';
|
|
120
|
+
}
|
|
121
|
+
// ============================================================
|
|
122
|
+
// Main init function
|
|
123
|
+
// ============================================================
|
|
124
|
+
export async function init(params) {
|
|
125
|
+
const startTime = Date.now();
|
|
126
|
+
const errors = [];
|
|
127
|
+
// Validate project path
|
|
128
|
+
if (!existsSync(params.path)) {
|
|
129
|
+
return {
|
|
130
|
+
success: false,
|
|
131
|
+
indexPath: '',
|
|
132
|
+
filesIndexed: 0,
|
|
133
|
+
filesSkipped: 0,
|
|
134
|
+
filesRemoved: 0,
|
|
135
|
+
itemsFound: 0,
|
|
136
|
+
methodsFound: 0,
|
|
137
|
+
typesFound: 0,
|
|
138
|
+
durationMs: Date.now() - startTime,
|
|
139
|
+
errors: [`Project path does not exist: ${params.path}`],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const stat = statSync(params.path);
|
|
143
|
+
if (!stat.isDirectory()) {
|
|
144
|
+
return {
|
|
145
|
+
success: false,
|
|
146
|
+
indexPath: '',
|
|
147
|
+
filesIndexed: 0,
|
|
148
|
+
filesSkipped: 0,
|
|
149
|
+
filesRemoved: 0,
|
|
150
|
+
itemsFound: 0,
|
|
151
|
+
methodsFound: 0,
|
|
152
|
+
typesFound: 0,
|
|
153
|
+
durationMs: Date.now() - startTime,
|
|
154
|
+
errors: [`Path is not a directory: ${params.path}`],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// Create index directory
|
|
158
|
+
const indexDir = join(params.path, INDEX_DIR);
|
|
159
|
+
if (!existsSync(indexDir)) {
|
|
160
|
+
mkdirSync(indexDir, { recursive: true });
|
|
161
|
+
}
|
|
162
|
+
const dbPath = join(indexDir, 'index.db');
|
|
163
|
+
const projectName = params.name ?? basename(params.path);
|
|
164
|
+
// Determine if incremental (default) or fresh re-index
|
|
165
|
+
const dbExists = existsSync(dbPath);
|
|
166
|
+
const incremental = dbExists && !params.fresh;
|
|
167
|
+
// Create database (incremental keeps existing data)
|
|
168
|
+
const db = createDatabase(dbPath, projectName, params.path, incremental);
|
|
169
|
+
const queries = createQueries(db);
|
|
170
|
+
// Build glob pattern for supported files
|
|
171
|
+
const extensions = getSupportedExtensions();
|
|
172
|
+
const patterns = extensions.map(ext => `**/*${ext}`);
|
|
173
|
+
// Merge exclude patterns (including .gitignore)
|
|
174
|
+
const gitignorePatterns = readGitignore(params.path);
|
|
175
|
+
const exclude = [...DEFAULT_EXCLUDE, ...gitignorePatterns, ...(params.exclude ?? [])];
|
|
176
|
+
// Find all source files
|
|
177
|
+
let files = [];
|
|
178
|
+
for (const pattern of patterns) {
|
|
179
|
+
const found = await glob(pattern, {
|
|
180
|
+
cwd: params.path,
|
|
181
|
+
ignore: exclude,
|
|
182
|
+
nodir: true,
|
|
183
|
+
absolute: false,
|
|
184
|
+
});
|
|
185
|
+
files.push(...found);
|
|
186
|
+
}
|
|
187
|
+
// Remove duplicates, normalize to forward slashes, and sort
|
|
188
|
+
files = [...new Set(files)].map(f => f.replace(/\\/g, '/')).sort();
|
|
189
|
+
// Index each file
|
|
190
|
+
let filesIndexed = 0;
|
|
191
|
+
let filesSkipped = 0;
|
|
192
|
+
let totalItems = 0;
|
|
193
|
+
let totalMethods = 0;
|
|
194
|
+
let totalTypes = 0;
|
|
195
|
+
// Use transaction for bulk insert
|
|
196
|
+
db.transaction(() => {
|
|
197
|
+
for (const filePath of files) {
|
|
198
|
+
try {
|
|
199
|
+
const result = indexFile(params.path, filePath, db, queries, incremental);
|
|
200
|
+
if (result.skipped) {
|
|
201
|
+
filesSkipped++;
|
|
202
|
+
}
|
|
203
|
+
else if (result.success) {
|
|
204
|
+
filesIndexed++;
|
|
205
|
+
totalItems += result.items;
|
|
206
|
+
totalMethods += result.methods;
|
|
207
|
+
totalTypes += result.types;
|
|
208
|
+
}
|
|
209
|
+
else if (result.error) {
|
|
210
|
+
errors.push(`${filePath}: ${result.error}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
// Cleanup unused items
|
|
219
|
+
queries.deleteUnusedItems();
|
|
220
|
+
// --------------------------------------------------------
|
|
221
|
+
// Cleanup: Remove files that are now excluded
|
|
222
|
+
// (e.g., build/ was indexed before exclude pattern was added)
|
|
223
|
+
// --------------------------------------------------------
|
|
224
|
+
let filesRemoved = 0;
|
|
225
|
+
const existingFiles = queries.getAllFiles();
|
|
226
|
+
db.transaction(() => {
|
|
227
|
+
for (const file of existingFiles) {
|
|
228
|
+
// Check if this file path matches any exclude pattern
|
|
229
|
+
const shouldExclude = exclude.some(pattern => minimatch(file.path, pattern, { dot: true }));
|
|
230
|
+
if (shouldExclude) {
|
|
231
|
+
// Remove from index
|
|
232
|
+
queries.clearFileData(file.id);
|
|
233
|
+
queries.deleteFile(file.id);
|
|
234
|
+
filesRemoved++;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
if (filesRemoved > 0) {
|
|
239
|
+
// Cleanup items that are now orphaned
|
|
240
|
+
queries.deleteUnusedItems();
|
|
241
|
+
}
|
|
242
|
+
// --------------------------------------------------------
|
|
243
|
+
// Scan project structure (all files, not just code)
|
|
244
|
+
// --------------------------------------------------------
|
|
245
|
+
const indexedFilesSet = new Set(files); // Code files we indexed
|
|
246
|
+
// Find ALL files in project
|
|
247
|
+
const allFiles = await glob('**/*', {
|
|
248
|
+
cwd: params.path,
|
|
249
|
+
ignore: exclude,
|
|
250
|
+
nodir: true,
|
|
251
|
+
absolute: false,
|
|
252
|
+
});
|
|
253
|
+
// Normalize paths and collect directories
|
|
254
|
+
const directories = new Set();
|
|
255
|
+
const normalizedAllFiles = allFiles.map(f => f.replace(/\\/g, '/'));
|
|
256
|
+
for (const filePath of normalizedAllFiles) {
|
|
257
|
+
// Extract all parent directories
|
|
258
|
+
const parts = filePath.split('/');
|
|
259
|
+
for (let i = 1; i < parts.length; i++) {
|
|
260
|
+
directories.add(parts.slice(0, i).join('/'));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Insert directories
|
|
264
|
+
db.transaction(() => {
|
|
265
|
+
for (const dir of directories) {
|
|
266
|
+
queries.insertProjectFile(dir, 'dir', null, false);
|
|
267
|
+
}
|
|
268
|
+
// Insert all files with type detection
|
|
269
|
+
for (const filePath of normalizedAllFiles) {
|
|
270
|
+
const ext = extname(filePath).toLowerCase() || null;
|
|
271
|
+
const fileType = detectFileType(filePath);
|
|
272
|
+
const isIndexed = indexedFilesSet.has(filePath);
|
|
273
|
+
queries.insertProjectFile(filePath, fileType, ext, isIndexed);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
// Reset session tracking after full re-index
|
|
277
|
+
const now = Date.now().toString();
|
|
278
|
+
db.setMetadata('last_session_start', now);
|
|
279
|
+
db.setMetadata('last_session_end', now);
|
|
280
|
+
db.setMetadata('current_session_start', now);
|
|
281
|
+
db.close();
|
|
282
|
+
return {
|
|
283
|
+
success: true,
|
|
284
|
+
indexPath: indexDir,
|
|
285
|
+
filesIndexed,
|
|
286
|
+
filesSkipped,
|
|
287
|
+
filesRemoved,
|
|
288
|
+
itemsFound: totalItems,
|
|
289
|
+
methodsFound: totalMethods,
|
|
290
|
+
typesFound: totalTypes,
|
|
291
|
+
durationMs: Date.now() - startTime,
|
|
292
|
+
errors,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function indexFile(projectPath, relativePath, db, queries, incremental = false) {
|
|
296
|
+
const absolutePath = join(projectPath, relativePath);
|
|
297
|
+
// Read file content
|
|
298
|
+
let content;
|
|
299
|
+
try {
|
|
300
|
+
content = readFileSync(absolutePath, 'utf-8');
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
return {
|
|
304
|
+
success: false,
|
|
305
|
+
items: 0,
|
|
306
|
+
methods: 0,
|
|
307
|
+
types: 0,
|
|
308
|
+
error: `Cannot read file: ${err instanceof Error ? err.message : String(err)}`,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
// Calculate hash
|
|
312
|
+
const hash = createHash('sha256').update(content).digest('hex').substring(0, 16);
|
|
313
|
+
// In incremental mode, skip unchanged files
|
|
314
|
+
if (incremental) {
|
|
315
|
+
const existingFile = queries.getFileByPath(relativePath);
|
|
316
|
+
if (existingFile && existingFile.hash === hash) {
|
|
317
|
+
return {
|
|
318
|
+
success: true,
|
|
319
|
+
skipped: true,
|
|
320
|
+
items: 0,
|
|
321
|
+
methods: 0,
|
|
322
|
+
types: 0,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
// File changed - clear old data before re-indexing
|
|
326
|
+
if (existingFile) {
|
|
327
|
+
queries.clearFileData(existingFile.id);
|
|
328
|
+
queries.deleteFile(existingFile.id);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// Extract data from file
|
|
332
|
+
const extraction = extract(content, relativePath);
|
|
333
|
+
if (!extraction) {
|
|
334
|
+
return {
|
|
335
|
+
success: false,
|
|
336
|
+
items: 0,
|
|
337
|
+
methods: 0,
|
|
338
|
+
types: 0,
|
|
339
|
+
error: 'Unsupported file type or parse error',
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
// Insert file record
|
|
343
|
+
const fileId = queries.insertFile(relativePath, hash);
|
|
344
|
+
// Split content into lines for hashing
|
|
345
|
+
const contentLines = content.split('\n');
|
|
346
|
+
const now = Date.now();
|
|
347
|
+
// Insert lines with hash
|
|
348
|
+
let lineId = 1;
|
|
349
|
+
for (const line of extraction.lines) {
|
|
350
|
+
const lineContent = contentLines[line.lineNumber - 1] ?? '';
|
|
351
|
+
const lineHash = createHash('sha256').update(lineContent).digest('hex').substring(0, 16);
|
|
352
|
+
queries.insertLine(fileId, lineId++, line.lineNumber, line.lineType, lineHash, now);
|
|
353
|
+
}
|
|
354
|
+
// Build line number to line ID mapping
|
|
355
|
+
const lineNumberToId = new Map();
|
|
356
|
+
lineId = 1;
|
|
357
|
+
for (const line of extraction.lines) {
|
|
358
|
+
lineNumberToId.set(line.lineNumber, lineId++);
|
|
359
|
+
}
|
|
360
|
+
// Insert items and occurrences
|
|
361
|
+
const itemsInserted = new Set();
|
|
362
|
+
for (const item of extraction.items) {
|
|
363
|
+
const lineIdForItem = lineNumberToId.get(item.lineNumber);
|
|
364
|
+
if (lineIdForItem === undefined) {
|
|
365
|
+
// Line wasn't recorded, add it now
|
|
366
|
+
const newLineId = lineId++;
|
|
367
|
+
const lineContent = contentLines[item.lineNumber - 1] ?? '';
|
|
368
|
+
const lineHash = createHash('sha256').update(lineContent).digest('hex').substring(0, 16);
|
|
369
|
+
queries.insertLine(fileId, newLineId, item.lineNumber, item.lineType, lineHash, now);
|
|
370
|
+
lineNumberToId.set(item.lineNumber, newLineId);
|
|
371
|
+
}
|
|
372
|
+
const itemId = queries.getOrCreateItem(item.term);
|
|
373
|
+
const finalLineId = lineNumberToId.get(item.lineNumber);
|
|
374
|
+
queries.insertOccurrence(itemId, fileId, finalLineId);
|
|
375
|
+
itemsInserted.add(item.term);
|
|
376
|
+
}
|
|
377
|
+
// Insert methods
|
|
378
|
+
for (const method of extraction.methods) {
|
|
379
|
+
queries.insertMethod(fileId, method.name, method.prototype, method.lineNumber, method.visibility, method.isStatic, method.isAsync);
|
|
380
|
+
}
|
|
381
|
+
// Insert types
|
|
382
|
+
for (const type of extraction.types) {
|
|
383
|
+
queries.insertType(fileId, type.name, type.kind, type.lineNumber);
|
|
384
|
+
}
|
|
385
|
+
// Insert signature (header comments)
|
|
386
|
+
if (extraction.headerComments.length > 0) {
|
|
387
|
+
queries.insertSignature(fileId, extraction.headerComments.join('\n'));
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
success: true,
|
|
391
|
+
items: itemsInserted.size,
|
|
392
|
+
methods: extraction.methods.length,
|
|
393
|
+
types: extraction.types.length,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* link command - Link dependency projects
|
|
3
|
+
*
|
|
4
|
+
* Allows cross-project queries by linking other AiDex instances.
|
|
5
|
+
*/
|
|
6
|
+
export interface LinkParams {
|
|
7
|
+
path: string;
|
|
8
|
+
dependency: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface LinkResult {
|
|
12
|
+
success: boolean;
|
|
13
|
+
dependencyId?: number;
|
|
14
|
+
name: string;
|
|
15
|
+
filesAvailable: number;
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface UnlinkParams {
|
|
19
|
+
path: string;
|
|
20
|
+
dependency: string;
|
|
21
|
+
}
|
|
22
|
+
export interface UnlinkResult {
|
|
23
|
+
success: boolean;
|
|
24
|
+
removed: boolean;
|
|
25
|
+
error?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ListLinksParams {
|
|
28
|
+
path: string;
|
|
29
|
+
}
|
|
30
|
+
export interface LinkedProject {
|
|
31
|
+
id: number;
|
|
32
|
+
path: string;
|
|
33
|
+
name: string | null;
|
|
34
|
+
filesAvailable: number;
|
|
35
|
+
available: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface ListLinksResult {
|
|
38
|
+
success: boolean;
|
|
39
|
+
dependencies: LinkedProject[];
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function link(params: LinkParams): LinkResult;
|
|
43
|
+
export declare function unlink(params: UnlinkParams): UnlinkResult;
|
|
44
|
+
export declare function listLinks(params: ListLinksParams): ListLinksResult;
|
|
45
|
+
//# sourceMappingURL=link.d.ts.map
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* link command - Link dependency projects
|
|
3
|
+
*
|
|
4
|
+
* Allows cross-project queries by linking other AiDex instances.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { join, basename } from 'path';
|
|
8
|
+
import { PRODUCT_NAME, INDEX_DIR, TOOL_PREFIX } from '../constants.js';
|
|
9
|
+
import { openDatabase } from '../db/index.js';
|
|
10
|
+
// ============================================================
|
|
11
|
+
// Link implementation
|
|
12
|
+
// ============================================================
|
|
13
|
+
export function link(params) {
|
|
14
|
+
const { path: projectPath, dependency: dependencyPath, name } = params;
|
|
15
|
+
// Validate project path
|
|
16
|
+
const indexDir = join(projectPath, INDEX_DIR);
|
|
17
|
+
const dbPath = join(indexDir, 'index.db');
|
|
18
|
+
if (!existsSync(dbPath)) {
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
name: '',
|
|
22
|
+
filesAvailable: 0,
|
|
23
|
+
error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Validate dependency path
|
|
27
|
+
const depIndexDir = join(dependencyPath, INDEX_DIR);
|
|
28
|
+
const depDbPath = join(depIndexDir, 'index.db');
|
|
29
|
+
if (!existsSync(depDbPath)) {
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
name: '',
|
|
33
|
+
filesAvailable: 0,
|
|
34
|
+
error: `No ${PRODUCT_NAME} index found at ${dependencyPath}. Run ${TOOL_PREFIX}init on dependency first.`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// Open main database
|
|
38
|
+
const db = openDatabase(dbPath);
|
|
39
|
+
try {
|
|
40
|
+
// Get dependency info
|
|
41
|
+
const depDb = openDatabase(depDbPath, true);
|
|
42
|
+
const depStats = depDb.getStats();
|
|
43
|
+
const depName = name ?? depDb.getMetadata('project_name') ?? basename(dependencyPath);
|
|
44
|
+
depDb.close();
|
|
45
|
+
// Check if already linked
|
|
46
|
+
const existingDep = db.getDb().prepare('SELECT * FROM dependencies WHERE path = ?').get(dependencyPath);
|
|
47
|
+
let dependencyId;
|
|
48
|
+
if (existingDep) {
|
|
49
|
+
// Update existing
|
|
50
|
+
db.getDb().prepare('UPDATE dependencies SET name = ?, last_checked = ? WHERE id = ?').run(depName, Date.now(), existingDep.id);
|
|
51
|
+
dependencyId = existingDep.id;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// Insert new
|
|
55
|
+
const result = db.getDb().prepare('INSERT INTO dependencies (path, name, last_checked) VALUES (?, ?, ?)').run(dependencyPath, depName, Date.now());
|
|
56
|
+
dependencyId = result.lastInsertRowid;
|
|
57
|
+
}
|
|
58
|
+
db.close();
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
dependencyId,
|
|
62
|
+
name: depName,
|
|
63
|
+
filesAvailable: depStats.files,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
db.close();
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
name: '',
|
|
71
|
+
filesAvailable: 0,
|
|
72
|
+
error: err instanceof Error ? err.message : String(err),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ============================================================
|
|
77
|
+
// Unlink implementation
|
|
78
|
+
// ============================================================
|
|
79
|
+
export function unlink(params) {
|
|
80
|
+
const { path: projectPath, dependency: dependencyPath } = params;
|
|
81
|
+
// Validate project path
|
|
82
|
+
const indexDir = join(projectPath, INDEX_DIR);
|
|
83
|
+
const dbPath = join(indexDir, 'index.db');
|
|
84
|
+
if (!existsSync(dbPath)) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
removed: false,
|
|
88
|
+
error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Open database
|
|
92
|
+
const db = openDatabase(dbPath);
|
|
93
|
+
try {
|
|
94
|
+
const result = db.getDb().prepare('DELETE FROM dependencies WHERE path = ?').run(dependencyPath);
|
|
95
|
+
db.close();
|
|
96
|
+
return {
|
|
97
|
+
success: true,
|
|
98
|
+
removed: result.changes > 0,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
db.close();
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
removed: false,
|
|
106
|
+
error: err instanceof Error ? err.message : String(err),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// ============================================================
|
|
111
|
+
// List links implementation
|
|
112
|
+
// ============================================================
|
|
113
|
+
export function listLinks(params) {
|
|
114
|
+
const { path: projectPath } = params;
|
|
115
|
+
// Validate project path
|
|
116
|
+
const indexDir = join(projectPath, INDEX_DIR);
|
|
117
|
+
const dbPath = join(indexDir, 'index.db');
|
|
118
|
+
if (!existsSync(dbPath)) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
dependencies: [],
|
|
122
|
+
error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Open database
|
|
126
|
+
const db = openDatabase(dbPath, true);
|
|
127
|
+
try {
|
|
128
|
+
const deps = db.getDb().prepare('SELECT * FROM dependencies ORDER BY name').all();
|
|
129
|
+
const dependencies = [];
|
|
130
|
+
for (const dep of deps) {
|
|
131
|
+
const depDbPath = join(dep.path, INDEX_DIR, 'index.db');
|
|
132
|
+
const available = existsSync(depDbPath);
|
|
133
|
+
let filesAvailable = 0;
|
|
134
|
+
if (available) {
|
|
135
|
+
try {
|
|
136
|
+
const depDb = openDatabase(depDbPath, true);
|
|
137
|
+
filesAvailable = depDb.getStats().files;
|
|
138
|
+
depDb.close();
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Ignore errors reading dependency
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
dependencies.push({
|
|
145
|
+
id: dep.id,
|
|
146
|
+
path: dep.path,
|
|
147
|
+
name: dep.name,
|
|
148
|
+
filesAvailable,
|
|
149
|
+
available,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
db.close();
|
|
153
|
+
return {
|
|
154
|
+
success: true,
|
|
155
|
+
dependencies,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
db.close();
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
dependencies: [],
|
|
163
|
+
error: err instanceof Error ? err.message : String(err),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* note command - Session notes for cross-session communication
|
|
3
|
+
*
|
|
4
|
+
* Stores a single text note in the project's AiDex database that persists
|
|
5
|
+
* between sessions. Useful for:
|
|
6
|
+
* - Reminders for the next session ("Test glob pattern fix!")
|
|
7
|
+
* - User requests ("Remember to refactor X")
|
|
8
|
+
* - Auto-generated notes before session end
|
|
9
|
+
*
|
|
10
|
+
* v1.3.0 - Session tracking integration
|
|
11
|
+
*/
|
|
12
|
+
export interface NoteParams {
|
|
13
|
+
path: string;
|
|
14
|
+
note?: string;
|
|
15
|
+
append?: boolean;
|
|
16
|
+
clear?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface NoteResult {
|
|
19
|
+
success: boolean;
|
|
20
|
+
note: string | null;
|
|
21
|
+
action: 'read' | 'write' | 'append' | 'clear';
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function note(params: NoteParams): NoteResult;
|
|
25
|
+
/**
|
|
26
|
+
* Get note for a project (used internally by other tools to include in output)
|
|
27
|
+
*/
|
|
28
|
+
export declare function getSessionNote(projectPath: string): string | null;
|
|
29
|
+
//# sourceMappingURL=note.d.ts.map
|