@softerist/heuristic-mcp 3.2.3 → 3.2.5

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 (46) hide show
  1. package/README.md +387 -376
  2. package/config.jsonc +800 -800
  3. package/features/ann-config.js +102 -110
  4. package/features/clear-cache.js +81 -84
  5. package/features/find-similar-code.js +265 -286
  6. package/features/hybrid-search.js +487 -536
  7. package/features/index-codebase.js +3146 -3271
  8. package/features/lifecycle.js +1011 -1063
  9. package/features/package-version.js +277 -291
  10. package/features/register.js +351 -370
  11. package/features/resources.js +115 -130
  12. package/features/set-workspace.js +214 -240
  13. package/index.js +788 -781
  14. package/lib/cache-ops.js +22 -22
  15. package/lib/cache-utils.js +465 -519
  16. package/lib/cache.js +1749 -1849
  17. package/lib/call-graph.js +396 -396
  18. package/lib/cli.js +232 -226
  19. package/lib/config.js +1483 -1495
  20. package/lib/constants.js +511 -493
  21. package/lib/embed-query-process.js +206 -212
  22. package/lib/embedding-process.js +434 -451
  23. package/lib/embedding-worker.js +862 -934
  24. package/lib/ignore-patterns.js +276 -316
  25. package/lib/json-worker.js +14 -14
  26. package/lib/json-writer.js +302 -310
  27. package/lib/logging.js +133 -127
  28. package/lib/memory-logger.js +13 -13
  29. package/lib/onnx-backend.js +188 -193
  30. package/lib/path-utils.js +18 -23
  31. package/lib/project-detector.js +82 -84
  32. package/lib/server-lifecycle.js +164 -147
  33. package/lib/settings-editor.js +738 -739
  34. package/lib/slice-normalize.js +25 -31
  35. package/lib/tokenizer.js +168 -203
  36. package/lib/utils.js +364 -409
  37. package/lib/vector-store-binary.js +973 -991
  38. package/lib/vector-store-sqlite.js +377 -414
  39. package/lib/workspace-env.js +32 -34
  40. package/mcp_config.json +9 -9
  41. package/package.json +86 -86
  42. package/scripts/clear-cache.js +20 -20
  43. package/scripts/download-model.js +43 -43
  44. package/scripts/mcp-launcher.js +49 -49
  45. package/scripts/postinstall.js +12 -12
  46. package/search-configs.js +36 -36
