@softerist/heuristic-mcp 2.1.43 β†’ 2.1.45

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 CHANGED
@@ -1,372 +1,117 @@
1
- # Heuristic MCP
1
+ # Heuristic MCP Server 🧠
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@softerist/heuristic-mcp.svg)](https://www.npmjs.com/package/@softerist/heuristic-mcp)
4
- [![npm downloads](https://img.shields.io/npm/dm/@softerist/heuristic-mcp.svg)](https://www.npmjs.com/package/@softerist/heuristic-mcp)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
- [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)](https://nodejs.org/)
3
+ > An **enhanced** MCP server for your codebase. It provides **intelligent semantic search**, **Find-Similar-Code**, **Recency Ranking**, and **Smart Chunking**.
4
+ > Optimized for Antigravity, Cursor, and Claude Desktop.
7
5
 
8
- An extensible Model Context Protocol (MCP) server that provides intelligent semantic code search for AI assistants. Built with local AI models (RAG), inspired by Cursor's semantic search research.
9
-
10
- ## What This Does
11
-
12
- AI coding assistants work better when they can find relevant code quickly. Traditional keyword search falls short - if you ask "where do we handle authentication?" but your code uses "login" and "session", keyword search misses it.
13
-
14
- This MCP server solves that by indexing your codebase with AI embeddings. Your AI assistant can search by meaning instead of exact keywords, finding relevant code even when the terminology differs.
15
-
16
- ## Example: Semantic Search in Action
17
-
18
- **User Query:** "How vector cache working?"
19
-
20
- ### MCP Tool Call
21
-
22
- ```json
23
- {
24
- "maxResults": 5,
25
- "query": "vector store embeddings cache save load"
26
- }
27
- ```
28
-
29
- ### Output
30
-
31
- **Result 1 (Relevance: 72.5%)**
32
-
33
- **File:** `lib/cache.js` **Lines:** 42-59
34
-
35
- ```javascript
36
- }
37
-
38
- const filtered = rawVectorStore.length - this.vectorStore.length;
39
- if (filtered > 0) {
40
- console.error(`[Cache] Filtered ${filtered} outdated cache entries`);
41
- }
42
- console.error(`[Cache] Loaded ${this.vectorStore.length} cached embeddings`);
43
- ```
44
-
45
- Here's how the **vector cache** works:
46
-
47
- ### Overview
48
-
49
- The cache system (`lib/cache.js`) stores two things:
50
-
51
- 1. **Vector embeddings** - AI-generated vectors for each code chunk
52
- 2. **File hashes** - MD5 hashes to detect file changes
53
-
54
- ## Why Heuristic MCP is Useful
55
-
56
- Yes, absolutely. The **Heuristic MCP** is highly effective because it bridges the gap between "having access to files" and "understanding the codebase." Here is why it is useful:
57
-
58
- ### 1. It Solved the "Needle in a Haystack" Problem
59
-
60
- To answer your technical questions, I didn't have to manually browse 15 files or run generic `grep` commands.
61
-
62
- - **Without MCP:** I would have listed directories, guessed `lib/utils.js` might be relevant, read the whole file, then checked `index.js`, etc.
63
- - **With MCP:** I asked *"how does chunking work"* and it instantly returned lines 91-108 of `lib/utils.js`. It acted like a senior engineer pointing me to the exact lines of code.
64
-
65
- ### 2. It Finds "Concepts," Not Just Words
66
-
67
- Standard tools like `grep` only find exact matches.
68
-
69
- - If I searched for "authentication" using `grep`, I might miss a function named `verifyUserCredentials`.
70
- - The **Heuristic MCP** links these concepts. In the test script I analyzed earlier, `authentication` correctly matched with `credentials` because of the vector similarity.
71
-
72
- ### 3. It Finds "Similar Code"
73
-
74
- AI agents have a limited memory (context window).
75
-
76
- - Instead of reading **every file** to understand the project (which wastes thousands of tokens), the MCP lets me retrieve **only the 5-10 relevant snippets**. This leaves more room for complex reasoning and generating code.
77
-
78
- ### 4. It Is Fast & Private
79
-
80
- Since it runs the **Local LLM** (Xenova) directly on your machine:
81
-
82
- - **Latency is near-zero** (<50ms).
83
- - **Privacy is 100%**: Your source code never leaves your laptop to be indexed by an external cloud service.
84
-
85
- ### Verdict
86
-
87
- For a developer (or an AI agent) working on a confusing or large project, this tool is a massive productivity booster. It essentially turns the entire codebase into a searchable database of knowledge.
88
-
89
- ## How This is Different
90
-
91
- Most MCP servers and RAG tools are "naive"β€”they just embed code chunks and run a vector search. **Heuristic MCP** is different because it adds **deterministic intelligence** on top of AI:
92
-
93
- | Feature | Generic MCP / RAG Tool | Heuristic MCP |
94
- | :- | :- | :- |
95
- | **Ranking** | Pure similarity score | Similarity + **Call Graph Proximity** + **Recency Boost** |
96
- | **Logic** | "Is this text similar?" | "Is this similar, AND used by this function, AND active?" |
97
- | **Refactoring** | N/A | **`find_similar_code`** tool to detect duplicates |
98
- | **Tuning** | Static (hardcoded) | **Runtime Config** (adjust ANN parameters on the fly) |
99
-
100
- ### Comparison to Cursor
101
-
102
- [Cursor](https://cursor.sh) is an excellent AI editor with built-in codebase indexing.
103
-
104
- - **Cursor** is an *Editor*: You must use their IDE to get the features.
105
- - **Heuristic MCP** is a *Protocol*: It brings Cursor-like intelligence to **any** tool (Claude Desktop, multiple IDEs, agentic workflows) without locking you into a specific editor.
106
- - **Transparency**: This is open-source. You know exactly how your code is indexed and where the data lives (locally).
107
-
108
- ## Performance
6
+ ---
109
7
 
110
- - Pre-indexed embeddings are faster than scanning files at runtime
111
- - Smart project detection skips dependencies automatically (node_modules, vendor, etc.)
112
- - Incremental updates - only re-processes changed files
113
- - Optional ANN search (HNSW) for faster queries on large codebases
8
+ ## πŸš€ Key Features
114
9
 
115
- ## Privacy
10
+ - **Zero-Config Installation**: Automatically detects your IDE (Antigravity, Cursor, Claude) and configures itself.
11
+ - **Smart Indexing**: Automatically identifies your project type (Python, JS, etc.) and ignores irrelevant files.
12
+ - **Robust Caching**: Pre-downloads AI models to avoid network blocks and caches embeddings globally or locally.
13
+ - **Semantic Search**: Finds code by *meaning*, not just keywords (e.g., "auth logic" finds `login.ts`).
14
+ - **Resilient**: Self-healing configuration and automatic recovery from race conditions.
116
15
 
117
- - Everything runs locally on your machine
118
- - Your code never leaves your system
119
- - No API calls to external services
16
+ ---
120
17
 
121
- ## Installation
18
+ ## πŸ“¦ Installation
122
19
 
123
- Install globally via npm:
20
+ To install globally (recommended):
124
21
 
125
22
  ```bash
126
23
  npm install -g @softerist/heuristic-mcp
127
24
  ```
128
25
 
129
- That's it! The installer will automatically detect your IDE (Antigravity, Claude, Cursor) and configure it for you.
26
+ **That's it!**
27
+ - The installer automatically creates the `mcp_config.json` for your IDE.
28
+ - It pre-downloads the AI model (`all-MiniLM-L6-v2`) to your cache.
29
+ - Just **Restart your IDE** (or Reload Window) to start using it.
130
30
 
131
- | IDE | OS | Config Path |
132
- | -------------------- | ------- | ----------------------------------------------------------------- |
133
- | **Claude Desktop** | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
134
- | **Claude Desktop** | Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
135
- | **Cascade (Cursor)** | All | Configured via UI Settings > Features > MCP |
136
- | **Antigravity** | macOS | `~/.gemini/antigravity/mcp_config.json` |
137
- | **Antigravity** | Windows | `%USERPROFILE%\.gemini\antigravity\mcp_config.json` |
31
+ ---
138
32
 
139
- Add the server configuration to the `mcpServers` object in your config file:
33
+ ## πŸ› οΈ CLI Commands
140
34
 
141
- ### Option 1: Specific Project (Recommended)
35
+ The `heuristic-mcp` tool is your control center.
142
36
 
143
- ```json
144
- {
145
- "mcpServers": {
146
- "heuristic-mcp": {
147
- "command": "heuristic-mcp",
148
- "args": ["--workspace", "/absolute/path/to/your/project"]
149
- }
150
- }
151
- }
37
+ ### Check Health & Status (Snapshots)
38
+ Use this to verify if the server is running and check indexing progress.
39
+ ```bash
40
+ heuristic-mcp --status
152
41
  ```
42
+ **Output:**
43
+ - 🟒 **Server Status**: Shows if the background process is running (PID).
44
+ - πŸ“ **Cache Info**: Shows number of files indexed, chunks, and "Initializing..." status if still working.
45
+ - βš™οΈ **Config Check**: Validates that your IDE config files exist.
153
46
 
154
- ### Option 2: Multi-Project Support
155
-
156
- ```json
157
- {
158
- "mcpServers": {
159
- "heuristic-mcp-project-a": {
160
- "command": "heuristic-mcp",
161
- "args": ["--workspace", "/path/to/project-a"]
162
- },
163
- "heuristic-mcp-project-b": {
164
- "command": "heuristic-mcp",
165
- "args": ["--workspace", "/path/to/project-b"]
166
- }
167
- }
168
- }
47
+ ### Live Logs (Streaming)
48
+ Use this to watch the server's brain at work in real-time.
49
+ ```bash
50
+ heuristic-mcp --logs
169
51
  ```
52
+ **Output:**
53
+ - Streams live logs from the server.
54
+ - Shows file indexing progress (`Processing 100/236 files...`).
55
+ - Useful for debugging why a specific file isn't being indexed.
170
56
 
171
- ### Troubleshooting
172
-
173
- If for some reason the server isn't detected automatically, you can trigger the registration manually:
174
-
57
+ ### Manual Registration
58
+ If you need to re-register the server manually:
175
59
  ```bash
176
60
  heuristic-mcp --register
177
61
  ```
178
62
 
179
- ### Starting and Stopping
180
-
181
- If you need to restart the server or kill a zombie process:
182
-
183
- **Stop the server:**
184
-
63
+ ### Stop Server
64
+ Forcefully stop all running instances:
185
65
  ```bash
186
66
  heuristic-mcp --stop
187
67
  ```
188
68
 
189
- *(This kills any running instances of the server)*
190
-
191
- **Start/Enable the server:**
192
-
69
+ ### Clear Cache
70
+ Wipe the index to force a complete rebuild:
193
71
  ```bash
194
- heuristic-mcp --start
72
+ heuristic-mcp --clean
195
73
  ```
196
74
 
197
- *(This re-runs the configuration step to ensure it is enabled in your IDE)*
198
-
199
- **Check Status:**
200
-
201
- ```bash
202
- heuristic-mcp --status
203
- ```
204
-
205
- *(Shows if the server is running and its PID)*
206
-
207
75
  ---
208
76
 
209
- ## Environment Variables
210
-
211
- Override configuration settings via environment variables in your MCP config:
77
+ ## βš™οΈ Configuration (`config.json`)
212
78
 
213
- | Variable | Type | Default | Description |
214
- | -------------------------------- | ------- | ------------------------- | ------------------------------------- |
215
- | `SMART_CODING_VERBOSE` | boolean | `false` | Enable detailed logging |
216
- | `SMART_CODING_BATCH_SIZE` | number | `100` | Files to process in parallel |
217
- | `SMART_CODING_MAX_FILE_SIZE` | number | `1048576` | Max file size in bytes (1MB) |
218
- | `SMART_CODING_CHUNK_SIZE` | number | `25` | Lines of code per chunk |
219
- | `SMART_CODING_MAX_RESULTS` | number | `5` | Max search results |
220
- | `SMART_CODING_SMART_INDEXING` | boolean | `true` | Enable smart project detection |
221
- | `SMART_CODING_WATCH_FILES` | boolean | `false` | Enable file watching for auto-reindex |
222
- | `SMART_CODING_SEMANTIC_WEIGHT` | number | `0.7` | Weight for semantic similarity (0-1) |
223
- | `SMART_CODING_EXACT_MATCH_BOOST` | number | `1.5` | Boost for exact text matches |
224
- | `SMART_CODING_RECENCY_BOOST` | number | `0.1` | Boost for recently modified files |
225
- | `SMART_CODING_RECENCY_DECAY_DAYS`| number | `30` | Days until recency boost fades to 0 |
226
- | `SMART_CODING_EMBEDDING_MODEL` | string | `Xenova/all-MiniLM-L6-v2` | AI embedding model to use |
227
- | `SMART_CODING_WORKER_THREADS` | string | `auto` | Worker threads (`auto` or 1-32) |
228
- | `SMART_CODING_ANN_ENABLED` | boolean | `true` | Enable ANN search (HNSW) |
229
-
230
- **ANN note**: HNSW support uses optional `hnswlib-node`. If it isn't installed, the server falls back to exact (linear) search automatically.
231
-
232
- **Example with environment variables:**
79
+ You can customize behavior by creating a `config.json` in your project root or `~/.heuristic-mcp/config.json`.
233
80
 
234
81
  ```json
235
82
  {
236
- "mcpServers": {
237
- "heuristic-mcp": {
238
- "command": "heuristic-mcp",
239
- "args": ["--workspace", "/path/to/project"],
240
- "env": {
241
- "SMART_CODING_VERBOSE": "true",
242
- "SMART_CODING_RECENCY_BOOST": "0.2"
243
- }
244
- }
245
- }
246
- }
247
- ```
248
-
249
- **Note**: The server starts instantly and indexes in the background, so your IDE won't be blocked waiting for indexing to complete.
250
-
251
- ## Available Tools
252
-
253
- **semantic_search** - Find code by meaning
254
-
255
- ```
256
- Query: "Where do we validate user input?"
257
- Returns: Relevant validation code with file paths and line numbers
258
- ```
259
-
260
- **find_similar_code** - Find duplicates or patterns
261
-
262
- ```
263
- Input: A code snippet (paste the code directly)
264
- Returns: Other code in the project that looks or functions similarly
265
- ```
266
-
267
- **index_codebase** - Manually trigger reindexing
268
-
269
- ```
270
- Use after major refactoring or branch switches
271
- ```
272
-
273
- **clear_cache** - Reset the embeddings cache
274
-
275
- ```
276
- Useful when cache becomes corrupted or outdated
277
- ```
278
-
279
- ## How It Works
280
-
281
- The server indexes your code in four steps:
282
-
283
- 1. **Discovery**: Scans your project for source files (smartly ignoring build/vendor folders)
284
- 2. **Chunking**: Breaks code into meaningful pieces (respecting function boundaries)
285
- 3. **Embedding**: Converts each chunk to a vector using a local AI model
286
- 4. **Storage**: Saves embeddings to `.smart-coding-cache/` for fast startup
287
-
288
- When you search, your query is converted to the same vector format. We use a **hybrid ranking algorithm** that combines:
289
-
290
- - **Semantic Similarity** (cosine similarity of vectors)
291
- - **Exact Keyword Matching** (BM25-inspired boost)
292
- - **Recency Boosting** (favoring files you're actively working on)
293
-
294
- ## Examples
295
-
296
- **Natural language search:**
297
-
298
- Query: "How do we handle cache persistence?"
299
-
300
- Result:
301
-
302
- ```javascript
303
- // lib/cache.js (Relevance: 38.2%)
304
- async save() {
305
- await fs.writeFile(cacheFile, JSON.stringify(this.vectorStore));
306
- await fs.writeFile(hashFile, JSON.stringify(this.fileHashes));
83
+ "excludePatterns": ["**/legacy-code/**", "**/*.test.ts"],
84
+ "smartIndexing": true,
85
+ "embeddingModel": "Xenova/all-MiniLM-L6-v2",
86
+ "workerThreads": "auto"
307
87
  }
308
88
  ```
309
89
 
310
- **Typo tolerance:**
311
-
312
- Query: "embeding modle initializashun"
90
+ ### Environment Variables
91
+ Override settings on the fly:
92
+ - `SMART_CODING_VERBOSE=true`: Enable debug logs.
93
+ - `SMART_CODING_WORKER_THREADS=4`: Force specific thread count.
313
94
 
314
- Still finds embedding model initialization code despite multiple typos.
315
-
316
- **Conceptual search:**
317
-
318
- Query: "error handling and exceptions"
319
-
320
- Finds all try/catch blocks and error handling patterns.
321
-
322
- ## Technical Details
323
-
324
- **Embedding Model**: all-MiniLM-L6-v2 via transformers.js
325
-
326
- - Fast inference (CPU-friendly)
327
- - Small model size (~100MB)
328
- - Good accuracy for code search
329
-
330
- **Vector Similarity**: Cosine similarity
331
-
332
- - Efficient comparison of embeddings
333
- - Normalized vectors for consistent scoring
334
-
335
- **Hybrid Scoring**: Combines semantic similarity with exact text matching
336
-
337
- - Semantic weight: 0.7 (configurable)
338
- - Exact match boost: 1.5x (configurable)
339
-
340
- ## Research Background
341
-
342
- This project builds on research from Cursor showing that semantic search improves AI coding agent performance by 12.5% on average across question-answering tasks. The key insight is that AI assistants benefit more from relevant context than from large amounts of context.
343
-
344
- See: <https://cursor.com/blog/semsearch>
95
+ ---
345
96
 
346
- ## Acknowledgements
97
+ ## πŸ”§ Troubleshooting
347
98
 
348
- This project is a fork of [smart-coding-mcp](https://github.com/omar-haris/smart-coding-mcp) by [Omar Haris](https://www.linkedin.com/in/omarharis/). We thank him for the original implementation.
99
+ **"Server isn't starting"**
100
+ 1. Run `heuristic-mcp --status` to see if config files exist.
101
+ 2. Run `heuristic-mcp --logs` and then Reload Window to see startup errors.
349
102
 
350
- ## License
103
+ **"Search returns no results"**
104
+ - Check `heuristic-mcp --status`. Does it say "Indexing: βœ… COMPLETE"?
105
+ - If it says "Initializing...", wait a moment.
106
+ - If it says "NO FILES", check your `.gitignore` or `excludePatterns`.
351
107
 
352
- MIT License
108
+ **"Network error downloading model"**
109
+ - We pre-download models during `npm install`. Try running `npm install -g @softerist/heuristic-mcp` again to retry the download.
353
110
 
354
- Copyright (c) 2025 Softerist
111
+ ---
355
112
 
356
- Permission is hereby granted, free of charge, to any person obtaining a copy
357
- of this software and associated documentation files (the "Software"), to deal
358
- in the Software without restriction, including without limitation the rights
359
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
360
- copies of the Software, and to permit persons to whom the Software is
361
- furnished to do so, subject to the following conditions:
113
+ ## 🀝 Contributing
362
114
 
363
- The above copyright notice and this permission notice shall be included in all
364
- copies or substantial portions of the Software.
115
+ Fork it, fix it, ship it. Open a PR!
365
116
 
366
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
367
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
368
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
369
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
370
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
371
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
372
- SOFTWARE.
117
+ License: MIT
@@ -150,17 +150,21 @@ export class CodebaseIndexer {
150
150
  }
151
151
  } catch (err) {
152
152
  console.error(`[Indexer] Worker initialization failed: ${err.message}, falling back to single-threaded`);
153
- this.terminateWorkers();
153
+ await this.terminateWorkers();
154
154
  }
155
155
  }
156
156
 
157
157
  /**
158
158
  * Terminate all worker threads
159
159
  */
160
- terminateWorkers() {
161
- for (const worker of this.workers) {
162
- worker.postMessage({ type: "shutdown" });
163
- }
160
+ async terminateWorkers() {
161
+ const terminations = this.workers.map((worker) => {
162
+ try {
163
+ worker.postMessage({ type: "shutdown" });
164
+ } catch {}
165
+ return worker.terminate().catch(() => null);
166
+ });
167
+ await Promise.all(terminations);
164
168
  this.workers = [];
165
169
  this.workerReady = [];
166
170
  }
@@ -730,7 +734,7 @@ export class CodebaseIndexer {
730
734
 
731
735
  // Cleanup workers
732
736
  if (useWorkers) {
733
- this.terminateWorkers();
737
+ await this.terminateWorkers();
734
738
  }
735
739
 
736
740
  const totalTime = ((Date.now() - totalStartTime) / 1000).toFixed(1);
package/index.js CHANGED
@@ -248,6 +248,11 @@ process.on('SIGINT', async () => {
248
248
  console.error("[Server] File watcher stopped");
249
249
  }
250
250
 
251
+ // Terminate workers to avoid native crashes on exit
252
+ if (indexer && indexer.terminateWorkers) {
253
+ await indexer.terminateWorkers();
254
+ }
255
+
251
256
  // Save cache
252
257
  if (cache) {
253
258
  await cache.save();
@@ -267,6 +272,11 @@ process.on('SIGTERM', async () => {
267
272
  console.error("[Server] File watcher stopped");
268
273
  }
269
274
 
275
+ // Terminate workers to avoid native crashes on exit
276
+ if (indexer && indexer.terminateWorkers) {
277
+ await indexer.terminateWorkers();
278
+ }
279
+
270
280
  // Save cache
271
281
  if (cache) {
272
282
  await cache.save();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softerist/heuristic-mcp",
3
- "version": "2.1.43",
3
+ "version": "2.1.45",
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
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,18 +1,19 @@
1
1
 
2
- import { pipeline, env } from '@xenova/transformers';
3
2
  import path from 'path';
4
- import fs from 'fs';
5
3
  import os from 'os';
6
4
  import { getGlobalCacheDir } from '../lib/config.js';
7
5
 
8
- // Force cache directory to global location
9
- const globalCacheDir = path.join(getGlobalCacheDir(), 'xenova');
10
- env.cacheDir = globalCacheDir;
11
-
12
- console.log(`[Model Setup] Pre-caching model to: ${globalCacheDir}`);
13
-
14
6
  async function downloadModel() {
7
+ const globalCacheDir = path.join(getGlobalCacheDir(), 'xenova');
8
+
15
9
  try {
10
+ const transformers = await import('@xenova/transformers');
11
+ const { pipeline, env } = transformers;
12
+
13
+ // Force cache directory to global location
14
+ env.cacheDir = globalCacheDir;
15
+
16
+ console.log(`[Model Setup] Pre-caching model to: ${globalCacheDir}`);
16
17
  // Check if network is available by pinging HF (simple check)
17
18
  // Actually, pipeline() will fail fast if network is down
18
19
  console.log(`[Model Setup] Downloading 'Xenova/all-MiniLM-L6-v2'...`);
@@ -22,8 +23,13 @@ async function downloadModel() {
22
23
 
23
24
  console.log(`[Model Setup] βœ… Model cached successfully!`);
24
25
  } catch (error) {
26
+ if (error && error.code === 'ERR_MODULE_NOT_FOUND') {
27
+ console.warn('[Model Setup] ⚠️ Transformers not available yet; skipping model pre-download.');
28
+ console.warn('[Model Setup] This is okay! The server will attempt to download it when started.');
29
+ return;
30
+ }
25
31
  console.warn(`[Model Setup] ⚠️ Constructive warning: Failed to pre-download model.`);
26
- console.warn(`[Model Setup] This is okay! The server will attempt to download it when started.`);
32
+ console.warn('[Model Setup] This is okay! The server will attempt to download it when started.');
27
33
  console.warn(`[Model Setup] Error details: ${error.message}`);
28
34
  // Don't fail the install, just warn
29
35
  }