@softerist/heuristic-mcp 3.2.7 → 3.2.9
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/features/index-codebase.js +129 -30
- package/features/set-workspace.js +36 -2
- package/index.js +1702 -1637
- package/lib/config.js +43 -17
- package/lib/workspace-cache-key.js +34 -4
- package/package.json +1 -1
- package/search-configs.js +0 -36
package/lib/config.js
CHANGED
|
@@ -4,7 +4,7 @@ import os from 'os';
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { ProjectDetector } from './project-detector.js';
|
|
6
6
|
import { parseJsonc } from './settings-editor.js';
|
|
7
|
-
import {
|
|
7
|
+
import { getWorkspaceCachePathCandidates } from './workspace-cache-key.js';
|
|
8
8
|
import {
|
|
9
9
|
EMBEDDING_PROCESS_DEFAULT_GC_MAX_REQUESTS_WITHOUT_COLLECTION,
|
|
10
10
|
EMBEDDING_PROCESS_DEFAULT_GC_MIN_INTERVAL_MS,
|
|
@@ -37,6 +37,7 @@ const DEFAULT_INDEXING_CONFIG = {
|
|
|
37
37
|
maxResults: 5, // Maximum number of semantic search results to return
|
|
38
38
|
watchFiles: true, // Enable file system watcher to re-index changed files in real-time
|
|
39
39
|
indexCheckpointIntervalMs: 5000, // Periodic cache checkpoint during full indexing (0 disables)
|
|
40
|
+
shutdownIndexWaitMs: 3000, // Max wait during shutdown for cooperative index checkpointing
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
const DEFAULT_LOGGING_CONFIG = {
|
|
@@ -389,6 +390,7 @@ const DEFAULT_CONFIG = {
|
|
|
389
390
|
},
|
|
390
391
|
watchFiles: DEFAULT_INDEXING_CONFIG.watchFiles,
|
|
391
392
|
indexCheckpointIntervalMs: DEFAULT_INDEXING_CONFIG.indexCheckpointIntervalMs,
|
|
393
|
+
shutdownIndexWaitMs: DEFAULT_INDEXING_CONFIG.shutdownIndexWaitMs,
|
|
392
394
|
verbose: DEFAULT_LOGGING_CONFIG.verbose,
|
|
393
395
|
memoryLogIntervalMs: DEFAULT_LOGGING_CONFIG.memoryLogIntervalMs,
|
|
394
396
|
saveReaderWaitTimeoutMs: DEFAULT_CACHE_CONFIG.saveReaderWaitTimeoutMs,
|
|
@@ -880,23 +882,36 @@ export async function loadConfig(workspaceDir = null) {
|
|
|
880
882
|
: path.join(baseDir, userConfig.cacheDirectory);
|
|
881
883
|
} else {
|
|
882
884
|
// Use global cache directory to prevent cluttering project root.
|
|
883
|
-
// Workspace path is normalized for hashing so Windows
|
|
884
|
-
//
|
|
885
|
+
// Workspace path is normalized for hashing so Windows case variations map
|
|
886
|
+
// to one canonical cache key while preserving fallback compatibility.
|
|
885
887
|
const globalCacheRoot = getGlobalCacheDir();
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
888
|
+
const cachePaths = getWorkspaceCachePathCandidates(config.searchDirectory, globalCacheRoot);
|
|
889
|
+
let cacheResolutionMode = 'canonical';
|
|
890
|
+
|
|
891
|
+
config.cacheDirectory = cachePaths.canonical;
|
|
892
|
+
if (!(await pathExists(cachePaths.canonical))) {
|
|
893
|
+
if (
|
|
894
|
+
cachePaths.compatDriveCase !== cachePaths.canonical &&
|
|
895
|
+
(await pathExists(cachePaths.compatDriveCase))
|
|
896
|
+
) {
|
|
897
|
+
config.cacheDirectory = cachePaths.compatDriveCase;
|
|
898
|
+
cacheResolutionMode = 'compat-drivecase';
|
|
899
|
+
console.info(
|
|
900
|
+
`[Config] Using drive-case compatible cache path: ${path.basename(cachePaths.compatDriveCase)}`
|
|
901
|
+
);
|
|
902
|
+
} else if (
|
|
903
|
+
cachePaths.legacy !== cachePaths.canonical &&
|
|
904
|
+
(await pathExists(cachePaths.legacy))
|
|
905
|
+
) {
|
|
906
|
+
config.cacheDirectory = cachePaths.legacy;
|
|
907
|
+
cacheResolutionMode = 'legacy';
|
|
908
|
+
console.info(
|
|
909
|
+
`[Config] Using legacy cache path for compatibility: ${path.basename(cachePaths.legacy)}`
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
if (config.verbose || cacheResolutionMode !== 'canonical') {
|
|
914
|
+
console.info(`[Config] Cache resolution mode: ${cacheResolutionMode}`);
|
|
900
915
|
}
|
|
901
916
|
|
|
902
917
|
// Support legacy .smart-coding-cache if it already exists in the project root
|
|
@@ -1085,6 +1100,17 @@ export async function loadConfig(workspaceDir = null) {
|
|
|
1085
1100
|
}
|
|
1086
1101
|
}
|
|
1087
1102
|
|
|
1103
|
+
if (process.env.SMART_CODING_SHUTDOWN_INDEX_WAIT_MS !== undefined) {
|
|
1104
|
+
const value = parseInt(process.env.SMART_CODING_SHUTDOWN_INDEX_WAIT_MS, 10);
|
|
1105
|
+
if (!isNaN(value) && value >= 0) {
|
|
1106
|
+
config.shutdownIndexWaitMs = value;
|
|
1107
|
+
} else {
|
|
1108
|
+
console.warn(
|
|
1109
|
+
`[Config] Invalid SMART_CODING_SHUTDOWN_INDEX_WAIT_MS: ${process.env.SMART_CODING_SHUTDOWN_INDEX_WAIT_MS}, using default`
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1088
1114
|
if (process.env.SMART_CODING_SEMANTIC_WEIGHT !== undefined) {
|
|
1089
1115
|
const value = parseFloat(process.env.SMART_CODING_SEMANTIC_WEIGHT);
|
|
1090
1116
|
if (!isNaN(value) && value >= 0 && value <= 1) {
|
|
@@ -7,13 +7,22 @@ export function normalizeWorkspacePathForCacheKey(workspacePath) {
|
|
|
7
7
|
return resolved;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
// Windows paths are case-insensitive
|
|
11
|
-
//
|
|
12
|
-
|
|
10
|
+
// Windows paths are case-insensitive. Normalize the whole path so casing
|
|
11
|
+
// changes (including folder segments) map to one cache key.
|
|
12
|
+
return resolved.toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function normalizeWorkspacePathForCompatDriveLetterKey(workspacePath) {
|
|
16
|
+
const resolved = path.resolve(workspacePath);
|
|
17
|
+
if (process.platform !== 'win32') {
|
|
18
|
+
return resolved;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Compatibility behavior used by older versions: normalize drive letter
|
|
22
|
+
// casing only.
|
|
13
23
|
if (/^[A-Za-z]:/.test(resolved)) {
|
|
14
24
|
return `${resolved[0].toLowerCase()}${resolved.slice(1)}`;
|
|
15
25
|
}
|
|
16
|
-
|
|
17
26
|
return resolved;
|
|
18
27
|
}
|
|
19
28
|
|
|
@@ -22,6 +31,11 @@ export function getWorkspaceCacheKey(workspacePath) {
|
|
|
22
31
|
return crypto.createHash('md5').update(normalized).digest('hex').slice(0, 12);
|
|
23
32
|
}
|
|
24
33
|
|
|
34
|
+
export function getDriveLetterCompatWorkspaceCacheKey(workspacePath) {
|
|
35
|
+
const normalized = normalizeWorkspacePathForCompatDriveLetterKey(workspacePath);
|
|
36
|
+
return crypto.createHash('md5').update(normalized).digest('hex').slice(0, 12);
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
export function getLegacyWorkspaceCacheKey(workspacePath) {
|
|
26
40
|
const resolved = path.resolve(workspacePath);
|
|
27
41
|
return crypto.createHash('md5').update(resolved).digest('hex').slice(0, 12);
|
|
@@ -31,6 +45,22 @@ export function getWorkspaceCachePath(workspacePath, globalCacheRoot) {
|
|
|
31
45
|
return path.join(globalCacheRoot, 'heuristic-mcp', getWorkspaceCacheKey(workspacePath));
|
|
32
46
|
}
|
|
33
47
|
|
|
48
|
+
export function getDriveLetterCompatWorkspaceCachePath(workspacePath, globalCacheRoot) {
|
|
49
|
+
return path.join(
|
|
50
|
+
globalCacheRoot,
|
|
51
|
+
'heuristic-mcp',
|
|
52
|
+
getDriveLetterCompatWorkspaceCacheKey(workspacePath)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
34
56
|
export function getLegacyWorkspaceCachePath(workspacePath, globalCacheRoot) {
|
|
35
57
|
return path.join(globalCacheRoot, 'heuristic-mcp', getLegacyWorkspaceCacheKey(workspacePath));
|
|
36
58
|
}
|
|
59
|
+
|
|
60
|
+
export function getWorkspaceCachePathCandidates(workspacePath, globalCacheRoot) {
|
|
61
|
+
return {
|
|
62
|
+
canonical: getWorkspaceCachePath(workspacePath, globalCacheRoot),
|
|
63
|
+
compatDriveCase: getDriveLetterCompatWorkspaceCachePath(workspacePath, globalCacheRoot),
|
|
64
|
+
legacy: getLegacyWorkspaceCachePath(workspacePath, globalCacheRoot),
|
|
65
|
+
};
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softerist/heuristic-mcp",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.9",
|
|
4
4
|
"description": "An enhanced MCP server providing intelligent semantic code search with find-similar-code, recency ranking, and improved chunking. Fork of smart-coding-mcp.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
package/search-configs.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { loadConfig } from './lib/config.js';
|
|
2
|
-
import { EmbeddingsCache } from './lib/cache.js';
|
|
3
|
-
import { HybridSearch } from './features/hybrid-search.js';
|
|
4
|
-
import { pipeline, env } from '@huggingface/transformers';
|
|
5
|
-
|
|
6
|
-
// Force same thread config as server
|
|
7
|
-
if (env?.backends?.onnx) {
|
|
8
|
-
env.backends.onnx.numThreads = 2;
|
|
9
|
-
if (env.backends.onnx.wasm) {
|
|
10
|
-
env.backends.onnx.wasm.numThreads = 2;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async function searchConfigs() {
|
|
15
|
-
const config = await loadConfig(process.cwd());
|
|
16
|
-
const cache = new EmbeddingsCache(config);
|
|
17
|
-
await cache.load();
|
|
18
|
-
|
|
19
|
-
const embedder = async (text) => {
|
|
20
|
-
const pipe = await pipeline('feature-extraction', config.embeddingModel, {
|
|
21
|
-
session_options: { numThreads: 2 },
|
|
22
|
-
dtype: 'fp32',
|
|
23
|
-
});
|
|
24
|
-
return pipe(text, { pooling: 'mean', normalize: true });
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const searcher = new HybridSearch(embedder, cache, config);
|
|
28
|
-
const { results } = await searcher.search('configuration files, config, settings');
|
|
29
|
-
|
|
30
|
-
console.info(JSON.stringify(results, null, 2));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
searchConfigs().catch((err) => {
|
|
34
|
-
console.error(err);
|
|
35
|
-
process.exit(1);
|
|
36
|
-
});
|