@softerist/heuristic-mcp 3.0.14 → 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.
- package/README.md +90 -82
- package/config.jsonc +173 -173
- package/features/ann-config.js +131 -0
- package/features/clear-cache.js +84 -0
- package/features/find-similar-code.js +291 -0
- package/features/hybrid-search.js +544 -0
- package/features/index-codebase.js +3268 -0
- package/features/lifecycle.js +1189 -0
- package/features/package-version.js +302 -0
- package/features/register.js +408 -0
- package/features/resources.js +156 -0
- package/features/set-workspace.js +265 -0
- package/index.js +136 -69
- package/lib/cache-ops.js +22 -22
- package/lib/cache-utils.js +565 -565
- package/lib/cache.js +1870 -1870
- package/lib/call-graph.js +396 -396
- package/lib/cli.js +1 -1
- package/lib/config.js +487 -427
- package/lib/constants.js +31 -0
- package/lib/embed-query-process.js +7 -7
- package/lib/embedding-process.js +7 -7
- package/lib/embedding-worker.js +299 -299
- package/lib/ignore-patterns.js +316 -316
- package/lib/json-worker.js +14 -14
- package/lib/json-writer.js +337 -337
- package/lib/logging.js +164 -164
- package/lib/memory-logger.js +13 -13
- package/lib/onnx-backend.js +193 -193
- package/lib/project-detector.js +84 -84
- package/lib/server-lifecycle.js +165 -165
- package/lib/settings-editor.js +754 -638
- package/lib/tokenizer.js +256 -256
- package/lib/utils.js +428 -428
- package/lib/vector-store-binary.js +627 -627
- package/lib/vector-store-sqlite.js +95 -95
- package/lib/workspace-env.js +28 -0
- package/mcp_config.json +9 -9
- package/package.json +86 -75
- package/scripts/clear-cache.js +20 -0
- package/scripts/download-model.js +43 -0
- package/scripts/mcp-launcher.js +49 -0
- package/scripts/postinstall.js +12 -0
- package/search-configs.js +36 -36
- package/.prettierrc +0 -7
- package/debug-pids.js +0 -30
- package/eslint.config.js +0 -36
- package/specs/plan.md +0 -23
- package/vitest.config.js +0 -39
package/lib/config.js
CHANGED
|
@@ -5,127 +5,128 @@ import crypto from 'crypto';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { ProjectDetector } from './project-detector.js';
|
|
7
7
|
import { parseJsonc } from './settings-editor.js';
|
|
8
|
-
import {
|
|
9
|
-
EMBEDDING_PROCESS_DEFAULT_GC_MAX_REQUESTS_WITHOUT_COLLECTION,
|
|
10
|
-
EMBEDDING_PROCESS_DEFAULT_GC_MIN_INTERVAL_MS,
|
|
11
|
-
EMBEDDING_PROCESS_DEFAULT_GC_RSS_THRESHOLD_MB,
|
|
12
|
-
} from './constants.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
8
|
+
import {
|
|
9
|
+
EMBEDDING_PROCESS_DEFAULT_GC_MAX_REQUESTS_WITHOUT_COLLECTION,
|
|
10
|
+
EMBEDDING_PROCESS_DEFAULT_GC_MIN_INTERVAL_MS,
|
|
11
|
+
EMBEDDING_PROCESS_DEFAULT_GC_RSS_THRESHOLD_MB,
|
|
12
|
+
} from './constants.js';
|
|
13
|
+
import { getWorkspaceEnvKeys } from './workspace-env.js';
|
|
14
|
+
|
|
15
|
+
const DEFAULT_MEMORY_CLEANUP_CONFIG = {
|
|
16
|
+
enableExplicitGc: true, // Require --expose-gc for more aggressive memory cleanup
|
|
17
|
+
clearCacheAfterIndex: true, // Drop in-memory vectors after indexing completes
|
|
18
|
+
unloadModelAfterIndex: true, // Unload embedding model from memory after indexing completes to free RAM
|
|
19
|
+
shutdownQueryEmbeddingPoolAfterIndex: true, // Force shutdown search embedding child pool after index operations
|
|
20
|
+
unloadModelAfterSearch: true, // Unload embedding model after search queries to keep memory low (trades speed for RAM)
|
|
21
|
+
embeddingPoolIdleTimeoutMs: 2000, // Idle timeout before killing persistent embedding child process (ms)
|
|
22
|
+
incrementalGcThresholdMb: 512, // RSS threshold for optional incremental GC
|
|
23
|
+
incrementalMemoryProfile: false, // Enable phase-level incremental indexing memory traces (diagnostics)
|
|
24
|
+
recycleServerOnHighRssAfterIncremental: false, // Recycle server process after incremental cleanup if RSS remains high
|
|
25
|
+
recycleServerOnHighRssThresholdMb: 4096, // RSS threshold (MB) that triggers incremental recycle
|
|
26
|
+
recycleServerOnHighRssCooldownMs: 300000, // Minimum interval between recycle attempts
|
|
27
|
+
recycleServerOnHighRssDelayMs: 2000, // Delay before recycle to allow logs/responses to flush
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const DEFAULT_INDEXING_CONFIG = {
|
|
31
|
+
smartIndexing: true, // Enable automatic project type detection and smart ignore patterns
|
|
32
|
+
chunkSize: 16, // Lines per chunk (tuned for speed/memory balance)
|
|
33
|
+
chunkOverlap: 4, // Overlap between chunks for context continuity
|
|
34
|
+
batchSize: 50, // Number of files to process in a single indexing batch
|
|
35
|
+
maxFileSize: 1048576, // 1MB - skip files larger than this
|
|
36
|
+
prefilterContentMaxBytes: 512 * 1024, // 512KB - cache content during prefilter to avoid double reads
|
|
37
|
+
maxResults: 5, // Maximum number of semantic search results to return
|
|
38
|
+
watchFiles: true, // Enable file system watcher to re-index changed files in real-time
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const DEFAULT_LOGGING_CONFIG = {
|
|
42
|
+
verbose: false, // Enable detailed logging for debugging and progress tracking
|
|
43
|
+
memoryLogIntervalMs: 5000, // Verbose memory log cadence during indexing (ms)
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const DEFAULT_CACHE_CONFIG = {
|
|
47
|
+
enableCache: true, // Whether to persist and reload embeddings between sessions
|
|
48
|
+
saveReaderWaitTimeoutMs: 5000, // Max wait for active reads before saving binary cache
|
|
49
|
+
cacheVectorAssumeFinite: true, // Assume vectors are finite (skip validation)
|
|
50
|
+
cacheVectorFloatDigits: null, // Decimal precision for cached vectors (null = default)
|
|
51
|
+
cacheWriteHighWaterMark: 262144, // Write stream highWaterMark for cache files
|
|
52
|
+
cacheVectorFlushChars: 262144, // Flush threshold (chars) for JSON writer
|
|
53
|
+
cacheVectorCheckFinite: true, // Validate vectors contain only finite numbers
|
|
54
|
+
cacheVectorNoMutation: false, // Avoid mutating vectors during serialization
|
|
55
|
+
cacheVectorJoinThreshold: 8192, // Join threshold for JSON array chunks
|
|
56
|
+
cacheVectorJoinChunkSize: 2048, // Chunk size for JSON join optimization
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const DEFAULT_WORKER_CONFIG = {
|
|
60
|
+
workerThreads: 'auto', // 0 = run in main thread (no workers), "auto" = CPU cores - 1, or set a number
|
|
61
|
+
workerBatchTimeoutMs: 120000, // Timeout per worker batch before fallback (ms)
|
|
62
|
+
workerFailureThreshold: 1, // Open circuit after N worker failures
|
|
63
|
+
workerFailureCooldownMs: 10 * 60 * 1000, // Cooldown before retrying workers
|
|
64
|
+
workerMaxChunksPerBatch: 100, // Cap chunks per worker batch to reduce hang risk
|
|
65
|
+
allowSingleThreadFallback: false, // Allow fallback to main-thread embeddings if workers fail
|
|
66
|
+
failFastEmbeddingErrors: false, // Abort worker embedding batch after repeated consecutive embed failures
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const DEFAULT_EMBEDDING_CONFIG = {
|
|
70
|
+
embeddingModel: 'jinaai/jina-embeddings-v2-base-code', // AI model ID used for semantic search
|
|
71
|
+
embeddingDimension: null, // null = full dimensions, or 64/128/256/512/768 for MRL-trained models
|
|
72
|
+
preloadEmbeddingModel: true, // Preload the embedding model at startup (server mode)
|
|
73
|
+
embeddingProcessPerBatch: false, // Use child process per batch for memory isolation
|
|
74
|
+
autoEmbeddingProcessPerBatch: true, // Auto-enable child process embedding in single-threaded mode for heavy models
|
|
75
|
+
embeddingBatchSize: null, // Override embedding batch size (null = auto)
|
|
76
|
+
embeddingProcessNumThreads: 8, // ONNX threads used by embedding child process
|
|
77
|
+
embeddingProcessGcRssThresholdMb: EMBEDDING_PROCESS_DEFAULT_GC_RSS_THRESHOLD_MB, // RSS threshold for embedding-child adaptive GC
|
|
78
|
+
embeddingProcessGcMinIntervalMs: EMBEDDING_PROCESS_DEFAULT_GC_MIN_INTERVAL_MS, // Minimum interval between embedding-child GC runs
|
|
79
|
+
embeddingProcessGcMaxRequestsWithoutCollection:
|
|
80
|
+
EMBEDDING_PROCESS_DEFAULT_GC_MAX_REQUESTS_WITHOUT_COLLECTION, // Backstop GC cadence for embedding child
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const DEFAULT_VECTOR_STORE_CONFIG = {
|
|
84
|
+
vectorStoreFormat: 'binary', // json | binary | sqlite (binary uses mmap-friendly on-disk store)
|
|
85
|
+
vectorStoreContentMode: 'external', // external = content loaded on-demand for binary store
|
|
86
|
+
contentCacheEntries: 256, // In-memory content cache entries for binary store
|
|
87
|
+
vectorStoreLoadMode: 'memory', // memory | disk (disk streams vectors from disk / memory is faster but requires more RAM)
|
|
88
|
+
vectorCacheEntries: 0, // In-memory vector cache entries for disk-backed loads
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const DEFAULT_SEARCH_CONFIG = {
|
|
92
|
+
semanticWeight: 0.7, // Balance between semantic and keyword scores (0.0 to 1.0)
|
|
93
|
+
exactMatchBoost: 1.5, // Multiplier applied when an exact string match is found
|
|
94
|
+
recencyBoost: 0.1, // Boost for recently modified files (max 0.1 added to score)
|
|
95
|
+
recencyDecayDays: 30, // After this many days, recency boost is 0
|
|
96
|
+
textMatchMaxCandidates: 2000, // Max candidates for full text matching before deferring
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const DEFAULT_CALL_GRAPH_CONFIG = {
|
|
100
|
+
callGraphEnabled: true, // Enable call graph extraction for proximity boosting
|
|
101
|
+
callGraphBoost: 0.15, // Boost for files related via call graph (0-1)
|
|
102
|
+
callGraphMaxHops: 1, // How many levels of calls to follow (1 = direct only)
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const DEFAULT_ANN_CONFIG = {
|
|
106
|
+
annEnabled: true, // Enable Approximate Nearest Neighbor (ANN) index for large codebases
|
|
107
|
+
annMinChunks: 5000, // Minimum number of chunks required to trigger ANN indexing
|
|
108
|
+
annMinCandidates: 50, // Minimum initial candidates to pull from ANN before refinement
|
|
109
|
+
annMaxCandidates: 200, // Hard limit on the number of ANN candidates to process
|
|
110
|
+
annCandidateMultiplier: 20, // Scale initial search depth based on requested maxResults
|
|
111
|
+
annEfConstruction: 200, // HNSW index construction quality (higher = better index, slower build)
|
|
112
|
+
annEfSearch: 64, // HNSW search parameter (higher = more accurate, slower search)
|
|
113
|
+
annM: 16, // Number of connections per element in HNSW index
|
|
114
|
+
annIndexCache: true, // Whether to cache the built HNSW index on disk
|
|
115
|
+
annMetric: 'cosine', // Distance metric for similarity (currently locked to cosine)
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const MEMORY_CLEANUP_KEYS = Object.freeze(Object.keys(DEFAULT_MEMORY_CLEANUP_CONFIG));
|
|
119
|
+
const INDEXING_KEYS = Object.freeze(Object.keys(DEFAULT_INDEXING_CONFIG));
|
|
120
|
+
const LOGGING_KEYS = Object.freeze(Object.keys(DEFAULT_LOGGING_CONFIG));
|
|
121
|
+
const CACHE_KEYS = Object.freeze(Object.keys(DEFAULT_CACHE_CONFIG));
|
|
122
|
+
const WORKER_KEYS = Object.freeze(Object.keys(DEFAULT_WORKER_CONFIG));
|
|
123
|
+
const EMBEDDING_KEYS = Object.freeze(Object.keys(DEFAULT_EMBEDDING_CONFIG));
|
|
124
|
+
const VECTOR_STORE_KEYS = Object.freeze(Object.keys(DEFAULT_VECTOR_STORE_CONFIG));
|
|
125
|
+
const SEARCH_KEYS = Object.freeze(Object.keys(DEFAULT_SEARCH_CONFIG));
|
|
126
|
+
const CALL_GRAPH_KEYS = Object.freeze(Object.keys(DEFAULT_CALL_GRAPH_CONFIG));
|
|
127
|
+
const ANN_KEYS = Object.freeze(Object.keys(DEFAULT_ANN_CONFIG));
|
|
128
|
+
|
|
129
|
+
const DEFAULT_CONFIG = {
|
|
129
130
|
searchDirectory: '.',
|
|
130
131
|
fileExtensions: [
|
|
131
132
|
// JavaScript/TypeScript
|
|
@@ -361,16 +362,16 @@ const DEFAULT_CONFIG = {
|
|
|
361
362
|
'**/scripts/**',
|
|
362
363
|
'**/tools/**',
|
|
363
364
|
],
|
|
364
|
-
chunkSize: DEFAULT_INDEXING_CONFIG.chunkSize,
|
|
365
|
-
chunkOverlap: DEFAULT_INDEXING_CONFIG.chunkOverlap,
|
|
366
|
-
batchSize: DEFAULT_INDEXING_CONFIG.batchSize,
|
|
367
|
-
maxFileSize: DEFAULT_INDEXING_CONFIG.maxFileSize,
|
|
368
|
-
prefilterContentMaxBytes: DEFAULT_INDEXING_CONFIG.prefilterContentMaxBytes,
|
|
369
|
-
maxResults: DEFAULT_INDEXING_CONFIG.maxResults,
|
|
370
|
-
enableCache: DEFAULT_CACHE_CONFIG.enableCache,
|
|
371
|
-
cacheDirectory: null, // Will be set dynamically by loadConfig()
|
|
372
|
-
// Cache cleanup behavior (consolidated namespace)
|
|
373
|
-
cacheCleanup: {
|
|
365
|
+
chunkSize: DEFAULT_INDEXING_CONFIG.chunkSize,
|
|
366
|
+
chunkOverlap: DEFAULT_INDEXING_CONFIG.chunkOverlap,
|
|
367
|
+
batchSize: DEFAULT_INDEXING_CONFIG.batchSize,
|
|
368
|
+
maxFileSize: DEFAULT_INDEXING_CONFIG.maxFileSize,
|
|
369
|
+
prefilterContentMaxBytes: DEFAULT_INDEXING_CONFIG.prefilterContentMaxBytes,
|
|
370
|
+
maxResults: DEFAULT_INDEXING_CONFIG.maxResults,
|
|
371
|
+
enableCache: DEFAULT_CACHE_CONFIG.enableCache,
|
|
372
|
+
cacheDirectory: null, // Will be set dynamically by loadConfig()
|
|
373
|
+
// Cache cleanup behavior (consolidated namespace)
|
|
374
|
+
cacheCleanup: {
|
|
374
375
|
autoCleanup: true, // Automatically remove stale caches on startup
|
|
375
376
|
staleNoMetaHours: 6, // Hours before incomplete cache (no meta.json) is considered stale
|
|
376
377
|
emptyThresholdHours: 24, // Hours before empty cache (0 files/chunks) is removed
|
|
@@ -378,97 +379,86 @@ const DEFAULT_CONFIG = {
|
|
|
378
379
|
maxUnusedDays: 30, // Days before unused cache is removed
|
|
379
380
|
tempThresholdHours: 24, // Hours before temp workspace cache is removed
|
|
380
381
|
staleProgressHours: 6, // Hours before stuck indexing is considered stale
|
|
381
|
-
safetyWindowMinutes: 10, // Minutes of recent activity to never delete
|
|
382
|
-
removeDuplicates: true, // Remove duplicate workspace caches
|
|
383
|
-
},
|
|
384
|
-
watchFiles: DEFAULT_INDEXING_CONFIG.watchFiles,
|
|
385
|
-
verbose: DEFAULT_LOGGING_CONFIG.verbose,
|
|
386
|
-
memoryLogIntervalMs: DEFAULT_LOGGING_CONFIG.memoryLogIntervalMs,
|
|
387
|
-
saveReaderWaitTimeoutMs: DEFAULT_CACHE_CONFIG.saveReaderWaitTimeoutMs,
|
|
388
|
-
workerThreads: DEFAULT_WORKER_CONFIG.workerThreads,
|
|
389
|
-
workerBatchTimeoutMs: DEFAULT_WORKER_CONFIG.workerBatchTimeoutMs,
|
|
390
|
-
workerFailureThreshold: DEFAULT_WORKER_CONFIG.workerFailureThreshold,
|
|
391
|
-
workerFailureCooldownMs: DEFAULT_WORKER_CONFIG.workerFailureCooldownMs,
|
|
392
|
-
workerMaxChunksPerBatch: DEFAULT_WORKER_CONFIG.workerMaxChunksPerBatch,
|
|
393
|
-
allowSingleThreadFallback: DEFAULT_WORKER_CONFIG.allowSingleThreadFallback,
|
|
394
|
-
failFastEmbeddingErrors: DEFAULT_WORKER_CONFIG.failFastEmbeddingErrors,
|
|
395
|
-
embeddingProcessPerBatch: DEFAULT_EMBEDDING_CONFIG.embeddingProcessPerBatch,
|
|
396
|
-
autoEmbeddingProcessPerBatch: DEFAULT_EMBEDDING_CONFIG.autoEmbeddingProcessPerBatch,
|
|
397
|
-
embeddingBatchSize: DEFAULT_EMBEDDING_CONFIG.embeddingBatchSize,
|
|
398
|
-
embeddingProcessNumThreads: DEFAULT_EMBEDDING_CONFIG.embeddingProcessNumThreads,
|
|
399
|
-
embeddingProcessGcRssThresholdMb: DEFAULT_EMBEDDING_CONFIG.embeddingProcessGcRssThresholdMb,
|
|
400
|
-
embeddingProcessGcMinIntervalMs: DEFAULT_EMBEDDING_CONFIG.embeddingProcessGcMinIntervalMs,
|
|
401
|
-
embeddingProcessGcMaxRequestsWithoutCollection:
|
|
402
|
-
DEFAULT_EMBEDDING_CONFIG.embeddingProcessGcMaxRequestsWithoutCollection,
|
|
403
|
-
enableExplicitGc: DEFAULT_MEMORY_CLEANUP_CONFIG.enableExplicitGc,
|
|
404
|
-
embeddingModel: DEFAULT_EMBEDDING_CONFIG.embeddingModel,
|
|
405
|
-
embeddingDimension: DEFAULT_EMBEDDING_CONFIG.embeddingDimension,
|
|
406
|
-
preloadEmbeddingModel: DEFAULT_EMBEDDING_CONFIG.preloadEmbeddingModel,
|
|
407
|
-
vectorStoreFormat: DEFAULT_VECTOR_STORE_CONFIG.vectorStoreFormat,
|
|
408
|
-
vectorStoreContentMode: DEFAULT_VECTOR_STORE_CONFIG.vectorStoreContentMode,
|
|
409
|
-
contentCacheEntries: DEFAULT_VECTOR_STORE_CONFIG.contentCacheEntries,
|
|
410
|
-
vectorStoreLoadMode: DEFAULT_VECTOR_STORE_CONFIG.vectorStoreLoadMode,
|
|
411
|
-
vectorCacheEntries: DEFAULT_VECTOR_STORE_CONFIG.vectorCacheEntries,
|
|
412
|
-
clearCacheAfterIndex: DEFAULT_MEMORY_CLEANUP_CONFIG.clearCacheAfterIndex,
|
|
413
|
-
unloadModelAfterIndex: DEFAULT_MEMORY_CLEANUP_CONFIG.unloadModelAfterIndex,
|
|
414
|
-
shutdownQueryEmbeddingPoolAfterIndex:
|
|
415
|
-
DEFAULT_MEMORY_CLEANUP_CONFIG.shutdownQueryEmbeddingPoolAfterIndex,
|
|
416
|
-
unloadModelAfterSearch: DEFAULT_MEMORY_CLEANUP_CONFIG.unloadModelAfterSearch,
|
|
417
|
-
embeddingPoolIdleTimeoutMs: DEFAULT_MEMORY_CLEANUP_CONFIG.embeddingPoolIdleTimeoutMs,
|
|
418
|
-
incrementalGcThresholdMb: DEFAULT_MEMORY_CLEANUP_CONFIG.incrementalGcThresholdMb,
|
|
419
|
-
incrementalMemoryProfile: DEFAULT_MEMORY_CLEANUP_CONFIG.incrementalMemoryProfile,
|
|
420
|
-
recycleServerOnHighRssAfterIncremental:
|
|
421
|
-
DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssAfterIncremental,
|
|
422
|
-
recycleServerOnHighRssThresholdMb:
|
|
423
|
-
DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssThresholdMb,
|
|
424
|
-
recycleServerOnHighRssCooldownMs:
|
|
425
|
-
DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssCooldownMs,
|
|
426
|
-
recycleServerOnHighRssDelayMs: DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssDelayMs,
|
|
427
|
-
memoryCleanup: { ...DEFAULT_MEMORY_CLEANUP_CONFIG },
|
|
428
|
-
semanticWeight: DEFAULT_SEARCH_CONFIG.semanticWeight,
|
|
429
|
-
exactMatchBoost: DEFAULT_SEARCH_CONFIG.exactMatchBoost,
|
|
430
|
-
recencyBoost: DEFAULT_SEARCH_CONFIG.recencyBoost,
|
|
431
|
-
recencyDecayDays: DEFAULT_SEARCH_CONFIG.recencyDecayDays,
|
|
432
|
-
textMatchMaxCandidates: DEFAULT_SEARCH_CONFIG.textMatchMaxCandidates,
|
|
433
|
-
smartIndexing: DEFAULT_INDEXING_CONFIG.smartIndexing,
|
|
434
|
-
callGraphEnabled: DEFAULT_CALL_GRAPH_CONFIG.callGraphEnabled,
|
|
435
|
-
callGraphBoost: DEFAULT_CALL_GRAPH_CONFIG.callGraphBoost,
|
|
436
|
-
callGraphMaxHops: DEFAULT_CALL_GRAPH_CONFIG.callGraphMaxHops,
|
|
437
|
-
annEnabled: DEFAULT_ANN_CONFIG.annEnabled,
|
|
438
|
-
annMinChunks: DEFAULT_ANN_CONFIG.annMinChunks,
|
|
439
|
-
annMinCandidates: DEFAULT_ANN_CONFIG.annMinCandidates,
|
|
440
|
-
annMaxCandidates: DEFAULT_ANN_CONFIG.annMaxCandidates,
|
|
441
|
-
annCandidateMultiplier: DEFAULT_ANN_CONFIG.annCandidateMultiplier,
|
|
442
|
-
annEfConstruction: DEFAULT_ANN_CONFIG.annEfConstruction,
|
|
443
|
-
annEfSearch: DEFAULT_ANN_CONFIG.annEfSearch,
|
|
444
|
-
annM: DEFAULT_ANN_CONFIG.annM,
|
|
445
|
-
annIndexCache: DEFAULT_ANN_CONFIG.annIndexCache,
|
|
446
|
-
annMetric: DEFAULT_ANN_CONFIG.annMetric,
|
|
447
|
-
indexing: { ...DEFAULT_INDEXING_CONFIG },
|
|
448
|
-
logging: { ...DEFAULT_LOGGING_CONFIG },
|
|
449
|
-
cache: { ...DEFAULT_CACHE_CONFIG },
|
|
450
|
-
worker: { ...DEFAULT_WORKER_CONFIG },
|
|
451
|
-
embedding: { ...DEFAULT_EMBEDDING_CONFIG },
|
|
452
|
-
vectorStore: { ...DEFAULT_VECTOR_STORE_CONFIG },
|
|
453
|
-
search: { ...DEFAULT_SEARCH_CONFIG },
|
|
454
|
-
callGraph: { ...DEFAULT_CALL_GRAPH_CONFIG },
|
|
455
|
-
ann: { ...DEFAULT_ANN_CONFIG },
|
|
456
|
-
};
|
|
382
|
+
safetyWindowMinutes: 10, // Minutes of recent activity to never delete
|
|
383
|
+
removeDuplicates: true, // Remove duplicate workspace caches
|
|
384
|
+
},
|
|
385
|
+
watchFiles: DEFAULT_INDEXING_CONFIG.watchFiles,
|
|
386
|
+
verbose: DEFAULT_LOGGING_CONFIG.verbose,
|
|
387
|
+
memoryLogIntervalMs: DEFAULT_LOGGING_CONFIG.memoryLogIntervalMs,
|
|
388
|
+
saveReaderWaitTimeoutMs: DEFAULT_CACHE_CONFIG.saveReaderWaitTimeoutMs,
|
|
389
|
+
workerThreads: DEFAULT_WORKER_CONFIG.workerThreads,
|
|
390
|
+
workerBatchTimeoutMs: DEFAULT_WORKER_CONFIG.workerBatchTimeoutMs,
|
|
391
|
+
workerFailureThreshold: DEFAULT_WORKER_CONFIG.workerFailureThreshold,
|
|
392
|
+
workerFailureCooldownMs: DEFAULT_WORKER_CONFIG.workerFailureCooldownMs,
|
|
393
|
+
workerMaxChunksPerBatch: DEFAULT_WORKER_CONFIG.workerMaxChunksPerBatch,
|
|
394
|
+
allowSingleThreadFallback: DEFAULT_WORKER_CONFIG.allowSingleThreadFallback,
|
|
395
|
+
failFastEmbeddingErrors: DEFAULT_WORKER_CONFIG.failFastEmbeddingErrors,
|
|
396
|
+
embeddingProcessPerBatch: DEFAULT_EMBEDDING_CONFIG.embeddingProcessPerBatch,
|
|
397
|
+
autoEmbeddingProcessPerBatch: DEFAULT_EMBEDDING_CONFIG.autoEmbeddingProcessPerBatch,
|
|
398
|
+
embeddingBatchSize: DEFAULT_EMBEDDING_CONFIG.embeddingBatchSize,
|
|
399
|
+
embeddingProcessNumThreads: DEFAULT_EMBEDDING_CONFIG.embeddingProcessNumThreads,
|
|
400
|
+
embeddingProcessGcRssThresholdMb: DEFAULT_EMBEDDING_CONFIG.embeddingProcessGcRssThresholdMb,
|
|
401
|
+
embeddingProcessGcMinIntervalMs: DEFAULT_EMBEDDING_CONFIG.embeddingProcessGcMinIntervalMs,
|
|
402
|
+
embeddingProcessGcMaxRequestsWithoutCollection:
|
|
403
|
+
DEFAULT_EMBEDDING_CONFIG.embeddingProcessGcMaxRequestsWithoutCollection,
|
|
404
|
+
enableExplicitGc: DEFAULT_MEMORY_CLEANUP_CONFIG.enableExplicitGc,
|
|
405
|
+
embeddingModel: DEFAULT_EMBEDDING_CONFIG.embeddingModel,
|
|
406
|
+
embeddingDimension: DEFAULT_EMBEDDING_CONFIG.embeddingDimension,
|
|
407
|
+
preloadEmbeddingModel: DEFAULT_EMBEDDING_CONFIG.preloadEmbeddingModel,
|
|
408
|
+
vectorStoreFormat: DEFAULT_VECTOR_STORE_CONFIG.vectorStoreFormat,
|
|
409
|
+
vectorStoreContentMode: DEFAULT_VECTOR_STORE_CONFIG.vectorStoreContentMode,
|
|
410
|
+
contentCacheEntries: DEFAULT_VECTOR_STORE_CONFIG.contentCacheEntries,
|
|
411
|
+
vectorStoreLoadMode: DEFAULT_VECTOR_STORE_CONFIG.vectorStoreLoadMode,
|
|
412
|
+
vectorCacheEntries: DEFAULT_VECTOR_STORE_CONFIG.vectorCacheEntries,
|
|
413
|
+
clearCacheAfterIndex: DEFAULT_MEMORY_CLEANUP_CONFIG.clearCacheAfterIndex,
|
|
414
|
+
unloadModelAfterIndex: DEFAULT_MEMORY_CLEANUP_CONFIG.unloadModelAfterIndex,
|
|
415
|
+
shutdownQueryEmbeddingPoolAfterIndex:
|
|
416
|
+
DEFAULT_MEMORY_CLEANUP_CONFIG.shutdownQueryEmbeddingPoolAfterIndex,
|
|
417
|
+
unloadModelAfterSearch: DEFAULT_MEMORY_CLEANUP_CONFIG.unloadModelAfterSearch,
|
|
418
|
+
embeddingPoolIdleTimeoutMs: DEFAULT_MEMORY_CLEANUP_CONFIG.embeddingPoolIdleTimeoutMs,
|
|
419
|
+
incrementalGcThresholdMb: DEFAULT_MEMORY_CLEANUP_CONFIG.incrementalGcThresholdMb,
|
|
420
|
+
incrementalMemoryProfile: DEFAULT_MEMORY_CLEANUP_CONFIG.incrementalMemoryProfile,
|
|
421
|
+
recycleServerOnHighRssAfterIncremental:
|
|
422
|
+
DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssAfterIncremental,
|
|
423
|
+
recycleServerOnHighRssThresholdMb:
|
|
424
|
+
DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssThresholdMb,
|
|
425
|
+
recycleServerOnHighRssCooldownMs:
|
|
426
|
+
DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssCooldownMs,
|
|
427
|
+
recycleServerOnHighRssDelayMs: DEFAULT_MEMORY_CLEANUP_CONFIG.recycleServerOnHighRssDelayMs,
|
|
428
|
+
memoryCleanup: { ...DEFAULT_MEMORY_CLEANUP_CONFIG },
|
|
429
|
+
semanticWeight: DEFAULT_SEARCH_CONFIG.semanticWeight,
|
|
430
|
+
exactMatchBoost: DEFAULT_SEARCH_CONFIG.exactMatchBoost,
|
|
431
|
+
recencyBoost: DEFAULT_SEARCH_CONFIG.recencyBoost,
|
|
432
|
+
recencyDecayDays: DEFAULT_SEARCH_CONFIG.recencyDecayDays,
|
|
433
|
+
textMatchMaxCandidates: DEFAULT_SEARCH_CONFIG.textMatchMaxCandidates,
|
|
434
|
+
smartIndexing: DEFAULT_INDEXING_CONFIG.smartIndexing,
|
|
435
|
+
callGraphEnabled: DEFAULT_CALL_GRAPH_CONFIG.callGraphEnabled,
|
|
436
|
+
callGraphBoost: DEFAULT_CALL_GRAPH_CONFIG.callGraphBoost,
|
|
437
|
+
callGraphMaxHops: DEFAULT_CALL_GRAPH_CONFIG.callGraphMaxHops,
|
|
438
|
+
annEnabled: DEFAULT_ANN_CONFIG.annEnabled,
|
|
439
|
+
annMinChunks: DEFAULT_ANN_CONFIG.annMinChunks,
|
|
440
|
+
annMinCandidates: DEFAULT_ANN_CONFIG.annMinCandidates,
|
|
441
|
+
annMaxCandidates: DEFAULT_ANN_CONFIG.annMaxCandidates,
|
|
442
|
+
annCandidateMultiplier: DEFAULT_ANN_CONFIG.annCandidateMultiplier,
|
|
443
|
+
annEfConstruction: DEFAULT_ANN_CONFIG.annEfConstruction,
|
|
444
|
+
annEfSearch: DEFAULT_ANN_CONFIG.annEfSearch,
|
|
445
|
+
annM: DEFAULT_ANN_CONFIG.annM,
|
|
446
|
+
annIndexCache: DEFAULT_ANN_CONFIG.annIndexCache,
|
|
447
|
+
annMetric: DEFAULT_ANN_CONFIG.annMetric,
|
|
448
|
+
indexing: { ...DEFAULT_INDEXING_CONFIG },
|
|
449
|
+
logging: { ...DEFAULT_LOGGING_CONFIG },
|
|
450
|
+
cache: { ...DEFAULT_CACHE_CONFIG },
|
|
451
|
+
worker: { ...DEFAULT_WORKER_CONFIG },
|
|
452
|
+
embedding: { ...DEFAULT_EMBEDDING_CONFIG },
|
|
453
|
+
vectorStore: { ...DEFAULT_VECTOR_STORE_CONFIG },
|
|
454
|
+
search: { ...DEFAULT_SEARCH_CONFIG },
|
|
455
|
+
callGraph: { ...DEFAULT_CALL_GRAPH_CONFIG },
|
|
456
|
+
ann: { ...DEFAULT_ANN_CONFIG },
|
|
457
|
+
};
|
|
457
458
|
|
|
458
459
|
let config = { ...DEFAULT_CONFIG };
|
|
459
460
|
|
|
460
|
-
const
|
|
461
|
-
'HEURISTIC_MCP_WORKSPACE',
|
|
462
|
-
'MCP_WORKSPACE',
|
|
463
|
-
'WORKSPACE_FOLDER',
|
|
464
|
-
'WORKSPACE_ROOT',
|
|
465
|
-
'CURSOR_WORKSPACE',
|
|
466
|
-
'CLAUDE_WORKSPACE',
|
|
467
|
-
'ANTIGRAVITY_WORKSPACE',
|
|
468
|
-
'INIT_CWD',
|
|
469
|
-
];
|
|
470
|
-
|
|
471
|
-
const WORKSPACE_MARKERS = [
|
|
461
|
+
const WORKSPACE_MARKERS = [
|
|
472
462
|
'.git',
|
|
473
463
|
'package.json',
|
|
474
464
|
'pyproject.toml',
|
|
@@ -480,118 +470,118 @@ const WORKSPACE_MARKERS = [
|
|
|
480
470
|
'requirements.txt',
|
|
481
471
|
'Gemfile',
|
|
482
472
|
'Makefile',
|
|
483
|
-
'CMakeLists.txt',
|
|
484
|
-
];
|
|
485
|
-
|
|
486
|
-
function hasOwn(obj, key) {
|
|
487
|
-
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const CONFIG_NAMESPACES = Object.freeze([
|
|
491
|
-
{
|
|
492
|
-
name: 'memoryCleanup',
|
|
493
|
-
keys: MEMORY_CLEANUP_KEYS,
|
|
494
|
-
defaults: DEFAULT_MEMORY_CLEANUP_CONFIG,
|
|
495
|
-
},
|
|
496
|
-
{
|
|
497
|
-
name: 'indexing',
|
|
498
|
-
keys: INDEXING_KEYS,
|
|
499
|
-
defaults: DEFAULT_INDEXING_CONFIG,
|
|
500
|
-
},
|
|
501
|
-
{
|
|
502
|
-
name: 'logging',
|
|
503
|
-
keys: LOGGING_KEYS,
|
|
504
|
-
defaults: DEFAULT_LOGGING_CONFIG,
|
|
505
|
-
},
|
|
506
|
-
{
|
|
507
|
-
name: 'cache',
|
|
508
|
-
keys: CACHE_KEYS,
|
|
509
|
-
defaults: DEFAULT_CACHE_CONFIG,
|
|
510
|
-
},
|
|
511
|
-
{
|
|
512
|
-
name: 'worker',
|
|
513
|
-
keys: WORKER_KEYS,
|
|
514
|
-
defaults: DEFAULT_WORKER_CONFIG,
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
name: 'embedding',
|
|
518
|
-
keys: EMBEDDING_KEYS,
|
|
519
|
-
defaults: DEFAULT_EMBEDDING_CONFIG,
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
name: 'vectorStore',
|
|
523
|
-
keys: VECTOR_STORE_KEYS,
|
|
524
|
-
defaults: DEFAULT_VECTOR_STORE_CONFIG,
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
name: 'search',
|
|
528
|
-
keys: SEARCH_KEYS,
|
|
529
|
-
defaults: DEFAULT_SEARCH_CONFIG,
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
name: 'callGraph',
|
|
533
|
-
keys: CALL_GRAPH_KEYS,
|
|
534
|
-
defaults: DEFAULT_CALL_GRAPH_CONFIG,
|
|
535
|
-
},
|
|
536
|
-
{
|
|
537
|
-
name: 'ann',
|
|
538
|
-
keys: ANN_KEYS,
|
|
539
|
-
defaults: DEFAULT_ANN_CONFIG,
|
|
540
|
-
},
|
|
541
|
-
]);
|
|
542
|
-
|
|
543
|
-
function applyNamespace(targetConfig, sourceConfig, namespaceName, keys, defaults) {
|
|
544
|
-
const sourceNamespace =
|
|
545
|
-
sourceConfig && typeof sourceConfig[namespaceName] === 'object'
|
|
546
|
-
? sourceConfig[namespaceName]
|
|
547
|
-
: {};
|
|
548
|
-
const mergedNamespace = {
|
|
549
|
-
...defaults,
|
|
550
|
-
...(targetConfig[namespaceName] && typeof targetConfig[namespaceName] === 'object'
|
|
551
|
-
? targetConfig[namespaceName]
|
|
552
|
-
: {}),
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
for (const key of keys) {
|
|
556
|
-
if (hasOwn(sourceNamespace, key)) {
|
|
557
|
-
targetConfig[key] = mergedNamespace[key];
|
|
558
|
-
} else {
|
|
559
|
-
mergedNamespace[key] = targetConfig[key];
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
targetConfig[namespaceName] = mergedNamespace;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
function syncNamespace(targetConfig, namespaceName, keys, defaults) {
|
|
567
|
-
const currentNamespace =
|
|
568
|
-
targetConfig[namespaceName] && typeof targetConfig[namespaceName] === 'object'
|
|
569
|
-
? targetConfig[namespaceName]
|
|
570
|
-
: {};
|
|
571
|
-
const mergedNamespace = { ...defaults, ...currentNamespace };
|
|
572
|
-
for (const key of keys) {
|
|
573
|
-
mergedNamespace[key] = targetConfig[key];
|
|
574
|
-
}
|
|
575
|
-
targetConfig[namespaceName] = mergedNamespace;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
function applyAllNamespaces(targetConfig, sourceConfig) {
|
|
579
|
-
for (const namespace of CONFIG_NAMESPACES) {
|
|
580
|
-
applyNamespace(
|
|
581
|
-
targetConfig,
|
|
582
|
-
sourceConfig,
|
|
583
|
-
namespace.name,
|
|
584
|
-
namespace.keys,
|
|
585
|
-
namespace.defaults
|
|
586
|
-
);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
function syncAllNamespaces(targetConfig) {
|
|
591
|
-
for (const namespace of CONFIG_NAMESPACES) {
|
|
592
|
-
syncNamespace(targetConfig, namespace.name, namespace.keys, namespace.defaults);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
473
|
+
'CMakeLists.txt',
|
|
474
|
+
];
|
|
475
|
+
|
|
476
|
+
function hasOwn(obj, key) {
|
|
477
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const CONFIG_NAMESPACES = Object.freeze([
|
|
481
|
+
{
|
|
482
|
+
name: 'memoryCleanup',
|
|
483
|
+
keys: MEMORY_CLEANUP_KEYS,
|
|
484
|
+
defaults: DEFAULT_MEMORY_CLEANUP_CONFIG,
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
name: 'indexing',
|
|
488
|
+
keys: INDEXING_KEYS,
|
|
489
|
+
defaults: DEFAULT_INDEXING_CONFIG,
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: 'logging',
|
|
493
|
+
keys: LOGGING_KEYS,
|
|
494
|
+
defaults: DEFAULT_LOGGING_CONFIG,
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
name: 'cache',
|
|
498
|
+
keys: CACHE_KEYS,
|
|
499
|
+
defaults: DEFAULT_CACHE_CONFIG,
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: 'worker',
|
|
503
|
+
keys: WORKER_KEYS,
|
|
504
|
+
defaults: DEFAULT_WORKER_CONFIG,
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
name: 'embedding',
|
|
508
|
+
keys: EMBEDDING_KEYS,
|
|
509
|
+
defaults: DEFAULT_EMBEDDING_CONFIG,
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
name: 'vectorStore',
|
|
513
|
+
keys: VECTOR_STORE_KEYS,
|
|
514
|
+
defaults: DEFAULT_VECTOR_STORE_CONFIG,
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
name: 'search',
|
|
518
|
+
keys: SEARCH_KEYS,
|
|
519
|
+
defaults: DEFAULT_SEARCH_CONFIG,
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
name: 'callGraph',
|
|
523
|
+
keys: CALL_GRAPH_KEYS,
|
|
524
|
+
defaults: DEFAULT_CALL_GRAPH_CONFIG,
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
name: 'ann',
|
|
528
|
+
keys: ANN_KEYS,
|
|
529
|
+
defaults: DEFAULT_ANN_CONFIG,
|
|
530
|
+
},
|
|
531
|
+
]);
|
|
532
|
+
|
|
533
|
+
function applyNamespace(targetConfig, sourceConfig, namespaceName, keys, defaults) {
|
|
534
|
+
const sourceNamespace =
|
|
535
|
+
sourceConfig && typeof sourceConfig[namespaceName] === 'object'
|
|
536
|
+
? sourceConfig[namespaceName]
|
|
537
|
+
: {};
|
|
538
|
+
const mergedNamespace = {
|
|
539
|
+
...defaults,
|
|
540
|
+
...(targetConfig[namespaceName] && typeof targetConfig[namespaceName] === 'object'
|
|
541
|
+
? targetConfig[namespaceName]
|
|
542
|
+
: {}),
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
for (const key of keys) {
|
|
546
|
+
if (hasOwn(sourceNamespace, key)) {
|
|
547
|
+
targetConfig[key] = mergedNamespace[key];
|
|
548
|
+
} else {
|
|
549
|
+
mergedNamespace[key] = targetConfig[key];
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
targetConfig[namespaceName] = mergedNamespace;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function syncNamespace(targetConfig, namespaceName, keys, defaults) {
|
|
557
|
+
const currentNamespace =
|
|
558
|
+
targetConfig[namespaceName] && typeof targetConfig[namespaceName] === 'object'
|
|
559
|
+
? targetConfig[namespaceName]
|
|
560
|
+
: {};
|
|
561
|
+
const mergedNamespace = { ...defaults, ...currentNamespace };
|
|
562
|
+
for (const key of keys) {
|
|
563
|
+
mergedNamespace[key] = targetConfig[key];
|
|
564
|
+
}
|
|
565
|
+
targetConfig[namespaceName] = mergedNamespace;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function applyAllNamespaces(targetConfig, sourceConfig) {
|
|
569
|
+
for (const namespace of CONFIG_NAMESPACES) {
|
|
570
|
+
applyNamespace(
|
|
571
|
+
targetConfig,
|
|
572
|
+
sourceConfig,
|
|
573
|
+
namespace.name,
|
|
574
|
+
namespace.keys,
|
|
575
|
+
namespace.defaults
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function syncAllNamespaces(targetConfig) {
|
|
581
|
+
for (const namespace of CONFIG_NAMESPACES) {
|
|
582
|
+
syncNamespace(targetConfig, namespace.name, namespace.keys, namespace.defaults);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
595
585
|
|
|
596
586
|
async function pathExists(filePath) {
|
|
597
587
|
try {
|
|
@@ -627,20 +617,86 @@ async function findWorkspaceRoot(startDir) {
|
|
|
627
617
|
return path.resolve(startDir);
|
|
628
618
|
}
|
|
629
619
|
|
|
620
|
+
async function resolveWorkspaceCandidate(rawValue) {
|
|
621
|
+
if (!rawValue || rawValue.includes('${')) return null;
|
|
622
|
+
const candidate = path.resolve(rawValue);
|
|
623
|
+
if (!(await pathExists(candidate))) return null;
|
|
624
|
+
try {
|
|
625
|
+
const stats = await fs.stat(candidate);
|
|
626
|
+
if (!stats.isDirectory()) return null;
|
|
627
|
+
} catch {
|
|
628
|
+
return null;
|
|
629
|
+
}
|
|
630
|
+
return candidate;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function logWorkspaceResolution(resolution) {
|
|
634
|
+
if (!resolution || !resolution.path) return;
|
|
635
|
+
|
|
636
|
+
if (resolution.source === 'workspace-arg') {
|
|
637
|
+
console.info(`[Config] Workspace resolution: --workspace -> ${resolution.path}`);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (resolution.source === 'env' && resolution.envKey) {
|
|
642
|
+
console.info(`[Config] Workspace resolution: env ${resolution.envKey} -> ${resolution.path}`);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (resolution.source === 'test-cwd') {
|
|
647
|
+
console.info(`[Config] Workspace resolution: process.cwd() (test mode) -> ${resolution.path}`);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (resolution.source === 'cwd-root-search') {
|
|
652
|
+
const from = resolution.fromPath || process.cwd();
|
|
653
|
+
console.info(
|
|
654
|
+
`[Config] Workspace resolution: workspace root from cwd (${from}) -> ${resolution.path}`
|
|
655
|
+
);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
console.info(`[Config] Workspace resolution: process.cwd() -> ${resolution.path}`);
|
|
660
|
+
}
|
|
661
|
+
|
|
630
662
|
async function resolveWorkspaceDir(workspaceDir) {
|
|
631
|
-
if (workspaceDir)
|
|
663
|
+
if (workspaceDir) {
|
|
664
|
+
return {
|
|
665
|
+
path: path.resolve(workspaceDir),
|
|
666
|
+
source: 'workspace-arg',
|
|
667
|
+
};
|
|
668
|
+
}
|
|
632
669
|
if (process.env.VITEST === 'true' || process.env.NODE_ENV === 'test') {
|
|
633
|
-
return
|
|
670
|
+
return {
|
|
671
|
+
path: path.resolve(process.cwd()),
|
|
672
|
+
source: 'test-cwd',
|
|
673
|
+
};
|
|
634
674
|
}
|
|
635
675
|
|
|
636
|
-
for (const key of
|
|
637
|
-
const
|
|
638
|
-
if (
|
|
639
|
-
|
|
640
|
-
|
|
676
|
+
for (const key of getWorkspaceEnvKeys()) {
|
|
677
|
+
const candidate = await resolveWorkspaceCandidate(process.env[key]);
|
|
678
|
+
if (candidate) {
|
|
679
|
+
return {
|
|
680
|
+
path: candidate,
|
|
681
|
+
source: 'env',
|
|
682
|
+
envKey: key,
|
|
683
|
+
};
|
|
684
|
+
}
|
|
641
685
|
}
|
|
642
686
|
|
|
643
|
-
|
|
687
|
+
const cwd = path.resolve(process.cwd());
|
|
688
|
+
const root = await findWorkspaceRoot(cwd);
|
|
689
|
+
if (root !== cwd) {
|
|
690
|
+
return {
|
|
691
|
+
path: root,
|
|
692
|
+
source: 'cwd-root-search',
|
|
693
|
+
fromPath: cwd,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
return {
|
|
697
|
+
path: cwd,
|
|
698
|
+
source: 'cwd',
|
|
699
|
+
};
|
|
644
700
|
}
|
|
645
701
|
|
|
646
702
|
export async function loadConfig(workspaceDir = null) {
|
|
@@ -652,14 +708,18 @@ export async function loadConfig(workspaceDir = null) {
|
|
|
652
708
|
let serverDir = null;
|
|
653
709
|
if (workspaceDir) {
|
|
654
710
|
// Workspace mode: load config from workspace root
|
|
655
|
-
|
|
711
|
+
const workspaceResolution = await resolveWorkspaceDir(workspaceDir);
|
|
712
|
+
baseDir = workspaceResolution.path;
|
|
656
713
|
console.info(`[Config] Workspace mode: ${baseDir}`);
|
|
714
|
+
logWorkspaceResolution(workspaceResolution);
|
|
657
715
|
} else {
|
|
658
716
|
// Server mode: load config from server directory for global settings,
|
|
659
717
|
// but use process.cwd() as base for searching if not specified otherwise
|
|
660
718
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
661
719
|
serverDir = path.resolve(scriptDir, '..');
|
|
662
|
-
|
|
720
|
+
const workspaceResolution = await resolveWorkspaceDir(null);
|
|
721
|
+
baseDir = workspaceResolution.path;
|
|
722
|
+
logWorkspaceResolution(workspaceResolution);
|
|
663
723
|
}
|
|
664
724
|
|
|
665
725
|
let userConfig = {};
|
|
@@ -699,16 +759,16 @@ export async function loadConfig(workspaceDir = null) {
|
|
|
699
759
|
}
|
|
700
760
|
}
|
|
701
761
|
|
|
702
|
-
config = { ...DEFAULT_CONFIG, ...userConfig };
|
|
703
|
-
applyAllNamespaces(config, userConfig);
|
|
704
|
-
|
|
705
|
-
// Backward compatibility for legacy top-level cache cleanup toggle.
|
|
706
|
-
if (
|
|
707
|
-
hasOwn(userConfig, 'autoCleanStaleCaches') &&
|
|
708
|
-
!(userConfig.cacheCleanup && hasOwn(userConfig.cacheCleanup, 'autoCleanup'))
|
|
709
|
-
) {
|
|
710
|
-
config.cacheCleanup.autoCleanup = Boolean(userConfig.autoCleanStaleCaches);
|
|
711
|
-
}
|
|
762
|
+
config = { ...DEFAULT_CONFIG, ...userConfig };
|
|
763
|
+
applyAllNamespaces(config, userConfig);
|
|
764
|
+
|
|
765
|
+
// Backward compatibility for legacy top-level cache cleanup toggle.
|
|
766
|
+
if (
|
|
767
|
+
hasOwn(userConfig, 'autoCleanStaleCaches') &&
|
|
768
|
+
!(userConfig.cacheCleanup && hasOwn(userConfig.cacheCleanup, 'autoCleanup'))
|
|
769
|
+
) {
|
|
770
|
+
config.cacheCleanup.autoCleanup = Boolean(userConfig.autoCleanStaleCaches);
|
|
771
|
+
}
|
|
712
772
|
|
|
713
773
|
// Set search directory (respect user override when provided)
|
|
714
774
|
if (userConfig.searchDirectory) {
|
|
@@ -990,74 +1050,74 @@ export async function loadConfig(workspaceDir = null) {
|
|
|
990
1050
|
}
|
|
991
1051
|
}
|
|
992
1052
|
|
|
993
|
-
if (process.env.SMART_CODING_INCREMENTAL_GC_THRESHOLD_MB !== undefined) {
|
|
994
|
-
const value = parseInt(process.env.SMART_CODING_INCREMENTAL_GC_THRESHOLD_MB, 10);
|
|
995
|
-
if (!isNaN(value) && value >= 0) {
|
|
996
|
-
config.incrementalGcThresholdMb = value;
|
|
1053
|
+
if (process.env.SMART_CODING_INCREMENTAL_GC_THRESHOLD_MB !== undefined) {
|
|
1054
|
+
const value = parseInt(process.env.SMART_CODING_INCREMENTAL_GC_THRESHOLD_MB, 10);
|
|
1055
|
+
if (!isNaN(value) && value >= 0) {
|
|
1056
|
+
config.incrementalGcThresholdMb = value;
|
|
997
1057
|
} else {
|
|
998
1058
|
console.warn(
|
|
999
1059
|
`[Config] Invalid SMART_CODING_INCREMENTAL_GC_THRESHOLD_MB: ${process.env.SMART_CODING_INCREMENTAL_GC_THRESHOLD_MB}, using default`
|
|
1000
|
-
);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
if (process.env.SMART_CODING_INCREMENTAL_MEMORY_PROFILE !== undefined) {
|
|
1005
|
-
const value = process.env.SMART_CODING_INCREMENTAL_MEMORY_PROFILE;
|
|
1006
|
-
if (value === 'true' || value === 'false') {
|
|
1007
|
-
config.incrementalMemoryProfile = value === 'true';
|
|
1008
|
-
} else {
|
|
1009
|
-
console.warn(
|
|
1010
|
-
`[Config] Invalid SMART_CODING_INCREMENTAL_MEMORY_PROFILE: ${value}, using default`
|
|
1011
|
-
);
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
if (process.env.SMART_CODING_RECYCLE_SERVER_ON_HIGH_RSS_AFTER_INCREMENTAL !== undefined) {
|
|
1016
|
-
const value = process.env.SMART_CODING_RECYCLE_SERVER_ON_HIGH_RSS_AFTER_INCREMENTAL;
|
|
1017
|
-
if (value === 'true' || value === 'false') {
|
|
1018
|
-
config.recycleServerOnHighRssAfterIncremental = value === 'true';
|
|
1019
|
-
} else {
|
|
1020
|
-
console.warn(
|
|
1021
|
-
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_ON_HIGH_RSS_AFTER_INCREMENTAL: ${value}, using default`
|
|
1022
|
-
);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
if (process.env.SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB !== undefined) {
|
|
1027
|
-
const value = parseInt(process.env.SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB, 10);
|
|
1028
|
-
if (!isNaN(value) && value > 0) {
|
|
1029
|
-
config.recycleServerOnHighRssThresholdMb = value;
|
|
1030
|
-
} else {
|
|
1031
|
-
console.warn(
|
|
1032
|
-
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB: ${process.env.SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB}, using default`
|
|
1033
|
-
);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
if (process.env.SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS !== undefined) {
|
|
1038
|
-
const value = parseInt(process.env.SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS, 10);
|
|
1039
|
-
if (!isNaN(value) && value >= 0) {
|
|
1040
|
-
config.recycleServerOnHighRssCooldownMs = value;
|
|
1041
|
-
} else {
|
|
1042
|
-
console.warn(
|
|
1043
|
-
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS: ${process.env.SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS}, using default`
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
if (process.env.SMART_CODING_RECYCLE_SERVER_DELAY_MS !== undefined) {
|
|
1049
|
-
const value = parseInt(process.env.SMART_CODING_RECYCLE_SERVER_DELAY_MS, 10);
|
|
1050
|
-
if (!isNaN(value) && value >= 0) {
|
|
1051
|
-
config.recycleServerOnHighRssDelayMs = value;
|
|
1052
|
-
} else {
|
|
1053
|
-
console.warn(
|
|
1054
|
-
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_DELAY_MS: ${process.env.SMART_CODING_RECYCLE_SERVER_DELAY_MS}, using default`
|
|
1055
|
-
);
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
if (process.env.SMART_CODING_CONTENT_CACHE_ENTRIES !== undefined) {
|
|
1060
|
-
const value = parseInt(process.env.SMART_CODING_CONTENT_CACHE_ENTRIES, 10);
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
if (process.env.SMART_CODING_INCREMENTAL_MEMORY_PROFILE !== undefined) {
|
|
1065
|
+
const value = process.env.SMART_CODING_INCREMENTAL_MEMORY_PROFILE;
|
|
1066
|
+
if (value === 'true' || value === 'false') {
|
|
1067
|
+
config.incrementalMemoryProfile = value === 'true';
|
|
1068
|
+
} else {
|
|
1069
|
+
console.warn(
|
|
1070
|
+
`[Config] Invalid SMART_CODING_INCREMENTAL_MEMORY_PROFILE: ${value}, using default`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
if (process.env.SMART_CODING_RECYCLE_SERVER_ON_HIGH_RSS_AFTER_INCREMENTAL !== undefined) {
|
|
1076
|
+
const value = process.env.SMART_CODING_RECYCLE_SERVER_ON_HIGH_RSS_AFTER_INCREMENTAL;
|
|
1077
|
+
if (value === 'true' || value === 'false') {
|
|
1078
|
+
config.recycleServerOnHighRssAfterIncremental = value === 'true';
|
|
1079
|
+
} else {
|
|
1080
|
+
console.warn(
|
|
1081
|
+
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_ON_HIGH_RSS_AFTER_INCREMENTAL: ${value}, using default`
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
if (process.env.SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB !== undefined) {
|
|
1087
|
+
const value = parseInt(process.env.SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB, 10);
|
|
1088
|
+
if (!isNaN(value) && value > 0) {
|
|
1089
|
+
config.recycleServerOnHighRssThresholdMb = value;
|
|
1090
|
+
} else {
|
|
1091
|
+
console.warn(
|
|
1092
|
+
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB: ${process.env.SMART_CODING_RECYCLE_SERVER_RSS_THRESHOLD_MB}, using default`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
if (process.env.SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS !== undefined) {
|
|
1098
|
+
const value = parseInt(process.env.SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS, 10);
|
|
1099
|
+
if (!isNaN(value) && value >= 0) {
|
|
1100
|
+
config.recycleServerOnHighRssCooldownMs = value;
|
|
1101
|
+
} else {
|
|
1102
|
+
console.warn(
|
|
1103
|
+
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS: ${process.env.SMART_CODING_RECYCLE_SERVER_COOLDOWN_MS}, using default`
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
if (process.env.SMART_CODING_RECYCLE_SERVER_DELAY_MS !== undefined) {
|
|
1109
|
+
const value = parseInt(process.env.SMART_CODING_RECYCLE_SERVER_DELAY_MS, 10);
|
|
1110
|
+
if (!isNaN(value) && value >= 0) {
|
|
1111
|
+
config.recycleServerOnHighRssDelayMs = value;
|
|
1112
|
+
} else {
|
|
1113
|
+
console.warn(
|
|
1114
|
+
`[Config] Invalid SMART_CODING_RECYCLE_SERVER_DELAY_MS: ${process.env.SMART_CODING_RECYCLE_SERVER_DELAY_MS}, using default`
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
if (process.env.SMART_CODING_CONTENT_CACHE_ENTRIES !== undefined) {
|
|
1120
|
+
const value = parseInt(process.env.SMART_CODING_CONTENT_CACHE_ENTRIES, 10);
|
|
1061
1121
|
if (!isNaN(value) && value >= 0 && value <= 10000) {
|
|
1062
1122
|
config.contentCacheEntries = value;
|
|
1063
1123
|
} else {
|
|
@@ -1354,9 +1414,9 @@ export async function loadConfig(workspaceDir = null) {
|
|
|
1354
1414
|
}
|
|
1355
1415
|
}
|
|
1356
1416
|
|
|
1357
|
-
if (
|
|
1358
|
-
config.embeddingProcessGcMaxRequestsWithoutCollection !== null &&
|
|
1359
|
-
config.embeddingProcessGcMaxRequestsWithoutCollection !== undefined
|
|
1417
|
+
if (
|
|
1418
|
+
config.embeddingProcessGcMaxRequestsWithoutCollection !== null &&
|
|
1419
|
+
config.embeddingProcessGcMaxRequestsWithoutCollection !== undefined
|
|
1360
1420
|
) {
|
|
1361
1421
|
const value = parseInt(config.embeddingProcessGcMaxRequestsWithoutCollection, 10);
|
|
1362
1422
|
if (!isNaN(value) && value > 0) {
|
|
@@ -1365,14 +1425,14 @@ export async function loadConfig(workspaceDir = null) {
|
|
|
1365
1425
|
console.warn(
|
|
1366
1426
|
`[Config] Invalid embeddingProcessGcMaxRequestsWithoutCollection: ${config.embeddingProcessGcMaxRequestsWithoutCollection}, using default`
|
|
1367
1427
|
);
|
|
1368
|
-
config.embeddingProcessGcMaxRequestsWithoutCollection =
|
|
1369
|
-
DEFAULT_CONFIG.embeddingProcessGcMaxRequestsWithoutCollection;
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
syncAllNamespaces(config);
|
|
1374
|
-
return config;
|
|
1375
|
-
}
|
|
1428
|
+
config.embeddingProcessGcMaxRequestsWithoutCollection =
|
|
1429
|
+
DEFAULT_CONFIG.embeddingProcessGcMaxRequestsWithoutCollection;
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
syncAllNamespaces(config);
|
|
1434
|
+
return config;
|
|
1435
|
+
}
|
|
1376
1436
|
|
|
1377
1437
|
/**
|
|
1378
1438
|
* Get platform-specific global cache directory
|