@softerist/heuristic-mcp 3.0.15 → 3.0.16

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 (49) hide show
  1. package/README.md +104 -104
  2. package/config.jsonc +173 -173
  3. package/features/ann-config.js +131 -0
  4. package/features/clear-cache.js +84 -0
  5. package/features/find-similar-code.js +291 -0
  6. package/features/hybrid-search.js +544 -0
  7. package/features/index-codebase.js +3268 -0
  8. package/features/lifecycle.js +1189 -0
  9. package/features/package-version.js +302 -0
  10. package/features/register.js +408 -0
  11. package/features/resources.js +156 -0
  12. package/features/set-workspace.js +265 -0
  13. package/index.js +96 -96
  14. package/lib/cache-ops.js +22 -22
  15. package/lib/cache-utils.js +565 -565
  16. package/lib/cache.js +1870 -1870
  17. package/lib/call-graph.js +396 -396
  18. package/lib/cli.js +1 -1
  19. package/lib/config.js +517 -517
  20. package/lib/constants.js +39 -39
  21. package/lib/embed-query-process.js +7 -7
  22. package/lib/embedding-process.js +7 -7
  23. package/lib/embedding-worker.js +299 -299
  24. package/lib/ignore-patterns.js +316 -316
  25. package/lib/json-worker.js +14 -14
  26. package/lib/json-writer.js +337 -337
  27. package/lib/logging.js +164 -164
  28. package/lib/memory-logger.js +13 -13
  29. package/lib/onnx-backend.js +193 -193
  30. package/lib/project-detector.js +84 -84
  31. package/lib/server-lifecycle.js +165 -165
  32. package/lib/settings-editor.js +754 -754
  33. package/lib/tokenizer.js +256 -256
  34. package/lib/utils.js +428 -428
  35. package/lib/vector-store-binary.js +627 -627
  36. package/lib/vector-store-sqlite.js +95 -95
  37. package/lib/workspace-env.js +28 -28
  38. package/mcp_config.json +9 -9
  39. package/package.json +86 -75
  40. package/scripts/clear-cache.js +20 -0
  41. package/scripts/download-model.js +43 -0
  42. package/scripts/mcp-launcher.js +49 -0
  43. package/scripts/postinstall.js +12 -0
  44. package/search-configs.js +36 -36
  45. package/.prettierrc +0 -7
  46. package/debug-pids.js +0 -30
  47. package/eslint.config.js +0 -36
  48. package/specs/plan.md +0 -23
  49. package/vitest.config.js +0 -39
@@ -224,18 +224,18 @@ export class SqliteVectorStore {
224
224
  view.content = row.content;
225
225
  }
226
226
 
227
- if (includeVector && row.vector) {
228
- const expectedBytes = this.dim * Float32Array.BYTES_PER_ELEMENT;
229
- if (row.vector.byteLength >= expectedBytes) {
230
- // Copy the buffer to avoid issues with SQLite reusing internal buffers
231
- const bufferView = new Float32Array(
232
- row.vector.buffer,
233
- row.vector.byteOffset,
234
- this.dim
235
- );
236
- view.vector = new Float32Array(bufferView);
237
- }
238
- }
227
+ if (includeVector && row.vector) {
228
+ const expectedBytes = this.dim * Float32Array.BYTES_PER_ELEMENT;
229
+ if (row.vector.byteLength >= expectedBytes) {
230
+ // Copy the buffer to avoid issues with SQLite reusing internal buffers
231
+ const bufferView = new Float32Array(
232
+ row.vector.buffer,
233
+ row.vector.byteOffset,
234
+ this.dim
235
+ );
236
+ view.vector = new Float32Array(bufferView);
237
+ }
238
+ }
239
239
 
240
240
  views.push(view);
241
241
  }
