magector 2.1.2 → 2.1.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 (2) hide show
  1. package/package.json +5 -5
  2. package/src/mcp-server.js +65 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magector",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
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.2",
43
- "@magector/cli-linux-x64": "2.1.2",
44
- "@magector/cli-linux-arm64": "2.1.2",
45
- "@magector/cli-win32-x64": "2.1.2"
42
+ "@magector/cli-darwin-arm64": "2.1.4",
43
+ "@magector/cli-linux-x64": "2.1.4",
44
+ "@magector/cli-linux-arm64": "2.1.4",
45
+ "@magector/cli-win32-x64": "2.1.4"
46
46
  },
47
47
  "keywords": [
48
48
  "magento",
package/src/mcp-server.js CHANGED
@@ -81,8 +81,8 @@ function logToFile(level, message) {
81
81
  }
82
82
  }
83
83
 
84
- // Initialize log file on startup
85
- try { writeFileSync(LOG_PATH, `[${new Date().toISOString()}] [INFO] Magector MCP server starting\n`); } catch {}
84
+ // Initialize log on startup — append to preserve history across MCP restarts
85
+ try { appendFileSync(LOG_PATH, `\n[${new Date().toISOString()}] [INFO] ════ Magector MCP server starting ════\n`); } catch {}
86
86
 
87
87
  // Log resolved configuration so the log file is self-contained for debugging
88
88
  logToFile('INFO', `Config: MAGENTO_ROOT=${config.magentoRoot}`);
@@ -141,6 +141,7 @@ function extractJson(stdout) {
141
141
  // Track the serve process PID to clean up orphans on restart.
142
142
 
143
143
  const PID_PATH = path.join(config.magentoRoot, '.magector', 'serve.pid');
144
+ const REINDEX_PID_PATH = path.join(config.magentoRoot, '.magector', 'reindex.pid');
144
145
 
145
146
  /**
146
147
  * Write the serve process PID to disk so future instances can clean up orphans.
@@ -153,6 +154,32 @@ function removePidFile() {
153
154
  try { if (existsSync(PID_PATH)) unlinkSync(PID_PATH); } catch {}
154
155
  }
155
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
+
156
183
  /**
157
184
  * Kill any stale serve process from a previous MCP server instance.
158
185
  * This handles the common case where the MCP server was killed without
@@ -229,6 +256,27 @@ function checkDbFormat() {
229
256
  */
230
257
  function startBackgroundReindex() {
231
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
+
232
280
  if (!config.magentoRoot || !existsSync(config.magentoRoot)) {
233
281
  const msg = 'Cannot auto-reindex: MAGENTO_ROOT not set or not found';
234
282
  console.error(msg);
@@ -269,18 +317,27 @@ function startBackgroundReindex() {
269
317
  env: rustEnv,
270
318
  });
271
319
 
272
- reindexProcess.stdout.on('data', (d) => {
273
- const text = d.toString().replace(/\x1b\[[0-9;]*m/g, '').trim();
320
+ // Write PID file so other MCP instances know a reindex is running
321
+ writeReindexPidFile(reindexProcess.pid);
322
+
323
+ // Log stdout/stderr line-by-line using readline to avoid buffering issues.
324
+ // Without this, Rust tracing output accumulates in pipe buffers and progress
325
+ // entries arrive in large chunks instead of in real time.
326
+ const indexStdout = createInterface({ input: reindexProcess.stdout });
327
+ const indexStderr = createInterface({ input: reindexProcess.stderr });
328
+ indexStdout.on('line', (line) => {
329
+ const text = line.replace(/\x1b\[[0-9;]*m/g, '').trim();
274
330
  if (text) logToFile('INDEX', text);
275
331
  });
276
- reindexProcess.stderr.on('data', (d) => {
277
- const text = d.toString().replace(/\x1b\[[0-9;]*m/g, '').trim();
332
+ indexStderr.on('line', (line) => {
333
+ const text = line.replace(/\x1b\[[0-9;]*m/g, '').trim();
278
334
  if (text) logToFile('INDEX', text);
279
335
  });
280
336
 
281
337
  reindexProcess.on('exit', (code) => {
282
338
  reindexInProgress = false;
283
339
  reindexProcess = null;
340
+ removeReindexPidFile();
284
341
  if (code === 0) {
285
342
  // Atomic swap: old → .bak, new → current
286
343
  try {
@@ -311,6 +368,7 @@ function startBackgroundReindex() {
311
368
  reindexProcess.on('error', (err) => {
312
369
  reindexInProgress = false;
313
370
  reindexProcess = null;
371
+ removeReindexPidFile();
314
372
  logToFile('ERR', `Background re-index error: ${err.message}`);
315
373
  console.error(`Background re-index error: ${err.message}`);
316
374
  });
@@ -3202,6 +3260,7 @@ function cleanup(reason) {
3202
3260
  reindexProcess = null;
3203
3261
  }
3204
3262
  removePidFile();
3263
+ removeReindexPidFile();
3205
3264
  }
3206
3265
 
3207
3266
  process.on('exit', () => cleanup('process exit'));