@softerist/heuristic-mcp 2.1.47 → 3.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.
- package/.agent/workflows/code-review.md +60 -0
- package/.prettierrc +7 -0
- package/ARCHITECTURE.md +105 -170
- package/CONTRIBUTING.md +32 -113
- package/GEMINI.md +73 -0
- package/LICENSE +21 -21
- package/README.md +161 -54
- package/config.json +876 -75
- package/debug-pids.js +27 -0
- package/eslint.config.js +36 -0
- package/features/ann-config.js +37 -26
- package/features/clear-cache.js +28 -19
- package/features/find-similar-code.js +142 -66
- package/features/hybrid-search.js +253 -93
- package/features/index-codebase.js +1455 -394
- package/features/lifecycle.js +813 -180
- package/features/register.js +58 -52
- package/index.js +450 -306
- package/lib/cache-ops.js +22 -0
- package/lib/cache-utils.js +68 -0
- package/lib/cache.js +1392 -587
- package/lib/call-graph.js +165 -50
- package/lib/cli.js +154 -0
- package/lib/config.js +462 -121
- package/lib/embedding-process.js +77 -0
- package/lib/embedding-worker.js +545 -30
- package/lib/ignore-patterns.js +61 -59
- package/lib/json-worker.js +14 -0
- package/lib/json-writer.js +344 -0
- package/lib/logging.js +88 -0
- package/lib/memory-logger.js +13 -0
- package/lib/project-detector.js +13 -17
- package/lib/server-lifecycle.js +38 -0
- package/lib/settings-editor.js +645 -0
- package/lib/tokenizer.js +207 -104
- package/lib/utils.js +273 -198
- package/lib/vector-store-binary.js +592 -0
- package/mcp_config.example.json +13 -0
- package/package.json +13 -2
- package/scripts/clear-cache.js +6 -17
- package/scripts/download-model.js +14 -9
- package/scripts/postinstall.js +5 -5
- package/search-configs.js +36 -0
- package/test/ann-config.test.js +179 -0
- package/test/ann-fallback.test.js +6 -6
- package/test/binary-store.test.js +69 -0
- package/test/cache-branches.test.js +120 -0
- package/test/cache-errors.test.js +264 -0
- package/test/cache-extra.test.js +300 -0
- package/test/cache-helpers.test.js +205 -0
- package/test/cache-hnsw-failure.test.js +40 -0
- package/test/cache-json-worker.test.js +190 -0
- package/test/cache-worker.test.js +102 -0
- package/test/cache.test.js +443 -0
- package/test/call-graph.test.js +103 -4
- package/test/clear-cache.test.js +69 -68
- package/test/code-review-workflow.test.js +50 -0
- package/test/config.test.js +418 -0
- package/test/coverage-gap.test.js +497 -0
- package/test/coverage-maximizer.test.js +236 -0
- package/test/debug-analysis.js +107 -0
- package/test/embedding-model.test.js +173 -103
- package/test/embedding-worker-extra.test.js +272 -0
- package/test/embedding-worker.test.js +158 -0
- package/test/features.test.js +139 -0
- package/test/final-boost.test.js +271 -0
- package/test/final-polish.test.js +183 -0
- package/test/final.test.js +95 -0
- package/test/find-similar-code.test.js +191 -0
- package/test/helpers.js +92 -11
- package/test/helpers.test.js +46 -0
- package/test/hybrid-search-basic.test.js +62 -0
- package/test/hybrid-search-branch.test.js +202 -0
- package/test/hybrid-search-callgraph.test.js +229 -0
- package/test/hybrid-search-extra.test.js +81 -0
- package/test/hybrid-search.test.js +484 -71
- package/test/index-cli.test.js +520 -0
- package/test/index-codebase-batch.test.js +119 -0
- package/test/index-codebase-branches.test.js +585 -0
- package/test/index-codebase-core.test.js +1032 -0
- package/test/index-codebase-edge-cases.test.js +254 -0
- package/test/index-codebase-errors.test.js +132 -0
- package/test/index-codebase-gap.test.js +239 -0
- package/test/index-codebase-lines.test.js +151 -0
- package/test/index-codebase-watcher.test.js +259 -0
- package/test/index-codebase-zone.test.js +259 -0
- package/test/index-codebase.test.js +371 -69
- package/test/index-memory.test.js +220 -0
- package/test/indexer-detailed.test.js +176 -0
- package/test/integration.test.js +148 -92
- package/test/json-worker.test.js +50 -0
- package/test/lifecycle.test.js +541 -0
- package/test/master.test.js +198 -0
- package/test/perfection.test.js +349 -0
- package/test/project-detector.test.js +65 -0
- package/test/register.test.js +262 -0
- package/test/tokenizer.test.js +55 -93
- package/test/ultra-maximizer.test.js +116 -0
- package/test/utils-branches.test.js +161 -0
- package/test/utils-extra.test.js +116 -0
- package/test/utils.test.js +131 -0
- package/test/verify_fixes.js +76 -0
- package/test/worker-errors.test.js +96 -0
- package/test/worker-init.test.js +102 -0
- package/test/worker_throttling.test.js +93 -0
- package/tools/scripts/benchmark-search.js +95 -0
- package/tools/scripts/cache-stats.js +71 -0
- package/tools/scripts/manual-search.js +34 -0
- package/vitest.config.js +19 -9
package/features/register.js
CHANGED
|
@@ -4,7 +4,7 @@ import { writeFileSync, existsSync, statSync } from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import os from 'os';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
|
-
|
|
7
|
+
import { parseJsonc, upsertMcpServerEntryInText } from '../lib/settings-editor.js';
|
|
8
8
|
|
|
9
9
|
// Detect which IDE is running the install
|
|
10
10
|
function detectCurrentIDE() {
|
|
@@ -18,17 +18,16 @@ function detectCurrentIDE() {
|
|
|
18
18
|
|
|
19
19
|
// Fallback: Check for Antigravity directory presence
|
|
20
20
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} catch (
|
|
21
|
+
const agPath = path.join(os.homedir(), '.gemini', 'antigravity');
|
|
22
|
+
if (existsSync(agPath) || (statSync && statSync(agPath).isDirectory())) {
|
|
23
|
+
return 'Antigravity';
|
|
24
|
+
}
|
|
25
|
+
} catch (_e) { /* ignore */ }
|
|
26
26
|
|
|
27
27
|
// Claude Desktop doesn't have a known env var, so we rely on existing config detection
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
32
31
|
// Known config paths for different IDEs
|
|
33
32
|
function getConfigPaths() {
|
|
34
33
|
const platform = process.platform;
|
|
@@ -39,19 +38,25 @@ function getConfigPaths() {
|
|
|
39
38
|
// Antigravity - dedicated mcp_config.json
|
|
40
39
|
allPaths.push({
|
|
41
40
|
name: 'Antigravity',
|
|
42
|
-
path: path.join(home, '.gemini', 'antigravity', 'mcp_config.json')
|
|
41
|
+
path: path.join(home, '.gemini', 'antigravity', 'mcp_config.json'),
|
|
43
42
|
});
|
|
44
43
|
|
|
45
44
|
// Claude Desktop - dedicated config file
|
|
46
45
|
if (platform === 'darwin') {
|
|
47
46
|
allPaths.push({
|
|
48
47
|
name: 'Claude Desktop',
|
|
49
|
-
path: path.join(
|
|
48
|
+
path: path.join(
|
|
49
|
+
home,
|
|
50
|
+
'Library',
|
|
51
|
+
'Application Support',
|
|
52
|
+
'Claude',
|
|
53
|
+
'claude_desktop_config.json'
|
|
54
|
+
),
|
|
50
55
|
});
|
|
51
56
|
} else if (platform === 'win32') {
|
|
52
57
|
allPaths.push({
|
|
53
58
|
name: 'Claude Desktop',
|
|
54
|
-
path: path.join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json')
|
|
59
|
+
path: path.join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json'),
|
|
55
60
|
});
|
|
56
61
|
}
|
|
57
62
|
|
|
@@ -59,17 +64,17 @@ function getConfigPaths() {
|
|
|
59
64
|
if (platform === 'darwin') {
|
|
60
65
|
allPaths.push({
|
|
61
66
|
name: 'Cursor',
|
|
62
|
-
path: path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'settings.json')
|
|
67
|
+
path: path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'settings.json'),
|
|
63
68
|
});
|
|
64
69
|
} else if (platform === 'win32') {
|
|
65
70
|
allPaths.push({
|
|
66
71
|
name: 'Cursor',
|
|
67
|
-
path: path.join(process.env.APPDATA || '', 'Cursor', 'User', 'settings.json')
|
|
72
|
+
path: path.join(process.env.APPDATA || '', 'Cursor', 'User', 'settings.json'),
|
|
68
73
|
});
|
|
69
74
|
} else {
|
|
70
75
|
allPaths.push({
|
|
71
76
|
name: 'Cursor',
|
|
72
|
-
path: path.join(home, '.config', 'Cursor', 'User', 'settings.json')
|
|
77
|
+
path: path.join(home, '.config', 'Cursor', 'User', 'settings.json'),
|
|
73
78
|
});
|
|
74
79
|
}
|
|
75
80
|
|
|
@@ -79,12 +84,10 @@ function getConfigPaths() {
|
|
|
79
84
|
|
|
80
85
|
if (currentIDE) {
|
|
81
86
|
// IDE detected - return only that IDE with permission to create
|
|
82
|
-
return allPaths
|
|
83
|
-
.filter(p => p.name === currentIDE)
|
|
84
|
-
.map(p => ({ ...p, canCreate: true }));
|
|
87
|
+
return allPaths.filter((p) => p.name === currentIDE).map((p) => ({ ...p, canCreate: true }));
|
|
85
88
|
} else {
|
|
86
89
|
// No IDE detected - return all but don't create new configs
|
|
87
|
-
return allPaths.map(p => ({ ...p, canCreate: false }));
|
|
90
|
+
return allPaths.map((p) => ({ ...p, canCreate: false }));
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
|
|
@@ -92,11 +95,11 @@ function getConfigPaths() {
|
|
|
92
95
|
function forceLog(message) {
|
|
93
96
|
try {
|
|
94
97
|
if (process.platform !== 'win32') {
|
|
95
|
-
|
|
98
|
+
writeFileSync('/dev/tty', message + '\n');
|
|
96
99
|
} else {
|
|
97
100
|
console.error(message);
|
|
98
101
|
}
|
|
99
|
-
} catch (
|
|
102
|
+
} catch (_e) {
|
|
100
103
|
console.error(message);
|
|
101
104
|
}
|
|
102
105
|
}
|
|
@@ -109,16 +112,15 @@ export async function register(filter = null) {
|
|
|
109
112
|
// For Antigravity, we MUST use absolute path because ${workspaceFolder} variable expansion
|
|
110
113
|
// is not supported in the current version, and '.' uses the wrong CWD.
|
|
111
114
|
// Use INIT_CWD (where npm install was run) if available, otherwise cwd.
|
|
112
|
-
const workspacePath =
|
|
115
|
+
const workspacePath =
|
|
116
|
+
currentIDE === 'Antigravity' ? process.env.INIT_CWD || process.cwd() : '${workspaceFolder}';
|
|
113
117
|
|
|
114
118
|
const serverConfig = {
|
|
115
119
|
command: binaryPath,
|
|
116
|
-
args: [scriptPath,
|
|
120
|
+
args: [scriptPath, '--workspace', workspacePath],
|
|
117
121
|
disabled: false,
|
|
118
|
-
autoRegistered: true // Marker to know we did this
|
|
119
122
|
};
|
|
120
123
|
|
|
121
|
-
|
|
122
124
|
const configPaths = getConfigPaths();
|
|
123
125
|
let registeredCount = 0;
|
|
124
126
|
|
|
@@ -131,7 +133,6 @@ export async function register(filter = null) {
|
|
|
131
133
|
|
|
132
134
|
try {
|
|
133
135
|
// Check if file exists - create if canCreate is true for this IDE
|
|
134
|
-
let config = {};
|
|
135
136
|
let fileExists = true;
|
|
136
137
|
|
|
137
138
|
try {
|
|
@@ -145,7 +146,9 @@ export async function register(filter = null) {
|
|
|
145
146
|
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
146
147
|
forceLog(`[Auto-Register] Creating ${name} config at ${configPath}`);
|
|
147
148
|
} catch (mkdirErr) {
|
|
148
|
-
forceLog(
|
|
149
|
+
forceLog(
|
|
150
|
+
`[Auto-Register] Skipped ${name}: Cannot create config directory: ${mkdirErr.message}`
|
|
151
|
+
);
|
|
149
152
|
continue;
|
|
150
153
|
}
|
|
151
154
|
} else {
|
|
@@ -154,37 +157,33 @@ export async function register(filter = null) {
|
|
|
154
157
|
}
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
|
|
160
|
+
let content = '';
|
|
158
161
|
if (fileExists) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
content = await fs.readFile(configPath, 'utf-8');
|
|
163
|
+
if (content.trim()) {
|
|
164
|
+
const parsed = parseJsonc(content);
|
|
165
|
+
if (!parsed) {
|
|
166
|
+
forceLog(
|
|
167
|
+
`[Auto-Register] Warning: ${name} config is not valid JSON/JSONC; skipping to avoid data loss.`
|
|
168
|
+
);
|
|
169
|
+
continue;
|
|
166
170
|
}
|
|
167
|
-
} catch (e) {
|
|
168
|
-
forceLog(`[Auto-Register] Warning: Corrupt/empty ${name} config, resetting to default. Error: ${e.message}`);
|
|
169
|
-
config = {};
|
|
170
171
|
}
|
|
171
|
-
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
if (!
|
|
176
|
-
|
|
174
|
+
const updated = upsertMcpServerEntryInText(content, 'heuristic-mcp', serverConfig);
|
|
175
|
+
if (!updated) {
|
|
176
|
+
forceLog(
|
|
177
|
+
`[Auto-Register] Warning: Failed to update ${name} config (could not locate root object).`
|
|
178
|
+
);
|
|
179
|
+
continue;
|
|
177
180
|
}
|
|
178
181
|
|
|
179
|
-
// Inject configuration
|
|
180
|
-
config.mcpServers['heuristic-mcp'] = serverConfig;
|
|
181
|
-
|
|
182
182
|
// Write back synchronously to avoid race conditions
|
|
183
|
-
writeFileSync(configPath,
|
|
183
|
+
writeFileSync(configPath, updated);
|
|
184
184
|
|
|
185
185
|
forceLog(`\x1b[32m[Auto-Register] ✅ Successfully registered with ${name}\x1b[0m`);
|
|
186
186
|
registeredCount++;
|
|
187
|
-
|
|
188
187
|
} catch (err) {
|
|
189
188
|
forceLog(`[Auto-Register] Failed to register with ${name}: ${err.message}`);
|
|
190
189
|
}
|
|
@@ -192,7 +191,9 @@ export async function register(filter = null) {
|
|
|
192
191
|
|
|
193
192
|
if (registeredCount === 0) {
|
|
194
193
|
forceLog(`[Auto-Register] No compatible IDE configurations found to update.`);
|
|
195
|
-
forceLog(
|
|
194
|
+
forceLog(
|
|
195
|
+
`[Auto-Register] Manual Config:\n${JSON.stringify({ mcpServers: { 'heuristic-mcp': serverConfig } }, null, 2)}`
|
|
196
|
+
);
|
|
196
197
|
} else {
|
|
197
198
|
// Friendly Banner (Using forceLog to bypass npm stdout suppression)
|
|
198
199
|
forceLog('\n\x1b[36m' + '='.repeat(60));
|
|
@@ -201,11 +202,15 @@ export async function register(filter = null) {
|
|
|
201
202
|
|
|
202
203
|
// Show important paths
|
|
203
204
|
const home = os.homedir();
|
|
204
|
-
const cacheRoot =
|
|
205
|
-
|
|
205
|
+
const cacheRoot =
|
|
206
|
+
process.platform === 'win32'
|
|
207
|
+
? path.join(
|
|
208
|
+
process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'),
|
|
209
|
+
'heuristic-mcp'
|
|
210
|
+
)
|
|
206
211
|
: process.platform === 'darwin'
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
? path.join(home, 'Library', 'Caches', 'heuristic-mcp')
|
|
213
|
+
: path.join(process.env.XDG_CACHE_HOME || path.join(home, '.cache'), 'heuristic-mcp');
|
|
209
214
|
|
|
210
215
|
forceLog(`
|
|
211
216
|
\x1b[33mACTION REQUIRED:\x1b[0m
|
|
@@ -218,9 +223,10 @@ export async function register(filter = null) {
|
|
|
218
223
|
- \x1b[1mUsage:\x1b[0m You can work while it indexes (it catches up!).
|
|
219
224
|
|
|
220
225
|
\x1b[90mPATHS:\x1b[0m
|
|
221
|
-
- \x1b[1mMCP Config:\x1b[0m ${configPaths.map(p => p.path).join(', ')}
|
|
226
|
+
- \x1b[1mMCP Config:\x1b[0m ${configPaths.map((p) => p.path).join(', ')}
|
|
222
227
|
- \x1b[1mCache:\x1b[0m ${cacheRoot}
|
|
223
|
-
- \x1b[1mCheck status:\x1b[0m heuristic-mcp --
|
|
228
|
+
- \x1b[1mCheck status:\x1b[0m heuristic-mcp --status
|
|
229
|
+
- \x1b[1mView logs:\x1b[0m heuristic-mcp --logs
|
|
224
230
|
|
|
225
231
|
\x1b[36mHappy Coding! 🤖\x1b[0m
|
|
226
232
|
`);
|