@@ -264,7 +264,7 @@ export class SqliteVectorStore {
264
264
  * @param {Array} chunks - Array of chunk objects with vector, file, startLine, endLine, content
265
265
  * @param {Object} options - { getContent, preRename }
266
266
  */
267
- static async write(cacheDir, chunks, { getContent, getVector, preRename } = {}) {
267
+ static async write(cacheDir, chunks, { getContent, getVector, preRename } = {}) {
268
268
  if (!chunks || chunks.length === 0) {
269
269
  return null;
270
270
  }
@@ -286,10 +286,10 @@ export class SqliteVectorStore {
286
286
  denseSourceIndices.push(i);
287
287
  }
288
288
 
289
- const resolveContent = async (chunk, sourceIndex) => {
290
- if (chunk.content !== undefined && chunk.content !== null) {
291
- return chunk.content;
292
- }
289
+ const resolveContent = async (chunk, sourceIndex) => {
290
+ if (chunk.content !== undefined && chunk.content !== null) {
291
+ return chunk.content;
292
+ }
293
293
  if (typeof getContent === 'function') {
294
294
  const value = getContent(chunk, sourceIndex);
295
295
  if (value && typeof value.then === 'function') {
@@ -297,39 +297,39 @@ export class SqliteVectorStore {
297
297
  }
298
298
  return value;
299
299
  }
300
- return null;
301
- };
302
-
303
- const resolveVector = async (chunk, sourceIndex) => {
304
- let vectorSource = chunk.vector;
305
- if (
306
- (vectorSource === undefined || vectorSource === null) &&
307
- typeof getVector === 'function'
308
- ) {
309
- vectorSource = getVector(chunk, sourceIndex);
310
- if (vectorSource && typeof vectorSource.then === 'function') {
311
- vectorSource = await vectorSource;
312
- }
313
- }
314
- if (vectorSource === undefined || vectorSource === null) {
315
- throw new Error(`Missing vector data for sqlite cache write at index ${sourceIndex}`);
316
- }
317
- const vector =
318
- vectorSource instanceof Float32Array
319
- ? vectorSource
320
- : ArrayBuffer.isView(vectorSource)
321
- ? Float32Array.from(vectorSource)
322
- : Float32Array.from(vectorSource);
323
- if (!vector || vector.length === 0) {
324
- throw new Error(`Empty vector data for sqlite cache write at index ${sourceIndex}`);
325
- }
326
- return vector;
327
- };
328
-
329
- const dim =
330
- denseChunks.length > 0
331
- ? (await resolveVector(denseChunks[0], denseSourceIndices[0])).length
332
- : 0;
300
+ return null;
301
+ };
302
+
303
+ const resolveVector = async (chunk, sourceIndex) => {
304
+ let vectorSource = chunk.vector;
305
+ if (
306
+ (vectorSource === undefined || vectorSource === null) &&
307
+ typeof getVector === 'function'
308
+ ) {
309
+ vectorSource = getVector(chunk, sourceIndex);
310
+ if (vectorSource && typeof vectorSource.then === 'function') {
311
+ vectorSource = await vectorSource;
312
+ }
313
+ }
314
+ if (vectorSource === undefined || vectorSource === null) {
315
+ throw new Error(`Missing vector data for sqlite cache write at index ${sourceIndex}`);
316
+ }
317
+ const vector =
318
+ vectorSource instanceof Float32Array
319
+ ? vectorSource
320
+ : ArrayBuffer.isView(vectorSource)
321
+ ? Float32Array.from(vectorSource)
322
+ : Float32Array.from(vectorSource);
323
+ if (!vector || vector.length === 0) {
324
+ throw new Error(`Empty vector data for sqlite cache write at index ${sourceIndex}`);
325
+ }
326
+ return vector;
327
+ };
328
+
329
+ const dim =
330
+ denseChunks.length > 0
331
+ ? (await resolveVector(denseChunks[0], denseSourceIndices[0])).length
332
+ : 0;
333
333
 
334
334
  // Create new database
335
335
  const db = new Database(writePath);
@@ -364,51 +364,51 @@ export class SqliteVectorStore {
364
364
  CREATE INDEX idx_chunks_file ON chunks(file);
365
365
  `);
366
366
 
367
- // Insert metadata
368
- const insertMeta = db.prepare(`INSERT INTO metadata (key, value) VALUES (?, ?)`);
369
- insertMeta.run('version', String(STORE_VERSION));
370
- insertMeta.run('dim', String(dim));
371
- insertMeta.run('count', String(denseChunks.length));
372
- insertMeta.run('createdAt', new Date().toISOString());
373
-
374
- // Insert chunks in a transaction for speed without pre-materializing all vectors/content.
375
- const insertChunk = db.prepare(`
376
- INSERT INTO chunks (id, file, startLine, endLine, content, vector)
377
- VALUES (?, ?, ?, ?, ?, ?)
378
- `);
379
-
380
- db.exec('BEGIN');
381
- try {
382
- for (let i = 0; i < denseChunks.length; i += 1) {
383
- const chunk = denseChunks[i];
384
- const sourceIndex = denseSourceIndices[i];
385
- const vector = await resolveVector(chunk, sourceIndex);
386
- if (vector.length !== dim) {
387
- throw new Error('Vector dimension mismatch in sqlite cache write');
388
- }
389
- let content = await resolveContent(chunk, sourceIndex);
390
- if (content === undefined) content = null;
391
- if (content !== null && typeof content !== 'string') {
392
- content = String(content);
393
- }
394
- insertChunk.run(
395
- i,
396
- chunk.file,
397
- chunk.startLine ?? 0,
398
- chunk.endLine ?? 0,
399
- content,
400
- Buffer.from(vector.buffer, vector.byteOffset, vector.byteLength)
401
- );
402
- }
403
- db.exec('COMMIT');
404
- } catch (error) {
405
- try {
406
- db.exec('ROLLBACK');
407
- } catch {
408
- // ignore rollback errors
409
- }
410
- throw error;
411
- }
367
+ // Insert metadata
368
+ const insertMeta = db.prepare(`INSERT INTO metadata (key, value) VALUES (?, ?)`);
369
+ insertMeta.run('version', String(STORE_VERSION));
370
+ insertMeta.run('dim', String(dim));
371
+ insertMeta.run('count', String(denseChunks.length));
372
+ insertMeta.run('createdAt', new Date().toISOString());
373
+
374
+ // Insert chunks in a transaction for speed without pre-materializing all vectors/content.
375
+ const insertChunk = db.prepare(`
376
+ INSERT INTO chunks (id, file, startLine, endLine, content, vector)
377
+ VALUES (?, ?, ?, ?, ?, ?)
378
+ `);
379
+
380
+ db.exec('BEGIN');
381
+ try {
382
+ for (let i = 0; i < denseChunks.length; i += 1) {
383
+ const chunk = denseChunks[i];
384
+ const sourceIndex = denseSourceIndices[i];
385
+ const vector = await resolveVector(chunk, sourceIndex);
386
+ if (vector.length !== dim) {
387
+ throw new Error('Vector dimension mismatch in sqlite cache write');
388
+ }
389
+ let content = await resolveContent(chunk, sourceIndex);
390
+ if (content === undefined) content = null;
391
+ if (content !== null && typeof content !== 'string') {
392
+ content = String(content);
393
+ }
394
+ insertChunk.run(
395
+ i,
396
+ chunk.file,
397
+ chunk.startLine ?? 0,
398
+ chunk.endLine ?? 0,
399
+ content,
400
+ Buffer.from(vector.buffer, vector.byteOffset, vector.byteLength)
401
+ );
402
+ }
403
+ db.exec('COMMIT');
404
+ } catch (error) {
405
+ try {
406
+ db.exec('ROLLBACK');
407
+ } catch {
408
+ // ignore rollback errors
409
+ }
410
+ throw error;
411
+ }
412
412
 
413
413
  // Optimize the database
414
414
  db.exec('ANALYZE');
@@ -1,28 +1,28 @@
1
- import {
2
- DYNAMIC_WORKSPACE_ENV_PREFIX,
3
- WORKSPACE_ENV_KEY_PATTERN,
4
- WORKSPACE_ENV_VARS,
5
- } from './constants.js';
6
-
7
- export function scoreWorkspaceEnvKey(key) {
8
- const upper = String(key || '').toUpperCase();
9
- let score = 0;
10
- if (upper.includes('WORKSPACE')) score += 8;
11
- if (upper.includes('PROJECT')) score += 4;
12
- if (upper.includes('ROOT')) score += 3;
13
- if (upper.includes('CWD')) score += 2;
14
- if (upper.includes('DIR')) score += 1;
15
- return score;
16
- }
17
-
18
- export function getDynamicWorkspaceEnvKeys(env = process.env) {
19
- return Object.keys(env)
20
- .filter((key) => key.startsWith(DYNAMIC_WORKSPACE_ENV_PREFIX))
21
- .filter((key) => WORKSPACE_ENV_KEY_PATTERN.test(key))
22
- .filter((key) => !WORKSPACE_ENV_VARS.includes(key))
23
- .sort((a, b) => scoreWorkspaceEnvKey(b) - scoreWorkspaceEnvKey(a));
24
- }
25
-
26
- export function getWorkspaceEnvKeys(env = process.env) {
27
- return [...WORKSPACE_ENV_VARS, ...getDynamicWorkspaceEnvKeys(env)];
28
- }
1
+ import {
2
+ DYNAMIC_WORKSPACE_ENV_PREFIX,
3
+ WORKSPACE_ENV_KEY_PATTERN,
4
+ WORKSPACE_ENV_VARS,
5
+ } from './constants.js';
6
+
7
+ export function scoreWorkspaceEnvKey(key) {
8
+ const upper = String(key || '').toUpperCase();
9
+ let score = 0;
10
+ if (upper.includes('WORKSPACE')) score += 8;
11
+ if (upper.includes('PROJECT')) score += 4;
12
+ if (upper.includes('ROOT')) score += 3;
13
+ if (upper.includes('CWD')) score += 2;
14
+ if (upper.includes('DIR')) score += 1;
15
+ return score;
16
+ }
17
+
18
+ export function getDynamicWorkspaceEnvKeys(env = process.env) {
19
+ return Object.keys(env)
20
+ .filter((key) => key.startsWith(DYNAMIC_WORKSPACE_ENV_PREFIX))
21
+ .filter((key) => WORKSPACE_ENV_KEY_PATTERN.test(key))
22
+ .filter((key) => !WORKSPACE_ENV_VARS.includes(key))
23
+ .sort((a, b) => scoreWorkspaceEnvKey(b) - scoreWorkspaceEnvKey(a));
24
+ }
25
+
26
+ export function getWorkspaceEnvKeys(env = process.env) {
27
+ return [...WORKSPACE_ENV_VARS, ...getDynamicWorkspaceEnvKeys(env)];
28
+ }
package/mcp_config.json CHANGED
@@ -1,9 +1,9 @@
1
- {
2
- "mcpServers": {
3
- "heuristic-mcp": {
4
- "command": "node",
5
- "args": ["scripts\\mcp-launcher.js"],
6
- "disabled": false
7
- }
8
- }
9
- }
1
+ {
2
+ "mcpServers": {
3
+ "heuristic-mcp": {
4
+ "command": "node",
5
+ "args": ["scripts\\mcp-launcher.js"],
6
+ "disabled": false
7
+ }
8
+ }
9
+ }
package/package.json CHANGED
@@ -1,75 +1,86 @@
1
- {
2
- "name": "@softerist/heuristic-mcp",
3
- "version": "3.0.15",
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
- "type": "module",
6
- "main": "index.js",
7
- "bin": {
8
- "heuristic-mcp": "index.js"
9
- },
10
- "scripts": {
11
- "start": "node --expose-gc index.js",
12
- "dev": "node --expose-gc --watch index.js",
13
- "test": "vitest run",
14
- "test:watch": "vitest",
15
- "clean": "node scripts/clear-cache.js",
16
- "lint": "eslint .",
17
- "format": "prettier --write .",
18
- "postinstall": "node scripts/postinstall.js && node scripts/download-model.js"
19
- },
20
- "keywords": [
21
- "mcp",
22
- "semantic-search",
23
- "code-search",
24
- "embeddings",
25
- "ai",
26
- "model-context-protocol",
27
- "hybrid-search",
28
- "code-intelligence",
29
- "cursor",
30
- "vscode",
31
- "claude",
32
- "codex",
33
- "openai",
34
- "gemini",
35
- "anthropic",
36
- "antigravity",
37
- "heuristic"
38
- ],
39
- "author": {
40
- "name": "Softerist",
41
- "url": "https://github.com/softerist"
42
- },
43
- "repository": {
44
- "type": "git",
45
- "url": "git+https://github.com/softerist/heuristic-mcp.git"
46
- },
47
- "homepage": "https://github.com/softerist/heuristic-mcp#readme",
48
- "license": "MIT",
49
- "dependencies": {
50
- "@huggingface/transformers": "^3.8.1",
51
- "@modelcontextprotocol/sdk": "^1.0.4",
52
- "better-sqlite3": "^12.6.2",
53
- "chokidar": "^3.5.3",
54
- "fdir": "^6.5.0",
55
- "ignore": "^7.0.5",
56
- "punycode": "^2.3.1"
57
- },
58
- "optionalDependencies": {
59
- "hnswlib-node": "^3.0.0"
60
- },
61
- "engines": {
62
- "node": ">=18.0.0"
63
- },
64
- "overrides": {
65
- "punycode": "^2.3.1"
66
- },
67
- "devDependencies": {
68
- "@eslint/js": "^9.39.2",
69
- "@vitest/coverage-v8": "^4.0.18",
70
- "eslint": "^9.39.2",
71
- "globals": "^17.1.0",
72
- "prettier": "^3.8.1",
73
- "vitest": "^4.0.16"
74
- }
75
- }
1
+ {
2
+ "name": "@softerist/heuristic-mcp",
3
+ "version": "3.0.16",
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
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "heuristic-mcp": "index.js"
9
+ },
10
+ "files": [
11
+ "index.js",
12
+ "config.jsonc",
13
+ "mcp_config.json",
14
+ "search-configs.js",
15
+ "lib/",
16
+ "features/",
17
+ "scripts/",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "scripts": {
22
+ "start": "node --expose-gc index.js",
23
+ "dev": "node --expose-gc --watch index.js",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "clean": "node scripts/clear-cache.js",
27
+ "lint": "eslint .",
28
+ "format": "prettier --write .",
29
+ "postinstall": "node scripts/postinstall.js && node scripts/download-model.js"
30
+ },
31
+ "keywords": [
32
+ "mcp",
33
+ "semantic-search",
34
+ "code-search",
35
+ "embeddings",
36
+ "ai",
37
+ "model-context-protocol",
38
+ "hybrid-search",
39
+ "code-intelligence",
40
+ "cursor",
41
+ "vscode",
42
+ "claude",
43
+ "codex",
44
+ "openai",
45
+ "gemini",
46
+ "anthropic",
47
+ "antigravity",
48
+ "heuristic"
49
+ ],
50
+ "author": {
51
+ "name": "Softerist",
52
+ "url": "https://github.com/softerist"
53
+ },
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "git+https://github.com/softerist/heuristic-mcp.git"
57
+ },
58
+ "homepage": "https://github.com/softerist/heuristic-mcp#readme",
59
+ "license": "MIT",
60
+ "dependencies": {
61
+ "@huggingface/transformers": "^3.8.1",
62
+ "@modelcontextprotocol/sdk": "^1.0.4",
63
+ "better-sqlite3": "^12.6.2",
64
+ "chokidar": "^3.5.3",
65
+ "fdir": "^6.5.0",
66
+ "ignore": "^7.0.5",
67
+ "punycode": "^2.3.1"
68
+ },
69
+ "optionalDependencies": {
70
+ "hnswlib-node": "^3.0.0"
71
+ },
72
+ "engines": {
73
+ "node": ">=18.0.0"
74
+ },
75
+ "overrides": {
76
+ "punycode": "^2.3.1"
77
+ },
78
+ "devDependencies": {
79
+ "@eslint/js": "^9.39.2",
80
+ "@vitest/coverage-v8": "^4.0.18",
81
+ "eslint": "^9.39.2",
82
+ "globals": "^17.1.0",
83
+ "prettier": "^3.8.1",
84
+ "vitest": "^4.0.16"
85
+ }
86
+ }
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs/promises';
3
+ import { loadConfig } from '../lib/config.js';
4
+
5
+ async function clearCache() {
6
+ try {
7
+ const config = await loadConfig(process.cwd());
8
+ const cacheDir = config.cacheDirectory;
9
+
10
+ // Remove cache directory
11
+ await fs.rm(cacheDir, { recursive: true, force: true });
12
+ console.info(`Cache cleared successfully: ${cacheDir}`);
13
+ console.info('Next startup will perform a full reindex.');
14
+ } catch (error) {
15
+ console.error(`Error clearing cache: ${error.message}`);
16
+ process.exit(1);
17
+ }
18
+ }
19
+
20
+ clearCache();
@@ -0,0 +1,43 @@
1
+ import path from 'path';
2
+
3
+ import { getGlobalCacheDir } from '../lib/config.js';
4
+
5
+ async function downloadModel() {
6
+ const globalCacheDir = path.join(getGlobalCacheDir(), 'xenova');
7
+
8
+ try {
9
+ const transformers = await import('@huggingface/transformers');
10
+ const { pipeline, env } = transformers;
11
+
12
+ // Force cache directory to global location
13
+ env.cacheDir = globalCacheDir;
14
+
15
+ console.info(`[Model Setup] Pre-caching model to: ${globalCacheDir}`);
16
+ // Check if network is available by pinging HF (simple check)
17
+ // Actually, pipeline() will fail fast if network is down
18
+ console.info(`[Model Setup] Downloading 'jinaai/jina-embeddings-v2-base-code'...`);
19
+
20
+ // This will download the model to the cache directory
21
+ await pipeline('feature-extraction', 'jinaai/jina-embeddings-v2-base-code');
22
+
23
+ console.info(`[Model Setup] ✅ Model cached successfully!`);
24
+ } catch (error) {
25
+ if (error && error.code === 'ERR_MODULE_NOT_FOUND') {
26
+ console.warn(
27
+ '[Model Setup] ⚠️ Transformers not available yet; skipping model pre-download.'
28
+ );
29
+ console.warn(
30
+ '[Model Setup] This is okay! The server will attempt to download it when started.'
31
+ );
32
+ return;
33
+ }
34
+ console.warn(`[Model Setup] ⚠️ Constructive warning: Failed to pre-download model.`);
35
+ console.warn(
36
+ '[Model Setup] This is okay! The server will attempt to download it when started.'
37
+ );
38
+ console.warn(`[Model Setup] Error details: ${error.message}`);
39
+ // Don't fail the install, just warn
40
+ }
41
+ }
42
+
43
+ downloadModel();
@@ -0,0 +1,49 @@
1
+ import path from 'node:path';
2
+ import { spawn } from 'node:child_process';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { getWorkspaceEnvKeys } from '../lib/workspace-env.js';
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const repoRoot = path.resolve(__dirname, '..');
8
+ const indexPath = path.join(repoRoot, 'index.js');
9
+
10
+ let workspace;
11
+ const passthrough = [];
12
+
13
+ function readWorkspaceFromEnv() {
14
+ for (const key of getWorkspaceEnvKeys()) {
15
+ const value = process.env[key];
16
+ if (!value || value.includes('${')) continue;
17
+ return value;
18
+ }
19
+ return null;
20
+ }
21
+
22
+ for (let i = 2; i < process.argv.length; i += 1) {
23
+ const arg = process.argv[i];
24
+ if (arg === '--workspace' && i + 1 < process.argv.length) {
25
+ workspace = process.argv[i + 1];
26
+ i += 1;
27
+ continue;
28
+ }
29
+ passthrough.push(arg);
30
+ }
31
+
32
+ if (!workspace) {
33
+ workspace = readWorkspaceFromEnv();
34
+ }
35
+
36
+ if (!workspace) {
37
+ workspace = process.cwd();
38
+ }
39
+
40
+ const args = ['--expose-gc', indexPath, '--workspace', workspace, ...passthrough];
41
+ const child = spawn(process.execPath, args, { stdio: 'inherit' });
42
+
43
+ child.on('exit', (code, signal) => {
44
+ if (signal) {
45
+ process.kill(process.pid, signal);
46
+ return;
47
+ }
48
+ process.exit(code ?? 1);
49
+ });
@@ -0,0 +1,12 @@
1
+ import { register } from '../features/register.js';
2
+
3
+ // Run the registration process - MUST await to ensure file writes complete
4
+ console.info('[PostInstall] Running Heuristic MCP registration...');
5
+
6
+ try {
7
+ await register();
8
+ console.info('[PostInstall] Registration complete.');
9
+ } catch (err) {
10
+ console.error('[PostInstall] Registration failed:', err.message);
11
+ // Don't fail the install if registration fails, just warn
12
+ }
package/search-configs.js CHANGED
@@ -1,36 +1,36 @@
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
- });
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
+ });