magector 2.1.1 → 2.1.3
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/package.json +5 -5
- package/src/mcp-server.js +71 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magector",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Semantic code search for Magento 2 — index, search, MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/mcp-server.js",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"ruvector": "^0.1.96"
|
|
40
40
|
},
|
|
41
41
|
"optionalDependencies": {
|
|
42
|
-
"@magector/cli-darwin-arm64": "2.1.
|
|
43
|
-
"@magector/cli-linux-x64": "2.1.
|
|
44
|
-
"@magector/cli-linux-arm64": "2.1.
|
|
45
|
-
"@magector/cli-win32-x64": "2.1.
|
|
42
|
+
"@magector/cli-darwin-arm64": "2.1.3",
|
|
43
|
+
"@magector/cli-linux-x64": "2.1.3",
|
|
44
|
+
"@magector/cli-linux-arm64": "2.1.3",
|
|
45
|
+
"@magector/cli-win32-x64": "2.1.3"
|
|
46
46
|
},
|
|
47
47
|
"keywords": [
|
|
48
48
|
"magento",
|
package/src/mcp-server.js
CHANGED
|
@@ -121,8 +121,14 @@ function extractJson(stdout) {
|
|
|
121
121
|
}
|
|
122
122
|
// Fallback: try parsing the entire output (handles multi-line JSON)
|
|
123
123
|
// Strip lines that look like tracing (start with ANSI escape or timestamp bracket)
|
|
124
|
+
// Also skip non-JSON prefix lines (e.g. "setting number of points 50000" from HNSW)
|
|
125
|
+
const logLineRe = /^\s*(\x1b\[|\[[\d\-T:.Z]+)/;
|
|
126
|
+
const jsonStartRe = /^\s*[\[{"\-0-9tfn]/;
|
|
127
|
+
let startIdx = lines.findIndex(l => l.trim() && !logLineRe.test(l) && jsonStartRe.test(l));
|
|
128
|
+
if (startIdx < 0) startIdx = 0;
|
|
124
129
|
const cleaned = lines
|
|
125
|
-
.
|
|
130
|
+
.slice(startIdx)
|
|
131
|
+
.filter(l => !logLineRe.test(l) && l.trim())
|
|
126
132
|
.join('\n')
|
|
127
133
|
.trim();
|
|
128
134
|
if (cleaned) {
|
|
@@ -135,6 +141,7 @@ function extractJson(stdout) {
|
|
|
135
141
|
// Track the serve process PID to clean up orphans on restart.
|
|
136
142
|
|
|
137
143
|
const PID_PATH = path.join(config.magentoRoot, '.magector', 'serve.pid');
|
|
144
|
+
const REINDEX_PID_PATH = path.join(config.magentoRoot, '.magector', 'reindex.pid');
|
|
138
145
|
|
|
139
146
|
/**
|
|
140
147
|
* Write the serve process PID to disk so future instances can clean up orphans.
|
|
@@ -147,6 +154,32 @@ function removePidFile() {
|
|
|
147
154
|
try { if (existsSync(PID_PATH)) unlinkSync(PID_PATH); } catch {}
|
|
148
155
|
}
|
|
149
156
|
|
|
157
|
+
function writeReindexPidFile(pid) {
|
|
158
|
+
try { writeFileSync(REINDEX_PID_PATH, String(pid)); } catch {}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function removeReindexPidFile() {
|
|
162
|
+
try { if (existsSync(REINDEX_PID_PATH)) unlinkSync(REINDEX_PID_PATH); } catch {}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Check if another reindex process is already running (from another MCP instance).
|
|
167
|
+
* Returns the PID if alive, null otherwise.
|
|
168
|
+
*/
|
|
169
|
+
function getRunningReindexPid() {
|
|
170
|
+
try {
|
|
171
|
+
if (!existsSync(REINDEX_PID_PATH)) return null;
|
|
172
|
+
const pid = parseInt(readFileSync(REINDEX_PID_PATH, 'utf-8').trim(), 10);
|
|
173
|
+
if (!pid || isNaN(pid)) return null;
|
|
174
|
+
process.kill(pid, 0); // signal 0 = existence check
|
|
175
|
+
return pid;
|
|
176
|
+
} catch {
|
|
177
|
+
// Process doesn't exist or PID file unreadable — clean up
|
|
178
|
+
removeReindexPidFile();
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
150
183
|
/**
|
|
151
184
|
* Kill any stale serve process from a previous MCP server instance.
|
|
152
185
|
* This handles the common case where the MCP server was killed without
|
|
@@ -223,6 +256,27 @@ function checkDbFormat() {
|
|
|
223
256
|
*/
|
|
224
257
|
function startBackgroundReindex() {
|
|
225
258
|
if (reindexInProgress) return;
|
|
259
|
+
|
|
260
|
+
// Check if another MCP instance is already running a reindex
|
|
261
|
+
const existingPid = getRunningReindexPid();
|
|
262
|
+
if (existingPid) {
|
|
263
|
+
logToFile('INFO', `Reindex already running in another process (PID ${existingPid}) — skipping`);
|
|
264
|
+
console.error(`Reindex already running (PID ${existingPid}) — skipping`);
|
|
265
|
+
reindexInProgress = true; // mark locally so tools know
|
|
266
|
+
// Poll the external process and react when it finishes
|
|
267
|
+
const pollInterval = setInterval(() => {
|
|
268
|
+
if (!getRunningReindexPid()) {
|
|
269
|
+
clearInterval(pollInterval);
|
|
270
|
+
reindexInProgress = false;
|
|
271
|
+
logToFile('INFO', 'External reindex finished. Restarting serve process.');
|
|
272
|
+
if (serveProcess) serveProcess.kill();
|
|
273
|
+
searchCache.clear();
|
|
274
|
+
startServeProcess();
|
|
275
|
+
}
|
|
276
|
+
}, 10000);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
226
280
|
if (!config.magentoRoot || !existsSync(config.magentoRoot)) {
|
|
227
281
|
const msg = 'Cannot auto-reindex: MAGENTO_ROOT not set or not found';
|
|
228
282
|
console.error(msg);
|
|
@@ -263,6 +317,9 @@ function startBackgroundReindex() {
|
|
|
263
317
|
env: rustEnv,
|
|
264
318
|
});
|
|
265
319
|
|
|
320
|
+
// Write PID file so other MCP instances know a reindex is running
|
|
321
|
+
writeReindexPidFile(reindexProcess.pid);
|
|
322
|
+
|
|
266
323
|
reindexProcess.stdout.on('data', (d) => {
|
|
267
324
|
const text = d.toString().replace(/\x1b\[[0-9;]*m/g, '').trim();
|
|
268
325
|
if (text) logToFile('INDEX', text);
|
|
@@ -275,6 +332,7 @@ function startBackgroundReindex() {
|
|
|
275
332
|
reindexProcess.on('exit', (code) => {
|
|
276
333
|
reindexInProgress = false;
|
|
277
334
|
reindexProcess = null;
|
|
335
|
+
removeReindexPidFile();
|
|
278
336
|
if (code === 0) {
|
|
279
337
|
// Atomic swap: old → .bak, new → current
|
|
280
338
|
try {
|
|
@@ -305,6 +363,7 @@ function startBackgroundReindex() {
|
|
|
305
363
|
reindexProcess.on('error', (err) => {
|
|
306
364
|
reindexInProgress = false;
|
|
307
365
|
reindexProcess = null;
|
|
366
|
+
removeReindexPidFile();
|
|
308
367
|
logToFile('ERR', `Background re-index error: ${err.message}`);
|
|
309
368
|
console.error(`Background re-index error: ${err.message}`);
|
|
310
369
|
});
|
|
@@ -500,7 +559,8 @@ async function rustSearchAsync(query, limit = 10) {
|
|
|
500
559
|
const cacheKey = `${query}|${limit}`;
|
|
501
560
|
if (searchCache.has(cacheKey)) {
|
|
502
561
|
logToFile('CACHE', `HIT: "${query}" (limit=${limit})`);
|
|
503
|
-
|
|
562
|
+
const cached = searchCache.get(cacheKey);
|
|
563
|
+
return Array.isArray(cached) ? cached : [];
|
|
504
564
|
}
|
|
505
565
|
|
|
506
566
|
// Wait for serve process if it's starting up but not yet ready
|
|
@@ -513,7 +573,7 @@ async function rustSearchAsync(query, limit = 10) {
|
|
|
513
573
|
if (serveProcess && serveReady) {
|
|
514
574
|
try {
|
|
515
575
|
const resp = await serveQuery('search', { query, limit });
|
|
516
|
-
if (resp.ok && resp.data) {
|
|
576
|
+
if (resp.ok && Array.isArray(resp.data)) {
|
|
517
577
|
cacheSet(cacheKey, resp.data);
|
|
518
578
|
return resp.data;
|
|
519
579
|
}
|
|
@@ -524,7 +584,13 @@ async function rustSearchAsync(query, limit = 10) {
|
|
|
524
584
|
|
|
525
585
|
// Fallback: cold-start execFileSync
|
|
526
586
|
logToFile('INFO', `Using execFileSync fallback for search: "${query}"`);
|
|
527
|
-
|
|
587
|
+
try {
|
|
588
|
+
const result = rustSearchSync(query, limit);
|
|
589
|
+
return Array.isArray(result) ? result : [];
|
|
590
|
+
} catch (err) {
|
|
591
|
+
logToFile('WARN', `execFileSync fallback failed: ${err.message}`);
|
|
592
|
+
return [];
|
|
593
|
+
}
|
|
528
594
|
}
|
|
529
595
|
|
|
530
596
|
function rustSearchSync(query, limit = 10) {
|
|
@@ -3189,6 +3255,7 @@ function cleanup(reason) {
|
|
|
3189
3255
|
reindexProcess = null;
|
|
3190
3256
|
}
|
|
3191
3257
|
removePidFile();
|
|
3258
|
+
removeReindexPidFile();
|
|
3192
3259
|
}
|
|
3193
3260
|
|
|
3194
3261
|
process.on('exit', () => cleanup('process exit'));
|