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,105 @@
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
+ import { existsSync } from 'fs';
13
+ import { join } from 'path';
14
+ import { PRODUCT_NAME, INDEX_DIR, TOOL_PREFIX } from '../constants.js';
15
+ import { openDatabase } from '../db/index.js';
16
+ // ============================================================
17
+ // Constants
18
+ // ============================================================
19
+ const NOTE_KEY = 'session_note';
20
+ // ============================================================
21
+ // Implementation
22
+ // ============================================================
23
+ export function note(params) {
24
+ const { path: projectPath, note: newNote, append, clear } = params;
25
+ // Validate project path
26
+ const dbPath = join(projectPath, INDEX_DIR, 'index.db');
27
+ if (!existsSync(dbPath)) {
28
+ return {
29
+ success: false,
30
+ note: null,
31
+ action: 'read',
32
+ error: `No ${PRODUCT_NAME} index found at ${projectPath}. Run ${TOOL_PREFIX}init first.`,
33
+ };
34
+ }
35
+ // Open database (read-write for writing, read-only for reading)
36
+ const isWriteOperation = newNote !== undefined || clear;
37
+ const db = openDatabase(dbPath, !isWriteOperation);
38
+ try {
39
+ if (clear) {
40
+ // Clear the note
41
+ db.deleteMetadata(NOTE_KEY);
42
+ db.close();
43
+ return {
44
+ success: true,
45
+ note: null,
46
+ action: 'clear',
47
+ };
48
+ }
49
+ if (newNote !== undefined) {
50
+ // Write or append note
51
+ let finalNote = newNote;
52
+ if (append) {
53
+ // Get existing note first
54
+ const existing = db.getMetadata(NOTE_KEY);
55
+ if (existing) {
56
+ finalNote = existing + '\n' + newNote;
57
+ }
58
+ }
59
+ // Save the note
60
+ db.setMetadata(NOTE_KEY, finalNote);
61
+ db.close();
62
+ return {
63
+ success: true,
64
+ note: finalNote,
65
+ action: append ? 'append' : 'write',
66
+ };
67
+ }
68
+ // Read note
69
+ const currentNote = db.getMetadata(NOTE_KEY);
70
+ db.close();
71
+ return {
72
+ success: true,
73
+ note: currentNote,
74
+ action: 'read',
75
+ };
76
+ }
77
+ catch (error) {
78
+ db.close();
79
+ return {
80
+ success: false,
81
+ note: null,
82
+ action: 'read',
83
+ error: error instanceof Error ? error.message : String(error),
84
+ };
85
+ }
86
+ }
87
+ /**
88
+ * Get note for a project (used internally by other tools to include in output)
89
+ */
90
+ export function getSessionNote(projectPath) {
91
+ const dbPath = join(projectPath, INDEX_DIR, 'index.db');
92
+ if (!existsSync(dbPath)) {
93
+ return null;
94
+ }
95
+ try {
96
+ const db = openDatabase(dbPath, true);
97
+ const currentNote = db.getMetadata(NOTE_KEY);
98
+ db.close();
99
+ return currentNote;
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ }
105
+ //# sourceMappingURL=note.js.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * query command - Search for terms in the index
3
+ */
4
+ export type QueryMode = 'exact' | 'contains' | 'starts_with';
5
+ export interface QueryParams {
6
+ path: string;
7
+ term: string;
8
+ mode?: QueryMode;
9
+ fileFilter?: string;
10
+ typeFilter?: string[];
11
+ modifiedSince?: string;
12
+ modifiedBefore?: string;
13
+ limit?: number;
14
+ }
15
+ export interface QueryMatch {
16
+ file: string;
17
+ lineNumber: number;
18
+ lineType: string;
19
+ modified?: number;
20
+ }
21
+ export interface QueryResult {
22
+ success: boolean;
23
+ term: string;
24
+ mode: QueryMode;
25
+ matches: QueryMatch[];
26
+ totalMatches: number;
27
+ truncated: boolean;
28
+ error?: string;
29
+ }
30
+ export declare function query(params: QueryParams): QueryResult;
31
+ /**
32
+ * Parse time offset string to Unix timestamp
33
+ * Supports: "2h" (hours), "30m" (minutes), "1d" (days), "1w" (weeks), or ISO date string
34
+ */
35
+ export declare function parseTimeOffset(input: string): number | null;
36
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1,176 @@
1
+ /**
2
+ * query command - Search for terms in the index
3
+ */
4
+ import { existsSync } from 'fs';
5
+ import { join } from 'path';
6
+ import { PRODUCT_NAME, INDEX_DIR, TOOL_PREFIX } from '../constants.js';
7
+ import { openDatabase, createQueries } from '../db/index.js';
8
+ // ============================================================
9
+ // Main query function
10
+ // ============================================================
11
+ export function query(params) {
12
+ const mode = params.mode ?? 'exact';
13
+ const limit = params.limit ?? 100;
14
+ // Validate project path
15
+ const dbPath = join(params.path, INDEX_DIR, 'index.db');
16
+ if (!existsSync(dbPath)) {
17
+ return {
18
+ success: false,
19
+ term: params.term,
20
+ mode,
21
+ matches: [],
22
+ totalMatches: 0,
23
+ truncated: false,
24
+ error: `No ${PRODUCT_NAME} index found at ${params.path}. Run ${TOOL_PREFIX}init first.`,
25
+ };
26
+ }
27
+ // Open database
28
+ const db = openDatabase(dbPath, true);
29
+ const queries = createQueries(db);
30
+ try {
31
+ // Search for items
32
+ const items = queries.searchItems(params.term, mode, 1000);
33
+ if (items.length === 0) {
34
+ db.close();
35
+ return {
36
+ success: true,
37
+ term: params.term,
38
+ mode,
39
+ matches: [],
40
+ totalMatches: 0,
41
+ truncated: false,
42
+ };
43
+ }
44
+ // Parse time filters
45
+ const modifiedSinceTs = params.modifiedSince ? parseTimeOffset(params.modifiedSince) : null;
46
+ const modifiedBeforeTs = params.modifiedBefore ? parseTimeOffset(params.modifiedBefore) : null;
47
+ // Collect all occurrences
48
+ let allMatches = [];
49
+ for (const item of items) {
50
+ const occurrences = queries.getOccurrencesByItem(item.id);
51
+ for (const occ of occurrences) {
52
+ // Apply file filter
53
+ if (params.fileFilter && !matchesGlob(occ.path, params.fileFilter)) {
54
+ continue;
55
+ }
56
+ // Apply type filter
57
+ if (params.typeFilter && params.typeFilter.length > 0) {
58
+ if (!params.typeFilter.includes(occ.line_type)) {
59
+ continue;
60
+ }
61
+ }
62
+ // Apply time filters
63
+ if (modifiedSinceTs !== null && occ.modified !== null) {
64
+ if (occ.modified < modifiedSinceTs) {
65
+ continue;
66
+ }
67
+ }
68
+ if (modifiedBeforeTs !== null && occ.modified !== null) {
69
+ if (occ.modified > modifiedBeforeTs) {
70
+ continue;
71
+ }
72
+ }
73
+ allMatches.push({
74
+ file: occ.path,
75
+ lineNumber: occ.line_number,
76
+ lineType: occ.line_type,
77
+ modified: occ.modified ?? undefined,
78
+ });
79
+ }
80
+ }
81
+ // Remove duplicates (same file + line)
82
+ const seen = new Set();
83
+ allMatches = allMatches.filter(m => {
84
+ const key = `${m.file}:${m.lineNumber}`;
85
+ if (seen.has(key))
86
+ return false;
87
+ seen.add(key);
88
+ return true;
89
+ });
90
+ // Sort by file, then line number
91
+ allMatches.sort((a, b) => {
92
+ const fileCompare = a.file.localeCompare(b.file);
93
+ if (fileCompare !== 0)
94
+ return fileCompare;
95
+ return a.lineNumber - b.lineNumber;
96
+ });
97
+ const totalMatches = allMatches.length;
98
+ const truncated = allMatches.length > limit;
99
+ if (truncated) {
100
+ allMatches = allMatches.slice(0, limit);
101
+ }
102
+ db.close();
103
+ return {
104
+ success: true,
105
+ term: params.term,
106
+ mode,
107
+ matches: allMatches,
108
+ totalMatches,
109
+ truncated,
110
+ };
111
+ }
112
+ catch (error) {
113
+ db.close();
114
+ return {
115
+ success: false,
116
+ term: params.term,
117
+ mode,
118
+ matches: [],
119
+ totalMatches: 0,
120
+ truncated: false,
121
+ error: error instanceof Error ? error.message : String(error),
122
+ };
123
+ }
124
+ }
125
+ // ============================================================
126
+ // Helper functions
127
+ // ============================================================
128
+ /**
129
+ * Parse time offset string to Unix timestamp
130
+ * Supports: "2h" (hours), "30m" (minutes), "1d" (days), "1w" (weeks), or ISO date string
131
+ */
132
+ export function parseTimeOffset(input) {
133
+ if (!input)
134
+ return null;
135
+ // Try relative time format: 2h, 30m, 1d, 1w
136
+ const match = input.match(/^(\d+)([mhdw])$/i);
137
+ if (match) {
138
+ const value = parseInt(match[1], 10);
139
+ const unit = match[2].toLowerCase();
140
+ const now = Date.now();
141
+ switch (unit) {
142
+ case 'm': return now - value * 60 * 1000; // minutes
143
+ case 'h': return now - value * 60 * 60 * 1000; // hours
144
+ case 'd': return now - value * 24 * 60 * 60 * 1000; // days
145
+ case 'w': return now - value * 7 * 24 * 60 * 60 * 1000; // weeks
146
+ }
147
+ }
148
+ // Try ISO date string
149
+ const date = new Date(input);
150
+ if (!isNaN(date.getTime())) {
151
+ return date.getTime();
152
+ }
153
+ return null;
154
+ }
155
+ /**
156
+ * Simple glob matching (supports * and ** patterns)
157
+ * Handles patterns like "** /folder/** " correctly for paths starting with folder/
158
+ */
159
+ function matchesGlob(path, pattern) {
160
+ // Normalize path separators
161
+ const normalizedPath = path.replace(/\\/g, '/');
162
+ const normalizedPattern = pattern.replace(/\\/g, '/');
163
+ // Convert glob to regex using placeholders to avoid interference
164
+ let regex = normalizedPattern
165
+ .replace(/\./g, '\\.') // Escape dots
166
+ .replace(/\*\*\//g, '<<<STARSTAR_SLASH>>>') // **/ placeholder
167
+ .replace(/\/\*\*/g, '<<<SLASH_STARSTAR>>>') // /** placeholder
168
+ .replace(/\*\*/g, '<<<STARSTAR>>>') // standalone ** placeholder
169
+ .replace(/\*/g, '[^/]*') // * matches anything except /
170
+ .replace(/<<<STARSTAR_SLASH>>>/g, '(.*/)?') // **/ = optional prefix ending with /
171
+ .replace(/<<<SLASH_STARSTAR>>>/g, '(/.*)?') // /** = optional suffix starting with /
172
+ .replace(/<<<STARSTAR>>>/g, '.*'); // ** matches anything
173
+ regex = '^' + regex + '$';
174
+ return new RegExp(regex, 'i').test(normalizedPath);
175
+ }
176
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * scan command - Find all AiDex index directories!
3
+ */
4
+ export interface ScanParams {
5
+ path: string;
6
+ maxDepth?: number;
7
+ }
8
+ export interface IndexedProject {
9
+ path: string;
10
+ name: string;
11
+ files: number;
12
+ items: number;
13
+ methods: number;
14
+ types: number;
15
+ lastIndexed: string;
16
+ }
17
+ export interface ScanResult {
18
+ success: boolean;
19
+ searchPath: string;
20
+ projects: IndexedProject[];
21
+ scannedDirs: number;
22
+ error?: string;
23
+ }
24
+ export declare function scan(params: ScanParams): ScanResult;
25
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1,104 @@
1
+ /**
2
+ * scan command - Find all AiDex index directories!
3
+ */
4
+ import { existsSync, readdirSync } from 'fs';
5
+ import { join, basename } from 'path';
6
+ import { INDEX_DIR } from '../constants.js';
7
+ import { openDatabase } from '../db/index.js';
8
+ // ============================================================
9
+ // Default excluded directories
10
+ // ============================================================
11
+ const EXCLUDED_DIRS = new Set([
12
+ 'node_modules',
13
+ '.git',
14
+ '.svn',
15
+ '.hg',
16
+ '__pycache__',
17
+ '.cache',
18
+ 'dist',
19
+ 'build',
20
+ 'out',
21
+ 'target',
22
+ 'bin',
23
+ 'obj',
24
+ '.next',
25
+ '.nuxt',
26
+ 'vendor',
27
+ '.gradle',
28
+ '.idea',
29
+ '.vscode',
30
+ ]);
31
+ // ============================================================
32
+ // Main scan function
33
+ // ============================================================
34
+ export function scan(params) {
35
+ const { path: searchPath, maxDepth = 10 } = params;
36
+ // Validate path
37
+ if (!existsSync(searchPath)) {
38
+ return {
39
+ success: false,
40
+ searchPath,
41
+ projects: [],
42
+ scannedDirs: 0,
43
+ error: `Path does not exist: ${searchPath}`,
44
+ };
45
+ }
46
+ const projects = [];
47
+ let scannedDirs = 0;
48
+ function scanDirectory(dirPath, depth) {
49
+ if (depth > maxDepth)
50
+ return;
51
+ scannedDirs++;
52
+ // Check if this directory has an index dir
53
+ const indexPath = join(dirPath, INDEX_DIR);
54
+ const dbPath = join(indexPath, 'index.db');
55
+ if (existsSync(dbPath)) {
56
+ try {
57
+ const db = openDatabase(dbPath, true);
58
+ const stats = db.getStats();
59
+ const projectName = db.getMetadata('project_name') ?? basename(dirPath);
60
+ const lastIndexed = db.getMetadata('last_indexed') ?? 'unknown';
61
+ db.close();
62
+ projects.push({
63
+ path: dirPath,
64
+ name: projectName,
65
+ files: stats.files,
66
+ items: stats.items,
67
+ methods: stats.methods,
68
+ types: stats.types,
69
+ lastIndexed,
70
+ });
71
+ }
72
+ catch {
73
+ // Skip invalid databases
74
+ }
75
+ }
76
+ // Scan subdirectories
77
+ try {
78
+ const entries = readdirSync(dirPath, { withFileTypes: true });
79
+ for (const entry of entries) {
80
+ if (!entry.isDirectory())
81
+ continue;
82
+ if (entry.name.startsWith('.') && entry.name !== INDEX_DIR)
83
+ continue;
84
+ if (EXCLUDED_DIRS.has(entry.name))
85
+ continue;
86
+ const subPath = join(dirPath, entry.name);
87
+ scanDirectory(subPath, depth + 1);
88
+ }
89
+ }
90
+ catch {
91
+ // Skip directories we can't read
92
+ }
93
+ }
94
+ scanDirectory(searchPath, 0);
95
+ // Sort by path
96
+ projects.sort((a, b) => a.path.localeCompare(b.path));
97
+ return {
98
+ success: true,
99
+ searchPath,
100
+ projects,
101
+ scannedDirs,
102
+ };
103
+ }
104
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * session command - Session tracking and external change detection
3
+ *
4
+ * Tracks session start/end times and detects files changed outside of sessions.
5
+ * This enables:
6
+ * - "What did we do last session?" queries using time filtering
7
+ * - Automatic detection of externally modified files that need re-indexing
8
+ */
9
+ export interface SessionParams {
10
+ path: string;
11
+ }
12
+ export interface SessionInfo {
13
+ lastSessionStart: number | null;
14
+ lastSessionEnd: number | null;
15
+ currentSessionStart: number | null;
16
+ }
17
+ export interface ChangedFile {
18
+ path: string;
19
+ reason: 'modified' | 'deleted' | 'new';
20
+ }
21
+ export interface SessionResult {
22
+ success: boolean;
23
+ isNewSession: boolean;
24
+ sessionInfo: SessionInfo;
25
+ externalChanges: ChangedFile[];
26
+ reindexed: string[];
27
+ note: string | null;
28
+ error?: string;
29
+ }
30
+ /**
31
+ * Start or continue a session.
32
+ * - If new session: detect external changes, store previous session times
33
+ * - Always: update session_end timestamp
34
+ */
35
+ export declare function session(params: SessionParams): SessionResult;
36
+ /**
37
+ * Update session heartbeat (call periodically during session)
38
+ */
39
+ export declare function updateSessionHeartbeat(projectPath: string): void;
40
+ /**
41
+ * Get session info without starting/updating
42
+ */
43
+ export declare function getSessionInfo(projectPath: string): SessionInfo | null;
44
+ /**
45
+ * Format session time for display
46
+ */
47
+ export declare function formatSessionTime(timestamp: number | null): string;
48
+ /**
49
+ * Format duration between two timestamps
50
+ */
51
+ export declare function formatDuration(startMs: number, endMs: number): string;
52
+ //# sourceMappingURL=session.d.ts.map