smart-coding-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,314 @@
1
+ // Comprehensive ignore patterns based on industry best practices
2
+ // Researched from gitignore templates and development community standards
3
+
4
+ export const IGNORE_PATTERNS = {
5
+ // JavaScript/Node.js
6
+ javascript: [
7
+ '**/node_modules/**',
8
+ '**/.next/**',
9
+ '**/dist/**',
10
+ '**/build/**',
11
+ '**/.nuxt/**',
12
+ '**/.output/**',
13
+ '**/.vercel/**',
14
+ '**/.netlify/**',
15
+ '**/out/**',
16
+ '**/coverage/**',
17
+ '**/.nyc_output/**',
18
+ '**/npm-debug.log*',
19
+ '**/yarn-debug.log*',
20
+ '**/yarn-error.log*',
21
+ '**/.pnpm-store/**',
22
+ '**/.turbo/**'
23
+ ],
24
+
25
+ // Python
26
+ python: [
27
+ '**/__pycache__/**',
28
+ '**/*.pyc',
29
+ '**/*.pyd',
30
+ '**/.Python',
31
+ '**/build/**',
32
+ '**/develop-eggs/**',
33
+ '**/dist/**',
34
+ '**/downloads/**',
35
+ '**/eggs/**',
36
+ '**/.eggs/**',
37
+ '**/lib/**',
38
+ '**/lib64/**',
39
+ '**/parts/**',
40
+ '**/sdist/**',
41
+ '**/var/**',
42
+ '**/*.egg-info/**',
43
+ '**/.installed.cfg',
44
+ '**/*.egg',
45
+ '**/.venv/**',
46
+ '**/venv/**',
47
+ '**/env/**',
48
+ '**/ENV/**',
49
+ '**/.pytest_cache/**',
50
+ '**/htmlcov/**',
51
+ '**/.tox/**',
52
+ '**/.coverage',
53
+ '**/.hypothesis/**',
54
+ '**/.mypy_cache/**',
55
+ '**/.ruff_cache/**'
56
+ ],
57
+
58
+ // Java/Maven
59
+ java: [
60
+ '**/target/**',
61
+ '**/.gradle/**',
62
+ '**/build/**',
63
+ '**/.idea/**',
64
+ '**/*.iml',
65
+ '**/out/**',
66
+ '**/gen/**',
67
+ '**/classes/**',
68
+ '**/.classpath',
69
+ '**/.project',
70
+ '**/.settings/**',
71
+ '**/.m2/**',
72
+ '**/*.class',
73
+ '**/*.jar',
74
+ '**/*.war',
75
+ '**/*.ear'
76
+ ],
77
+
78
+ // Android
79
+ android: [
80
+ '**/.gradle/**',
81
+ '**/build/**',
82
+ '**/.idea/**',
83
+ '**/*.iml',
84
+ '**/local.properties',
85
+ '**/captures/**',
86
+ '**/.externalNativeBuild/**',
87
+ '**/.cxx/**',
88
+ '**/*.apk',
89
+ '**/*.aar',
90
+ '**/*.ap_',
91
+ '**/*.dex',
92
+ '**/google-services.json',
93
+ '**/gradle-app.setting',
94
+ '**/.navigation/**'
95
+ ],
96
+
97
+ // iOS/Swift
98
+ ios: [
99
+ '**/Pods/**',
100
+ '**/DerivedData/**',
101
+ '**/xcuserdata/**',
102
+ '**/*.xcarchive',
103
+ '**/build/**',
104
+ '**/.build/**',
105
+ '**/Packages/**',
106
+ '**/.swiftpm/**',
107
+ '**/Carthage/Build/**',
108
+ '**/fastlane/report.xml',
109
+ '**/fastlane/Preview.html',
110
+ '**/fastlane/screenshots/**',
111
+ '**/fastlane/test_output/**',
112
+ '**/*.moved-aside',
113
+ '**/*.xcuserstate',
114
+ '**/*.hmap',
115
+ '**/*.ipa'
116
+ ],
117
+
118
+ // Go
119
+ go: [
120
+ '**/vendor/**',
121
+ '**/bin/**',
122
+ '**/pkg/**',
123
+ '**/*.exe',
124
+ '**/*.test',
125
+ '**/*.prof'
126
+ ],
127
+
128
+ // PHP
129
+ php: [
130
+ '**/vendor/**',
131
+ '**/composer.phar',
132
+ '**/composer.lock',
133
+ '**/.phpunit.result.cache'
134
+ ],
135
+
136
+ // Rust
137
+ rust: [
138
+ '**/target/**',
139
+ '**/Cargo.lock',
140
+ '**/*.rs.bk'
141
+ ],
142
+
143
+ // Ruby
144
+ ruby: [
145
+ '**/vendor/bundle/**',
146
+ '**/.bundle/**',
147
+ '**/Gemfile.lock',
148
+ '**/.byebug_history'
149
+ ],
150
+
151
+ // .NET/C#
152
+ dotnet: [
153
+ '**/bin/**',
154
+ '**/obj/**',
155
+ '**/packages/**',
156
+ '**/*.user',
157
+ '**/*.suo',
158
+ '**/.vs/**',
159
+ '**/node_modules/**'
160
+ ],
161
+
162
+ // Common (IDE, OS, Build tools)
163
+ common: [
164
+ // Version control
165
+ '**/.git/**',
166
+ '**/.svn/**',
167
+ '**/.hg/**',
168
+ '**/.bzr/**',
169
+
170
+ // OS files
171
+ '**/.DS_Store',
172
+ '**/Thumbs.db',
173
+ '**/desktop.ini',
174
+ '**/$RECYCLE.BIN/**',
175
+
176
+ // Backup files
177
+ '**/*.bak',
178
+ '**/*.backup',
179
+ '**/*~',
180
+ '**/*.swp',
181
+ '**/*.swo',
182
+ '**/*.swn',
183
+ '**/#*#',
184
+ '**/.#*',
185
+
186
+ // Lock files (editor/runtime, not package managers)
187
+ '**/*.lock',
188
+ '**/.~lock*',
189
+
190
+ // Logs
191
+ '**/*.log',
192
+ '**/logs/**',
193
+ '**/*.log.*',
194
+
195
+ // IDEs and Editors
196
+ '**/.vscode/**',
197
+ '**/.idea/**',
198
+ '**/.sublime-project',
199
+ '**/.sublime-workspace',
200
+ '**/nbproject/**',
201
+ '**/.settings/**',
202
+ '**/.metadata/**',
203
+ '**/.classpath',
204
+ '**/.project',
205
+ '**/.c9/**',
206
+ '**/*.launch',
207
+ '**/*.tmproj',
208
+ '**/*.tmproject',
209
+ '**/tmtags',
210
+
211
+ // Vim
212
+ '**/*~',
213
+ '**/*.swp',
214
+ '**/*.swo',
215
+ '**/.*.sw?',
216
+ '**/Session.vim',
217
+
218
+ // Emacs
219
+ '**/*~',
220
+ '**/#*#',
221
+ '**/.#*',
222
+
223
+ // Environment files (secrets)
224
+ '**/.env',
225
+ '**/.env.local',
226
+ '**/.env.*.local',
227
+ '**/.env.production',
228
+ '**/.env.development',
229
+ '**/.env.test',
230
+ '**/secrets.json',
231
+ '**/secrets.yaml',
232
+ '**/secrets.yml',
233
+ '**/*.key',
234
+ '**/*.pem',
235
+ '**/*.crt',
236
+ '**/*.cer',
237
+ '**/*.p12',
238
+ '**/*.pfx',
239
+
240
+ // Temporary files
241
+ '**/tmp/**',
242
+ '**/temp/**',
243
+ '**/*.tmp',
244
+ '**/*.temp',
245
+ '**/.cache/**',
246
+
247
+ // Session & runtime
248
+ '**/.sass-cache/**',
249
+ '**/connect.lock',
250
+ '**/*.pid',
251
+ '**/*.seed',
252
+ '**/*.pid.lock',
253
+
254
+ // Coverage & test output
255
+ '**/coverage/**',
256
+ '**/.nyc_output/**',
257
+ '**/test-results/**',
258
+ '**/*.cover',
259
+ '**/*.coverage',
260
+ '**/htmlcov/**',
261
+
262
+ // Documentation builds
263
+ '**/docs/_build/**',
264
+ '**/site/**',
265
+
266
+ // Misc
267
+ '**/*.orig',
268
+ '**/core',
269
+ '**/*.core'
270
+ ]
271
+ };
272
+
273
+ // Map marker files to project types
274
+ export const FILE_TYPE_MAP = {
275
+ // JavaScript/Node
276
+ 'package.json': 'javascript',
277
+ 'package-lock.json': 'javascript',
278
+ 'yarn.lock': 'javascript',
279
+ 'pnpm-lock.yaml': 'javascript',
280
+
281
+ // Python
282
+ 'requirements.txt': 'python',
283
+ 'Pipfile': 'python',
284
+ 'pyproject.toml': 'python',
285
+ 'setup.py': 'python',
286
+
287
+ // Android
288
+ 'build.gradle': 'android',
289
+ 'build.gradle.kts': 'android',
290
+ 'settings.gradle': 'android',
291
+
292
+ // Java
293
+ 'pom.xml': 'java',
294
+
295
+ // iOS
296
+ 'Podfile': 'ios',
297
+ 'Package.swift': 'ios',
298
+
299
+ // Go
300
+ 'go.mod': 'go',
301
+
302
+ // PHP
303
+ 'composer.json': 'php',
304
+
305
+ // Rust
306
+ 'Cargo.toml': 'rust',
307
+
308
+ // Ruby
309
+ 'Gemfile': 'ruby',
310
+
311
+ // .NET
312
+ '*.csproj': 'dotnet',
313
+ '*.sln': 'dotnet'
314
+ };
@@ -0,0 +1,75 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { FILE_TYPE_MAP, IGNORE_PATTERNS } from "./ignore-patterns.js";
4
+
5
+ export class ProjectDetector {
6
+ constructor(searchDirectory) {
7
+ this.searchDirectory = searchDirectory;
8
+ this.detectedTypes = new Set();
9
+ }
10
+
11
+ async detectProjectTypes() {
12
+ const markerFiles = Object.keys(FILE_TYPE_MAP);
13
+
14
+ for (const marker of markerFiles) {
15
+ // Handle wildcard patterns like *.csproj
16
+ if (marker.includes('*')) {
17
+ await this.detectWithWildcard(marker);
18
+ } else {
19
+ await this.detectExactFile(marker);
20
+ }
21
+ }
22
+
23
+ return Array.from(this.detectedTypes);
24
+ }
25
+
26
+ async detectExactFile(markerFile) {
27
+ const markerPath = path.join(this.searchDirectory, markerFile);
28
+ try {
29
+ await fs.access(markerPath);
30
+ const projectType = FILE_TYPE_MAP[markerFile];
31
+ this.detectedTypes.add(projectType);
32
+ console.error(`[Detector] Detected ${projectType} project (${markerFile})`);
33
+ } catch {
34
+ // File doesn't exist, continue
35
+ }
36
+ }
37
+
38
+ async detectWithWildcard(pattern) {
39
+ try {
40
+ const files = await fs.readdir(this.searchDirectory);
41
+ const regex = new RegExp('^' + pattern.replace('*', '.*') + '$');
42
+
43
+ for (const file of files) {
44
+ if (regex.test(file)) {
45
+ const projectType = FILE_TYPE_MAP[pattern];
46
+ this.detectedTypes.add(projectType);
47
+ console.error(`[Detector] Detected ${projectType} project (${file})`);
48
+ break;
49
+ }
50
+ }
51
+ } catch {
52
+ // Directory read failed, continue
53
+ }
54
+ }
55
+
56
+ getSmartIgnorePatterns() {
57
+ const patterns = [...IGNORE_PATTERNS.common];
58
+
59
+ for (const type of this.detectedTypes) {
60
+ if (IGNORE_PATTERNS[type]) {
61
+ patterns.push(...IGNORE_PATTERNS[type]);
62
+ }
63
+ }
64
+
65
+ // Remove duplicates
66
+ return [...new Set(patterns)];
67
+ }
68
+
69
+ getSummary() {
70
+ return {
71
+ detectedTypes: Array.from(this.detectedTypes),
72
+ patternCount: this.getSmartIgnorePatterns().length
73
+ };
74
+ }
75
+ }
package/lib/utils.js ADDED
@@ -0,0 +1,80 @@
1
+ import crypto from "crypto";
2
+ import path from "path";
3
+
4
+ /**
5
+ * Calculate cosine similarity between two vectors
6
+ */
7
+ export function cosineSimilarity(a, b) {
8
+ let dot = 0, normA = 0, normB = 0;
9
+ for (let i = 0; i < a.length; i++) {
10
+ dot += a[i] * b[i];
11
+ normA += a[i] * a[i];
12
+ normB += b[i] * b[i];
13
+ }
14
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB));
15
+ }
16
+
17
+ /**
18
+ * Generate hash for file content to detect changes
19
+ */
20
+ export function hashContent(content) {
21
+ return crypto.createHash("md5").update(content).digest("hex");
22
+ }
23
+
24
+ /**
25
+ * Intelligent chunking: tries to split by function/class boundaries
26
+ */
27
+ export function smartChunk(content, file, config) {
28
+ const lines = content.split("\n");
29
+ const chunks = [];
30
+ const ext = path.extname(file);
31
+
32
+ // Language-specific patterns for function/class detection
33
+ const patterns = {
34
+ js: /^(export\s+)?(async\s+)?(function|class|const|let|var)\s+\w+/,
35
+ ts: /^(export\s+)?(async\s+)?(function|class|const|let|var|interface|type)\s+\w+/,
36
+ py: /^(class|def)\s+\w+/,
37
+ java: /^(public|private|protected)?\s*(static\s+)?(class|interface|void|int|String|boolean)\s+\w+/,
38
+ go: /^func\s+\w+/,
39
+ rs: /^(pub\s+)?(fn|struct|enum|trait|impl)\s+\w+/,
40
+ };
41
+
42
+ const langPattern = patterns[ext.slice(1)] || patterns.js;
43
+ let currentChunk = [];
44
+ let chunkStartLine = 0;
45
+
46
+ for (let i = 0; i < lines.length; i++) {
47
+ const line = lines[i];
48
+ currentChunk.push(line);
49
+
50
+ // Check if we should start a new chunk
51
+ const shouldSplit =
52
+ langPattern.test(line.trim()) &&
53
+ currentChunk.length > config.chunkSize * 0.5;
54
+
55
+ if (shouldSplit || currentChunk.length >= config.chunkSize + config.chunkOverlap) {
56
+ if (currentChunk.join("\n").trim().length > 20) {
57
+ chunks.push({
58
+ text: currentChunk.join("\n"),
59
+ startLine: chunkStartLine + 1,
60
+ endLine: i + 1
61
+ });
62
+ }
63
+
64
+ // Keep overlap
65
+ currentChunk = currentChunk.slice(-config.chunkOverlap);
66
+ chunkStartLine = i - config.chunkOverlap + 1;
67
+ }
68
+ }
69
+
70
+ // Add remaining chunk
71
+ if (currentChunk.length > 0 && currentChunk.join("\n").trim().length > 20) {
72
+ chunks.push({
73
+ text: currentChunk.join("\n"),
74
+ startLine: chunkStartLine + 1,
75
+ endLine: lines.length
76
+ });
77
+ }
78
+
79
+ return chunks;
80
+ }
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "smart-coding-mcp",
3
+ "version": "1.0.0",
4
+ "description": "An extensible MCP server that enhances coding productivity with AI-powered features including semantic code search, intelligent indexing, and more, using local LLMs",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "smart-coding-mcp": "index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js",
12
+ "dev": "node --watch index.js",
13
+ "clear-cache": "node scripts/clear-cache.js"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "semantic-search",
18
+ "code-search",
19
+ "embeddings",
20
+ "ai",
21
+ "model-context-protocol",
22
+ "hybrid-search",
23
+ "code-intelligence",
24
+ "cursor",
25
+ "vscode",
26
+ "claude",
27
+ "codex",
28
+ "openai",
29
+ "gemini",
30
+ "anthropic"
31
+ ],
32
+ "author": {
33
+ "name": "Omar Haris",
34
+ "url": "https://www.linkedin.com/in/omarharis/"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/omar-haris/smart-coding-mcp.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/omar-haris/smart-coding-mcp/issues"
42
+ },
43
+ "homepage": "https://github.com/omar-haris/smart-coding-mcp#readme",
44
+ "license": "MIT",
45
+ "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.0.4",
47
+ "@xenova/transformers": "^2.17.2",
48
+ "glob": "^10.3.10",
49
+ "chokidar": "^3.5.3"
50
+ },
51
+ "engines": {
52
+ "node": ">=18.0.0"
53
+ }
54
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+
5
+ async function clearCache() {
6
+ try {
7
+ const configPath = path.join(process.cwd(), "config.json");
8
+ let cacheDir = "./.smart-coding-cache";
9
+
10
+ // Try to load cache directory from config
11
+ try {
12
+ const configData = await fs.readFile(configPath, "utf-8");
13
+ const config = JSON.parse(configData);
14
+ if (config.cacheDirectory) {
15
+ cacheDir = path.resolve(config.cacheDirectory);
16
+ }
17
+ } catch {
18
+ console.log("Using default cache directory");
19
+ }
20
+
21
+ // Remove cache directory
22
+ await fs.rm(cacheDir, { recursive: true, force: true });
23
+ console.log(`Cache cleared successfully: ${cacheDir}`);
24
+ console.log("Next startup will perform a full reindex.");
25
+ } catch (error) {
26
+ console.error(`Error clearing cache: ${error.message}`);
27
+ process.exit(1);
28
+ }
29
+ }
30
+
31
+ clearCache();