@softerist/heuristic-mcp 3.0.3 → 3.0.6

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 (96) hide show
  1. package/.agent/workflows/code-review.md +14 -3
  2. package/LICENSE +1 -1
  3. package/config.jsonc +4 -4
  4. package/debug-pids.js +26 -23
  5. package/features/find-similar-code.js +20 -16
  6. package/features/hybrid-search.js +197 -187
  7. package/features/index-codebase.js +2610 -2554
  8. package/features/lifecycle.js +74 -58
  9. package/features/register.js +3 -1
  10. package/index.js +531 -516
  11. package/lib/cache-utils.js +1 -3
  12. package/lib/cache.js +1474 -1456
  13. package/lib/call-graph.js +1 -1
  14. package/lib/config.js +789 -797
  15. package/lib/embedding-process.js +35 -24
  16. package/lib/embedding-worker.js +734 -684
  17. package/lib/json-writer.js +14 -21
  18. package/lib/logging.js +4 -2
  19. package/lib/onnx-backend.js +14 -8
  20. package/lib/settings-editor.js +2 -9
  21. package/lib/tokenizer.js +87 -85
  22. package/lib/utils.js +7 -6
  23. package/lib/vector-store-binary.js +615 -612
  24. package/mcp_config.json +9 -0
  25. package/package.json +1 -1
  26. package/scripts/mcp-launcher.js +35 -0
  27. package/search-configs.js +6 -6
  28. package/test/ann-config.test.js +0 -1
  29. package/test/ann-fallback.test.js +0 -1
  30. package/test/binary-store.test.js +0 -1
  31. package/test/cache-branches.test.js +0 -1
  32. package/test/cache-errors.test.js +7 -4
  33. package/test/cache-extra.test.js +6 -5
  34. package/test/cache-helpers.test.js +0 -1
  35. package/test/cache-hnsw-failure.test.js +0 -1
  36. package/test/cache-json-worker.test.js +1 -2
  37. package/test/cache-worker.test.js +104 -103
  38. package/test/cache.test.js +15 -16
  39. package/test/call-graph.test.js +0 -1
  40. package/test/clear-cache.test.js +0 -1
  41. package/test/code-review-workflow.test.js +0 -1
  42. package/test/config.test.js +0 -1
  43. package/test/coverage-gap.test.js +0 -1
  44. package/test/coverage-maximizer.test.js +3 -2
  45. package/test/debug-analysis.js +106 -108
  46. package/test/embedding-model.test.js +27 -16
  47. package/test/embedding-worker-extra.test.js +42 -39
  48. package/test/embedding-worker.test.js +3 -4
  49. package/test/features.test.js +3 -2
  50. package/test/final-boost.test.js +281 -272
  51. package/test/final-polish.test.js +9 -4
  52. package/test/final.test.js +0 -1
  53. package/test/find-similar-code.test.js +3 -2
  54. package/test/fixtures/mcp-workspace/config.jsonc +12 -0
  55. package/test/fixtures/mcp-workspace/example.js +8 -0
  56. package/test/helpers.js +0 -1
  57. package/test/helpers.test.js +0 -1
  58. package/test/hybrid-search-basic.test.js +9 -10
  59. package/test/hybrid-search-branch.test.js +176 -178
  60. package/test/hybrid-search-callgraph.test.js +27 -27
  61. package/test/hybrid-search-extra.test.js +0 -1
  62. package/test/hybrid-search.test.js +0 -1
  63. package/test/index-cli.test.js +13 -6
  64. package/test/index-codebase-batch.test.js +1 -4
  65. package/test/index-codebase-branches.test.js +575 -582
  66. package/test/index-codebase-core.test.js +1039 -1033
  67. package/test/index-codebase-edge-cases.test.js +250 -254
  68. package/test/index-codebase-errors.test.js +0 -1
  69. package/test/index-codebase-gap.test.js +244 -233
  70. package/test/index-codebase-lines.test.js +0 -1
  71. package/test/index-codebase-watcher.test.js +369 -368
  72. package/test/index-codebase-zone.test.js +154 -153
  73. package/test/index-codebase.test.js +0 -1
  74. package/test/index-memory.test.js +195 -185
  75. package/test/indexer-detailed.test.js +0 -1
  76. package/test/integration.test.js +0 -1
  77. package/test/json-worker.test.js +0 -1
  78. package/test/lifecycle.test.js +7 -6
  79. package/test/master.test.js +0 -1
  80. package/test/mcp-search.test.js +78 -0
  81. package/test/perfection.test.js +0 -1
  82. package/test/project-detector.test.js +0 -1
  83. package/test/register.test.js +0 -1
  84. package/test/stress.js +19530 -18955
  85. package/test/tokenizer.test.js +0 -1
  86. package/test/ultra-maximizer.test.js +0 -1
  87. package/test/utils-branches.test.js +160 -162
  88. package/test/utils-extra.test.js +51 -52
  89. package/test/utils.test.js +0 -1
  90. package/test/verify_fixes.js +78 -77
  91. package/test/worker-errors.test.js +3 -2
  92. package/test/worker-init.test.js +0 -1
  93. package/test/worker_throttling.test.js +91 -94
  94. package/tools/scripts/cache-stats.js +1 -1
  95. package/tools/scripts/manual-search.js +70 -34
  96. package/mcp_config.example.json +0 -13
