magector 2.16.2 → 2.16.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 +56 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magector",
3
- "version": "2.16.2",
3
+ "version": "2.16.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",
@@ -33,10 +33,10 @@
33
33
  "ruvector": "^0.1.96"
34
34
  },
35
35
  "optionalDependencies": {
36
- "@magector/cli-darwin-arm64": "2.16.2",
37
- "@magector/cli-linux-x64": "2.16.2",
38
- "@magector/cli-linux-arm64": "2.16.2",
39
- "@magector/cli-win32-x64": "2.16.2"
36
+ "@magector/cli-darwin-arm64": "2.16.4",
37
+ "@magector/cli-linux-x64": "2.16.4",
38
+ "@magector/cli-linux-arm64": "2.16.4",
39
+ "@magector/cli-win32-x64": "2.16.4"
40
40
  },
41
41
  "keywords": [
42
42
  "magento",
package/src/mcp-server.js CHANGED
@@ -817,6 +817,8 @@ function startServeProcess() {
817
817
  // First line is ready signal
818
818
  if (parsed.ready) {
819
819
  serveReady = true;
820
+ // Clear stale cache entries — they may contain [] from when index was unavailable
821
+ searchCache.clear();
820
822
  logToFile('INFO', `Serve process ready (PID ${proc.pid})`);
821
823
  if (serveReadyResolve) { serveReadyResolve(true); serveReadyResolve = null; }
822
824
  // Now that serve is up, persist primary lock state to data.db
@@ -952,6 +954,7 @@ function tryConnectSocket() {
952
954
 
953
955
  isSocketClient = true;
954
956
  serveReady = true;
957
+ searchCache.clear(); // clear stale [] entries from before socket was available
955
958
  logToFile('INFO', 'Connected to existing serve process via socket proxy');
956
959
  resolve(true);
957
960
  });
@@ -997,6 +1000,15 @@ async function rustSearchAsync(query, limit = 10) {
997
1000
  await Promise.race([serveReadyPromise, new Promise(r => setTimeout(() => r(false), 10000))]);
998
1001
  }
999
1002
 
1003
+ // Secondary instance: retry socket if not connected (primary may have (re)started serve)
1004
+ if (!serveProcess && !globalServeQuery) {
1005
+ const reconnected = await tryConnectSocket();
1006
+ if (reconnected) {
1007
+ logToFile('INFO', 'rustSearchAsync: reconnected to serve socket');
1008
+ searchCache.clear(); // clear stale empty results before using new serve
1009
+ }
1010
+ }
1011
+
1000
1012
  // Try socket proxy (secondary instance) or local serve process (primary)
1001
1013
  const queryFn = globalServeQuery || ((serveProcess && serveReady) ? serveQuery : null);
1002
1014
  if (queryFn) {
@@ -4492,41 +4504,54 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
4492
4504
  * Returns null when not re-indexing.
4493
4505
  */
4494
4506
  function getReindexWarning() {
4495
- if (!reindexInProgress || !reindexStartTime) return null;
4496
- const elapsedSec = Math.round((Date.now() - reindexStartTime) / 1000);
4497
- const elapsedStr = elapsedSec >= 60
4498
- ? `${Math.floor(elapsedSec / 60)}m ${elapsedSec % 60}s`
4499
- : `${elapsedSec}s`;
4500
-
4501
- let phaseStr, etaStr;
4502
- if (reindexPhase <= 0) {
4503
- phaseStr = 'initializing';
4504
- etaStr = 'est. ~40–70 min total';
4505
- } else if (reindexPhase === 1) {
4506
- const filesStr = reindexTotalFiles > 0 ? ` (${reindexTotalFiles.toLocaleString('en')} files)` : '';
4507
- phaseStr = `phase 1/3: AST parsing${filesStr}`;
4508
- etaStr = 'est. ~13 min for this phase, then ~40–60 min for embeddings';
4509
- } else if (reindexPhase === 2) {
4510
- const itemsStr = reindexItemsToEmbed > 0 ? ` (${reindexItemsToEmbed.toLocaleString('en')} items)` : '';
4511
- phaseStr = `phase 2/3: generating embeddings${itemsStr}`;
4512
- if (reindexPhase2Start && reindexItemsToEmbed > 0) {
4513
- // Empirical rate: ~87k items 45 min on 8-core ONNX. Scale linearly.
4514
- const estimatedTotalSec = Math.round((reindexItemsToEmbed / 87000) * 45 * 60);
4515
- const phase2Elapsed = (Date.now() - reindexPhase2Start) / 1000;
4516
- const remainingSec = Math.max(estimatedTotalSec - phase2Elapsed, 0);
4517
- etaStr = remainingSec > 60
4518
- ? `est. ~${Math.round(remainingSec / 60)} min remaining`
4519
- : 'almost done with embeddings';
4507
+ // Primary instance: use in-memory state (accurate phase + ETA)
4508
+ if (reindexInProgress && reindexStartTime) {
4509
+ const elapsedSec = Math.round((Date.now() - reindexStartTime) / 1000);
4510
+ const elapsedStr = elapsedSec >= 60
4511
+ ? `${Math.floor(elapsedSec / 60)}m ${elapsedSec % 60}s`
4512
+ : `${elapsedSec}s`;
4513
+
4514
+ let phaseStr, etaStr;
4515
+ if (reindexPhase <= 0) {
4516
+ phaseStr = 'initializing';
4517
+ etaStr = 'est. ~40–70 min total';
4518
+ } else if (reindexPhase === 1) {
4519
+ const filesStr = reindexTotalFiles > 0 ? ` (${reindexTotalFiles.toLocaleString('en')} files)` : '';
4520
+ phaseStr = `phase 1/3: AST parsing${filesStr}`;
4521
+ etaStr = 'est. ~1–3 min for this phase, then ~40–60 min for embeddings';
4522
+ } else if (reindexPhase === 2) {
4523
+ const itemsStr = reindexItemsToEmbed > 0 ? ` (${reindexItemsToEmbed.toLocaleString('en')} items)` : '';
4524
+ phaseStr = `phase 2/3: generating embeddings${itemsStr}`;
4525
+ if (reindexPhase2Start && reindexItemsToEmbed > 0) {
4526
+ // Empirical rate: ~87k items 45 min on 8-core ONNX. Scale linearly.
4527
+ const estimatedTotalSec = Math.round((reindexItemsToEmbed / 87000) * 45 * 60);
4528
+ const phase2Elapsed = (Date.now() - reindexPhase2Start) / 1000;
4529
+ const remainingSec = Math.max(estimatedTotalSec - phase2Elapsed, 0);
4530
+ etaStr = remainingSec > 60
4531
+ ? `est. ~${Math.round(remainingSec / 60)} min remaining`
4532
+ : 'almost done with embeddings';
4533
+ } else {
4534
+ etaStr = 'est. 30–60 min for this phase';
4535
+ }
4520
4536
  } else {
4521
- etaStr = 'est. 30–60 min for this phase';
4537
+ phaseStr = 'phase 3/3: building HNSW vector index';
4538
+ etaStr = 'est. ~5–10 min remaining';
4522
4539
  }
4523
- } else {
4524
- phaseStr = 'phase 3/3: building HNSW vector index';
4525
- etaStr = 'est. ~5–10 min remaining';
4540
+
4541
+ return `> **Re-indexing in progress** ${elapsedStr} elapsed, ${phaseStr}. ${etaStr}.\n` +
4542
+ `> Results below use the **previous index** — valid, but may miss recently added files.\n\n`;
4526
4543
  }
4527
4544
 
4528
- return `> **Re-indexing in progress** ${elapsedStr} elapsed, ${phaseStr}. ${etaStr}.\n` +
4529
- `> Results below use the **previous index** — valid, but may miss recently added files.\n\n`;
4545
+ // Secondary instance: detect via PID file (no phase info available)
4546
+ try {
4547
+ const externalPid = getRunningReindexPid();
4548
+ if (externalPid) {
4549
+ return `> ⏳ **Re-indexing in progress** (PID ${externalPid}) — semantic search may return empty results until complete.\n` +
4550
+ `> Grep and filesystem-based tools work normally. Check \`.magector/magector.log\` for progress.\n\n`;
4551
+ }
4552
+ } catch { /* ignore */ }
4553
+
4554
+ return null;
4530
4555
  }
4531
4556
 
4532
4557
  const _callToolHandler = async (request) => {