@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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function formatMb(bytes) {
|
|
2
|
+
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function logMemory(prefix) {
|
|
6
|
+
const { rss, heapUsed, heapTotal } = process.memoryUsage();
|
|
7
|
+
console.info(`${prefix} rss=${formatMb(rss)} heap=${formatMb(heapUsed)}/${formatMb(heapTotal)}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function startMemoryLogger(prefix, intervalMs) {
|
|
11
|
+
const timer = setInterval(() => logMemory(prefix), intervalMs);
|
|
12
|
+
return () => clearInterval(timer);
|
|
13
|
+
}
|
package/lib/project-detector.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
import { FILE_TYPE_MAP, IGNORE_PATTERNS } from
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { FILE_TYPE_MAP, IGNORE_PATTERNS, SKIP_DIRECTORIES } from './ignore-patterns.js';
|
|
4
4
|
|
|
5
5
|
export class ProjectDetector {
|
|
6
6
|
constructor(searchDirectory) {
|
|
@@ -8,22 +8,24 @@ export class ProjectDetector {
|
|
|
8
8
|
this.detectedTypes = new Set();
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
async detectProjectTypes() {
|
|
11
|
+
async detectProjectTypes(options = {}) {
|
|
12
|
+
const maxDepth = typeof options.maxDepth === 'number' ? options.maxDepth : 2;
|
|
13
|
+
const startDepth = typeof options.startDepth === 'number' ? options.startDepth : 0;
|
|
12
14
|
const markerFiles = Object.keys(FILE_TYPE_MAP);
|
|
13
15
|
const discoveredTypes = new Map(); // type -> first marker found
|
|
14
16
|
|
|
15
17
|
const checkDir = async (dir, depth) => {
|
|
16
|
-
if (depth >
|
|
18
|
+
if (depth > maxDepth) return;
|
|
17
19
|
|
|
18
20
|
const items = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
19
|
-
const itemNames = items.map(i => i.name);
|
|
21
|
+
const itemNames = items.map((i) => i.name);
|
|
20
22
|
const itemSet = new Set(itemNames);
|
|
21
23
|
|
|
22
24
|
for (const marker of markerFiles) {
|
|
23
25
|
let found = false;
|
|
24
26
|
if (marker.includes('*')) {
|
|
25
27
|
const regex = new RegExp('^' + marker.replace('*', '.*') + '$');
|
|
26
|
-
found = itemNames.some(file => regex.test(file));
|
|
28
|
+
found = itemNames.some((file) => regex.test(file));
|
|
27
29
|
} else {
|
|
28
30
|
found = itemSet.has(marker);
|
|
29
31
|
}
|
|
@@ -37,17 +39,11 @@ export class ProjectDetector {
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
// Recurse into subdirectories
|
|
40
|
-
if (depth <
|
|
42
|
+
if (depth < maxDepth) {
|
|
41
43
|
for (const item of items) {
|
|
42
44
|
if (item.isDirectory()) {
|
|
43
45
|
const name = item.name;
|
|
44
|
-
if (name.startsWith('.') ||
|
|
45
|
-
'node_modules', 'dist', 'build', 'target', 'vendor', // Build outputs
|
|
46
|
-
'coverage', 'htmlcov', // Test coverage
|
|
47
|
-
'typings', 'nltk_data', 'secrets', // Data/secrets
|
|
48
|
-
'venv', 'env', // Python envs (non-dot)
|
|
49
|
-
'__pycache__', 'eggs', '.eggs' // Python artifacts
|
|
50
|
-
].includes(name)) {
|
|
46
|
+
if (name.startsWith('.') || SKIP_DIRECTORIES.includes(name)) {
|
|
51
47
|
continue;
|
|
52
48
|
}
|
|
53
49
|
await checkDir(path.join(dir, name), depth + 1);
|
|
@@ -56,7 +52,7 @@ export class ProjectDetector {
|
|
|
56
52
|
}
|
|
57
53
|
};
|
|
58
54
|
|
|
59
|
-
await checkDir(this.searchDirectory,
|
|
55
|
+
await checkDir(this.searchDirectory, startDepth);
|
|
60
56
|
|
|
61
57
|
for (const [type, marker] of discoveredTypes) {
|
|
62
58
|
this.detectedTypes.add(type);
|
|
@@ -82,7 +78,7 @@ export class ProjectDetector {
|
|
|
82
78
|
getSummary() {
|
|
83
79
|
return {
|
|
84
80
|
detectedTypes: Array.from(this.detectedTypes),
|
|
85
|
-
patternCount: this.getSmartIgnorePatterns().length
|
|
81
|
+
patternCount: this.getSmartIgnorePatterns().length,
|
|
86
82
|
};
|
|
87
83
|
}
|
|
88
84
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import fsSync from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
6
|
+
function isTestEnv() {
|
|
7
|
+
return process.env.VITEST === 'true' || process.env.NODE_ENV === 'test';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function setupPidFile({ pidFileName = '.heuristic-mcp.pid' } = {}) {
|
|
11
|
+
if (isTestEnv()) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const pidPath = path.join(os.homedir(), pidFileName);
|
|
16
|
+
try {
|
|
17
|
+
await fs.writeFile(pidPath, `${process.pid}`, 'utf-8');
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.error(`[Server] Warning: Failed to write PID file: ${err.message}`);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const cleanup = () => {
|
|
24
|
+
try {
|
|
25
|
+
fsSync.unlinkSync(pidPath);
|
|
26
|
+
} catch {
|
|
27
|
+
// ignore
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
process.on('exit', cleanup);
|
|
32
|
+
return pidPath;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function registerSignalHandlers(handler) {
|
|
36
|
+
process.on('SIGINT', () => handler('SIGINT'));
|
|
37
|
+
process.on('SIGTERM', () => handler('SIGTERM'));
|
|
38
|
+
}
|