@softerist/heuristic-mcp 3.2.2 → 3.2.4

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 +3139 -3270
  8. package/features/lifecycle.js +1041 -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 +742 -762
  14. package/lib/cache-ops.js +22 -22
  15. package/lib/cache-utils.js +465 -519
  16. package/lib/cache.js +1699 -1767
  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 -492
  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 +116 -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 +133 -145
  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 +811 -591
  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
@@ -5,9 +5,7 @@ import {
5
5
  WORKSPACE_ENV_VARS,
6
6
  } from './constants.js';
7
7
 
8
- const EXCLUDED_DYNAMIC_WORKSPACE_ENV_KEYS = new Set([
9
- 'ANTIGRAVITY_EDITOR_APP_ROOT',
10
- ]);
8
+ const EXCLUDED_DYNAMIC_WORKSPACE_ENV_KEYS = new Set(['ANTIGRAVITY_EDITOR_APP_ROOT']);
11
9
 
12
10
  function isTruthy(value) {
13
11
  return /^(1|true|yes|on)$/i.test(String(value || '').trim());
@@ -21,20 +19,20 @@ export function isDynamicWorkspaceEnvEnabled(env = process.env, options = {}) {
21
19
  }
22
20
 
23
21
  export function scoreWorkspaceEnvKey(key) {
24
- const upper = String(key || '').toUpperCase();
25
- let score = 0;
26
- if (upper.includes('WORKSPACE')) score += 8;
27
- if (upper.includes('PROJECT')) score += 4;
28
- if (upper.includes('ROOT')) score += 3;
29
- if (upper.includes('CWD')) score += 2;
30
- if (upper.includes('DIR')) score += 1;
31
- return score;
32
- }
33
-
34
- function hasDynamicWorkspacePrefix(key) {
35
- return DYNAMIC_WORKSPACE_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));
36
- }
37
-
22
+ const upper = String(key || '').toUpperCase();
23
+ let score = 0;
24
+ if (upper.includes('WORKSPACE')) score += 8;
25
+ if (upper.includes('PROJECT')) score += 4;
26
+ if (upper.includes('ROOT')) score += 3;
27
+ if (upper.includes('CWD')) score += 2;
28
+ if (upper.includes('DIR')) score += 1;
29
+ return score;
30
+ }
31
+
32
+ function hasDynamicWorkspacePrefix(key) {
33
+ return DYNAMIC_WORKSPACE_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));
34
+ }
35
+
38
36
  export function getDynamicWorkspaceEnvKeys(env = process.env, options = {}) {
39
37
  if (!isDynamicWorkspaceEnvEnabled(env, options)) {
40
38
  return [];
@@ -43,27 +41,27 @@ export function getDynamicWorkspaceEnvKeys(env = process.env, options = {}) {
43
41
  return Object.keys(env)
44
42
  .filter((key) => !EXCLUDED_DYNAMIC_WORKSPACE_ENV_KEYS.has(String(key || '').toUpperCase()))
45
43
  .filter((key) => !WORKSPACE_ENV_VARS.includes(key))
46
- .filter((key) => {
47
- const providerSpecific = hasDynamicWorkspacePrefix(key) && WORKSPACE_ENV_KEY_PATTERN.test(key);
48
- const genericWorkspace = WORKSPACE_ENV_GENERIC_DISCOVERY_PATTERN.test(key);
49
- return providerSpecific || genericWorkspace;
50
- })
51
- .sort((a, b) => scoreWorkspaceEnvKey(b) - scoreWorkspaceEnvKey(a));
52
- }
53
-
44
+ .filter((key) => {
45
+ const providerSpecific =
46
+ hasDynamicWorkspacePrefix(key) && WORKSPACE_ENV_KEY_PATTERN.test(key);
47
+ const genericWorkspace = WORKSPACE_ENV_GENERIC_DISCOVERY_PATTERN.test(key);
48
+ return providerSpecific || genericWorkspace;
49
+ })
50
+ .sort((a, b) => scoreWorkspaceEnvKey(b) - scoreWorkspaceEnvKey(a));
51
+ }
52
+
54
53
  export function getWorkspaceEnvKeys(env = process.env, options = {}) {
55
54
  return [...WORKSPACE_ENV_VARS, ...getDynamicWorkspaceEnvKeys(env, options)];
56
55
  }
57
56
 
58
-
59
57
  export function getWorkspaceEnvDiagnosticKeys(env = process.env, options = {}) {
60
58
  const prioritized = getWorkspaceEnvKeys(env, options);
61
59
  const prioritizedSet = new Set(prioritized);
62
-
63
- const extraKeys = Object.keys(env)
64
- .filter((key) => !prioritizedSet.has(key))
65
- .filter((key) => WORKSPACE_ENV_KEY_PATTERN.test(key))
66
- .sort((a, b) => scoreWorkspaceEnvKey(b) - scoreWorkspaceEnvKey(a));
67
-
68
- return [...prioritized, ...extraKeys];
69
- }
60
+
61
+ const extraKeys = Object.keys(env)
62
+ .filter((key) => !prioritizedSet.has(key))
63
+ .filter((key) => WORKSPACE_ENV_KEY_PATTERN.test(key))
64
+ .sort((a, b) => scoreWorkspaceEnvKey(b) - scoreWorkspaceEnvKey(a));
65
+
66
+ return [...prioritized, ...extraKeys];
67
+ }
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,86 +1,86 @@
1
- {
2
- "name": "@softerist/heuristic-mcp",
3
- "version": "3.2.2",
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
- }
1
+ {
2
+ "name": "@softerist/heuristic-mcp",
3
+ "version": "3.2.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
+ "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
+ }
@@ -1,20 +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();
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();
@@ -1,43 +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();
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();
@@ -1,49 +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
- });
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
+ });
@@ -1,12 +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
- }
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
+ });