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,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