@@ -7,6 +7,7 @@ last_updated: 2026-01-29
7
7
  You are a senior software engineer and code reviewer. Review the code provided according to the following strict guidelines.
8
8
 
9
9
  ## 1. Review Scope & Context
10
+
10
11
  - **For code <100 lines**: Quick review focusing on correctness and obvious bugs.
11
12
  - **For code 100-500 lines**: Standard review following all sections below.
12
13
  - **For code >500 lines or critical systems**: Deep review with extra emphasis on architecture, security, and edge cases.
@@ -14,46 +15,56 @@ You are a senior software engineer and code reviewer. Review the code provided a
14
15
  - **Domain-Specific Checks**: If the code domain is identifiable (e.g., web, mobile, embedded, ML, healthcare), apply relevant domain-specific standards (e.g., WCAG for web, PII handling for healthcare, real-time constraints for embedded).
15
16
 
16
17
  ## 2. Line-by-Line Review
18
+
17
19
  - Review every function and critical code path. For files >200 lines, focus on functions with issues rather than every line.
18
20
  - Group line-by-line findings by severity (**Critical** first), then by file/function within each severity tier.
19
21
  - For each issue, quote the relevant line(s).
20
22
  - **Confidence Ratings**: For ambiguous issues where context is missing, explicitly note `[Confidence: Low/Medium/High]` and explain what additional information would clarify the finding.
21
23
 
22
24
  ## 3. High-Level Review
25
+
23
26
  - Focus on system-level patterns not visible at function scope: module organization, layer violations, missing abstraction layers, deployment concerns.
24
27
  - Do not check for issues already covered in line-by-line (avoid redundancy).
25
28
 
26
29
  ## 4. Follow-up Reviews
30
+
27
31
  - For follow-up reviews, focus on: regression verification, new code introduced by fixes, and cross-cutting impact of changes.
28
32
 
29
33
  ## 5. Stalled/Incomplete Logic
34
+
30
35
  - Check for "forgotten error paths": places where exceptions/errors could occur but aren't caught, or catch blocks that are empty/only log without recovery strategy.
31
36
  - Verify TODOs or placeholders.
32
37
 
33
38
  ## 6. Consistency
39
+
34
40
  - Identify the dominant pattern in the codebase and flag deviations. If no clear majority, note the inconsistency itself as an issue.
35
41
  - Check naming conventions, coding style, and file structure.
36
42
 
37
43
  ## 7. Fix Plan
44
+
38
45
  Provide a prioritized checklist (most critical first):
46
+
39
47
  - **Estimated effort per item** using this scale:
40
- * **S (Small)**: <2 hours, isolated change, no breaking changes.
41
- * **M (Medium)**: 2-8 hours, may affect multiple files, local refactoring.
42
- * **L (Large)**: >8 hours, architectural changes, breaking changes, or requires team coordination.
48
+ - **S (Small)**: <2 hours, isolated change, no breaking changes.
49
+ - **M (Medium)**: 2-8 hours, may affect multiple files, local refactoring.
50
+ - **L (Large)**: >8 hours, architectural changes, breaking changes, or requires team coordination.
43
51
  - For each item, note any dependencies: "Requires #N" if another fix must be completed first.
44
52
  - Group independent fixes together to enable parallel work.
45
53
 
46
54
  ## 8. Patch
55
+
47
56
  - Propose concrete code edits in **unified diff format** for **ALL critical severity issues**.
48
57
  - For **high severity** issues, provide patches for the top 5 most impactful.
49
58
  - For new files or large refactors (>50 lines changed), provide complete code blocks with clear before/after markers.
50
59
 
51
60
  ## 9. Tests
61
+
52
62
  - Separate **unit tests** (isolated, mocked dependencies) from **integration tests** (real dependencies). Specify which category each test belongs to.