@@ -1,130 +1,115 @@
1
-
2
-
3
- import fs from 'fs/promises';
4
- import path from 'path';
5
- import { fdir } from 'fdir';
6
- import { getMimeType } from '../lib/constants.js';
7
-
8
-
9
- function pathToUri(filePath) {
10
-
11
- const normalized = filePath.replace(/\\/g, '/');
12
-
13
- if (/^[a-zA-Z]:/.test(normalized)) {
14
- return `file:///${normalized}`;
15
- }
16
- return `file://${normalized}`;
17
- }
18
-
19
-
20
- function uriToPath(uri) {
21
- if (!uri.startsWith('file://')) {
22
- throw new Error(`Invalid file URI: ${uri}`);
23
- }
24
- let filePath = uri.slice(7);
25
-
26
- if (/^\/[a-zA-Z]:/.test(filePath)) {
27
- filePath = filePath.slice(1);
28
- }
29
-
30
- filePath = decodeURIComponent(filePath);
31
-
32
- if (process.platform === 'win32') {
33
- filePath = filePath.replace(/\//g, '\\');
34
- }
35
- return filePath;
36
- }
37
-
38
-
39
- function isWithinWorkspace(filePath, workspaceDir) {
40
- const resolvedPath = path.resolve(filePath);
41
- const resolvedWorkspace = path.resolve(workspaceDir);
42
- const relativePath = path.relative(resolvedWorkspace, resolvedPath);
43
- return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
44
- }
45
-
46
-
47
- export async function handleListResources(config) {
48
- const workspaceDir = config.searchDirectory;
49
- const maxResults = 500;
50
-
51
-
52
- const allowedExtensions = new Set(
53
- (config.fileExtensions || []).map(ext => `.${ext.toLowerCase()}`)
54
- );
55
-
56
-
57
- const excludedDirs = new Set();
58
- for (const pattern of config.excludePatterns || []) {
59
-
60
- const match = pattern.match(/(?:\*\*\/)?([^/*]+)(?:\/\*\*)?$/);
61
- if (match && match[1] && !match[1].includes('*')) {
62
- excludedDirs.add(match[1]);
63
- }
64
- }
65
-
66
- try {
67
-
68
- const crawler = new fdir()
69
- .withBasePath()
70
- .withMaxDepth(10)
71
- .exclude((dirName) => {
72
- return excludedDirs.has(dirName);
73
- })
74
- .filter((filePath) => {
75
- const ext = path.extname(filePath).toLowerCase();
76
- return allowedExtensions.has(ext);
77
- })
78
- .crawl(workspaceDir);
79
-
80
- const files = await crawler.withPromise();
81
- const limitedFiles = files.slice(0, maxResults);
82
-
83
- const resources = limitedFiles.map((filePath) => {
84
- const relativePath = path.relative(workspaceDir, filePath);
85
- return {
86
- uri: pathToUri(filePath),
87
- name: relativePath.replace(/\\/g, '/'),
88
- mimeType: getMimeType(path.extname(filePath)),
89
- };
90
- });
91
-
92
- return { resources };
93
- } catch (error) {
94
- console.error(`[Resources] Error listing resources: ${error.message}`);
95
- return { resources: [] };
96
- }
97
- }
98
-
99
-
100
- export async function handleReadResource(uri, config) {
101
- const workspaceDir = config.searchDirectory;
102
-
103
- try {
104
- const filePath = uriToPath(uri);
105
-
106
-
107
- if (!isWithinWorkspace(filePath, workspaceDir)) {
108
- throw new Error(`Access denied: ${uri} is outside workspace`);
109
- }
110
-
111
-
112
- await fs.access(filePath);
113
-
114
-
115
- const content = await fs.readFile(filePath, 'utf-8');
116
-
117
- return {
118
- contents: [
119
- {
120
- uri,
121
- mimeType: getMimeType(path.extname(filePath)),
122
- text: content,
123
- },
124
- ],
125
- };
126
- } catch (error) {
127
- console.error(`[Resources] Error reading resource ${uri}: ${error.message}`);
128
- throw error;
129
- }
130
- }
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { fdir } from 'fdir';
4
+ import { getMimeType } from '../lib/constants.js';
5
+
6
+ function pathToUri(filePath) {
7
+ const normalized = filePath.replace(/\\/g, '/');
8
+
9
+ if (/^[a-zA-Z]:/.test(normalized)) {
10
+ return `file:///${normalized}`;
11
+ }
12
+ return `file://${normalized}`;
13
+ }
14
+
15
+ function uriToPath(uri) {
16
+ if (!uri.startsWith('file://')) {
17
+ throw new Error(`Invalid file URI: ${uri}`);
18
+ }
19
+ let filePath = uri.slice(7);
20
+
21
+ if (/^\/[a-zA-Z]:/.test(filePath)) {
22
+ filePath = filePath.slice(1);
23
+ }
24
+
25
+ filePath = decodeURIComponent(filePath);
26
+
27
+ if (process.platform === 'win32') {
28
+ filePath = filePath.replace(/\//g, '\\');
29
+ }
30
+ return filePath;
31
+ }
32
+
33
+ function isWithinWorkspace(filePath, workspaceDir) {
34
+ const resolvedPath = path.resolve(filePath);
35
+ const resolvedWorkspace = path.resolve(workspaceDir);
36
+ const relativePath = path.relative(resolvedWorkspace, resolvedPath);
37
+ return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
38
+ }
39
+
40
+ export async function handleListResources(config) {
41
+ const workspaceDir = config.searchDirectory;
42
+ const maxResults = 500;
43
+
44
+ const allowedExtensions = new Set(
45
+ (config.fileExtensions || []).map((ext) => `.${ext.toLowerCase()}`)
46
+ );
47
+
48
+ const excludedDirs = new Set();
49
+ for (const pattern of config.excludePatterns || []) {
50
+ const match = pattern.match(/(?:\*\*\/)?([^/*]+)(?:\/\*\*)?$/);
51
+ if (match && match[1] && !match[1].includes('*')) {
52
+ excludedDirs.add(match[1]);
53
+ }
54
+ }
55
+
56
+ try {
57
+ const crawler = new fdir()
58
+ .withBasePath()
59
+ .withMaxDepth(10)
60
+ .exclude((dirName) => {
61
+ return excludedDirs.has(dirName);
62
+ })
63
+ .filter((filePath) => {
64
+ const ext = path.extname(filePath).toLowerCase();
65
+ return allowedExtensions.has(ext);
66
+ })
67
+ .crawl(workspaceDir);
68
+
69
+ const files = await crawler.withPromise();
70
+ const limitedFiles = files.slice(0, maxResults);
71
+
72
+ const resources = limitedFiles.map((filePath) => {
73
+ const relativePath = path.relative(workspaceDir, filePath);
74
+ return {
75
+ uri: pathToUri(filePath),
76
+ name: relativePath.replace(/\\/g, '/'),
77
+ mimeType: getMimeType(path.extname(filePath)),
78
+ };
79
+ });
80
+
81
+ return { resources };
82
+ } catch (error) {
83
+ console.error(`[Resources] Error listing resources: ${error.message}`);
84
+ return { resources: [] };
85
+ }
86
+ }
87
+
88
+ export async function handleReadResource(uri, config) {
89
+ const workspaceDir = config.searchDirectory;
90
+
91
+ try {
92
+ const filePath = uriToPath(uri);
93
+
94
+ if (!isWithinWorkspace(filePath, workspaceDir)) {
95
+ throw new Error(`Access denied: ${uri} is outside workspace`);
96
+ }
97
+
98
+ await fs.access(filePath);
99
+
100
+ const content = await fs.readFile(filePath, 'utf-8');
101
+
102
+ return {
103
+ contents: [
104
+ {
105
+ uri,
106
+ mimeType: getMimeType(path.extname(filePath)),
107
+ text: content,
108
+ },
109
+ ],
110
+ };
111
+ } catch (error) {
112
+ console.error(`[Resources] Error reading resource ${uri}: ${error.message}`);
113
+ throw error;
114
+ }
115
+ }