53
63
  - List the exact tests you'd add (test names + what each asserts).
54
64
  - For performance issues, include benchmark or load tests with acceptable thresholds.
55
65
 
56
66
  ## Output Format Constraints
67
+
57
68
  - **Do not skip sections.** If a section has no findings, state "No issues found" and briefly explain why (e.g., "No concurrency issues: code is single-threaded").
58
69
  - **Assume production context**: Treat as a professional audit. If context is unclear, state assumptions (e.g., "assuming user-facing web application with moderate traffic").
59
70
  - **Be exhaustive and specific.** Do not be polite; be direct.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Omar Haris
3
+ Copyright (c) 2026 Omar Haris, softerist
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/config.jsonc CHANGED
@@ -563,7 +563,7 @@
563
563
  "gitattributes",
564
564
  "editorconfig",
565
565
  "npmrc",
566
- "yarnrc"
566
+ "yarnrc",
567
567
  ],
568
568
  // Specific filenames to include regardless of extension.
569
569
  "fileNames": [
@@ -612,7 +612,7 @@
612
612
  "docker-compose.yml",
613
613
  "docker-compose.yaml",
614
614
  "makefile.am",
615
- "makefile.in"
615
+ "makefile.in",
616
616
  ],
617
617
  // Glob patterns to exclude from indexing.
618
618
  "excludePatterns": [
@@ -624,7 +624,7 @@
624
624
  "**/.next/**",
625
625
  "**/target/**",
626
626
  "**/vendor/**",
627
- "**/.smart-coding-cache/**"
627
+ "**/.smart-coding-cache/**",
628
628
  ],
629
629
  // Enable project-type detection + smart ignore patterns.
630
630
  "smartIndexing": true,
@@ -719,5 +719,5 @@
719
719
  // Persist ANN index to disk.
720
720
  "annIndexCache": true,
721
721
  // ANN distance metric.
722
- "annMetric": "cosine"
722
+ "annMetric": "cosine",
723
723
  }
package/debug-pids.js CHANGED
@@ -1,27 +1,30 @@
1
- import { exec } from 'child_process';
2
- import util from 'util';
3
-
4
- const execPromise = util.promisify(exec);
5
-
6
- async function check() {
1
+ import { exec } from 'child_process';
2
+ import util from 'util';
3
+
4
+ const execPromise = util.promisify(exec);
5
+
6
+ async function check() {
7
7
  console.info('Checking processes...');
8
- try {
9
- const { stdout } = await execPromise(
10
- `powershell -NoProfile -Command "Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'node.exe' } | Select-Object ProcessId, CommandLine, ParentProcessId | ConvertTo-Json"`
11
- );
12
- const processes = JSON.parse(stdout);
13
- const list = Array.isArray(processes) ? processes : [processes];
14
-
15
- for (const p of list) {
16
- if (p.CommandLine && (p.CommandLine.includes('heuristic-mcp') || p.CommandLine.includes('index.js'))) {
8
+ try {
9
+ const { stdout } = await execPromise(
10
+ `powershell -NoProfile -Command "Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'node.exe' } | Select-Object ProcessId, CommandLine, ParentProcessId | ConvertTo-Json"`
11
+ );
12
+ const processes = JSON.parse(stdout);
13
+ const list = Array.isArray(processes) ? processes : [processes];
14
+
15
+ for (const p of list) {
16
+ if (
17
+ p.CommandLine &&
18
+ (p.CommandLine.includes('heuristic-mcp') || p.CommandLine.includes('index.js'))
19
+ ) {
17
20
  console.info(`PID: ${p.ProcessId}, Parent: ${p.ParentProcessId}`);
18
21
  console.info(`CMD: ${p.CommandLine}`);
19
22
  console.info('---');
20
- }
21
- }
22
- } catch (err) {
23
- console.error('Error:', err.message);
24
- }
25
- }
26
-
27
- check();
23
+ }
24
+ }
25
+ } catch (err) {
26
+ console.error('Error:', err.message);
27
+ }
28
+ }
29
+
30
+ check();
@@ -48,7 +48,7 @@ export class FindSimilarCode {
48
48
  // Check if input is too large and truncate intelligently
49
49
  const estimatedTokens = estimateTokens(code);
50
50
  const limit = getModelTokenLimit(this.config.embeddingModel);
51
-
51
+
52
52
  // If input is significantly larger than the model limit, we should chunk it
53
53
  if (estimatedTokens > limit) {
54
54
  // Use smartChunk to get a semantically valid first block
@@ -66,14 +66,16 @@ export class FindSimilarCode {
66
66
  pooling: 'mean',
67
67
  normalize: true,
68
68
  });
69
- const codeVector = codeEmbed.data; // Keep as Float32Array for performance
70
- const codeVectorTyped = codeVector;
69
+
70
+ // CRITICAL: Deep copy Float32Array to avoid detachment issues with WASM/Workers
71
+ // accessing a detached buffer from a reusable ONNX tensor can crash the process.
72
+ const codeVector = new Float32Array(codeEmbed.data);
71
73
 
72
74
  let candidates = vectorStore;
73
75
  let usedAnn = false;
74
76
  if (this.config.annEnabled) {
75
77
  const candidateCount = this.getAnnCandidateCount(maxResults, vectorStore.length);
76
- const annLabels = await this.cache.queryAnn(codeVectorTyped, candidateCount);
78
+ const annLabels = await this.cache.queryAnn(codeVector, candidateCount);
77
79
  if (annLabels && annLabels.length >= maxResults) {
78
80
  usedAnn = true;
79
81
  const seen = new Set();
@@ -88,27 +90,27 @@ export class FindSimilarCode {
88
90
  }
89
91
 
90
92
  const normalizedInput = codeToEmbed.trim().replace(/\s+/g, ' ');
91
-
93
+
92
94
  /**
93
95
  * Batch scoring function to prevent blocking the event loop
94
96
  */
95
97
  const scoreAndFilter = async (chunks) => {
96
98
  const BATCH_SIZE = 500;
97
99
  const scored = [];
98
-
100
+
99
101
  for (let i = 0; i < chunks.length; i += BATCH_SIZE) {
100
102
  const batch = chunks.slice(i, i + BATCH_SIZE);
101
-
103
+
102
104
  // Yield to event loop between batches
103
105
  if (i > 0) {
104
106
  await new Promise((resolve) => setTimeout(resolve, 0));
105
107
  }
106
-
108
+
107
109
  for (const chunk of batch) {
108
110
  const vector = this.getChunkVector(chunk);
109
111
  if (!vector) continue;
110
112
  const similarity = dotSimilarity(codeVector, vector);
111
-
113
+
112
114
  if (similarity >= minSimilarity) {
113
115
  // Deduplicate against input
114
116
  if (normalizedInput) {
@@ -116,17 +118,17 @@ export class FindSimilarCode {
116
118
  const normalizedChunk = content.trim().replace(/\s+/g, ' ');
117
119
  if (normalizedChunk === normalizedInput) continue;
118
120
  }
119
-
121
+
120
122
  scored.push({ ...chunk, similarity });
121
123
  }
122
124
  }
123
125
  }
124
-
126
+
125
127
  return scored.sort((a, b) => b.similarity - a.similarity);
126
128
  };
127
129
 
128
130
  let filteredResults = await scoreAndFilter(candidates);
129
-
131
+
130
132
  // Fallback to full scan if ANN didn't provide enough results
131
133
  // Optimization: Skip full scan on large codebases to avoid long pauses
132
134
  const MAX_FULL_SCAN_SIZE = 5000;
@@ -143,12 +145,14 @@ export class FindSimilarCode {
143
145
  return { ...chunk, content: await this.getChunkContent(chunk) };
144
146
  }
145
147
  return chunk;
146
- }),
148
+ })
147
149
  );
148
150
 
149
151
  return {
150
152
  results,
151
- message: warningMessage || (results.length === 0 ? 'No similar code found above the similarity threshold.' : null),
153
+ message:
154
+ warningMessage ||
155
+ (results.length === 0 ? 'No similar code found above the similarity threshold.' : null),
152
156
  };
153
157
  }
154
158
 
@@ -160,7 +164,7 @@ export class FindSimilarCode {
160
164
  const formatted = await Promise.all(
161
165
  results.map(async (r, idx) => {
162
166
  const relPath = path.relative(this.config.searchDirectory, r.file);
163
- const content = r.content ?? await this.getChunkContent(r);
167
+ const content = r.content ?? (await this.getChunkContent(r));
164
168
  return (
165
169
  `## Similar Code ${idx + 1} (Similarity: ${(r.similarity * 100).toFixed(1)}%)\n` +
166
170
  `**File:** \`${relPath}\`\n` +
@@ -172,7 +176,7 @@ export class FindSimilarCode {
172
176
  '\n' +
173
177
  '```\n'
174
178
  );
175
- }),
179
+ })
176
180
  );
177
181
 
178
182
  return formatted.join('\n');