magector 2.16.1 → 2.16.2
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 +80 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magector",
|
|
3
|
-
"version": "2.16.
|
|
3
|
+
"version": "2.16.2",
|
|
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.
|
|
37
|
-
"@magector/cli-linux-x64": "2.16.
|
|
38
|
-
"@magector/cli-linux-arm64": "2.16.
|
|
39
|
-
"@magector/cli-win32-x64": "2.16.
|
|
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"
|
|
40
40
|
},
|
|
41
41
|
"keywords": [
|
|
42
42
|
"magento",
|
package/src/mcp-server.js
CHANGED
|
@@ -423,6 +423,13 @@ let reindexInProgress = false;
|
|
|
423
423
|
let reindexProcess = null;
|
|
424
424
|
let warmupInProgress = true; // true until checkDbFormat + serve process ready
|
|
425
425
|
|
|
426
|
+
// Re-index progress tracking (updated from INDEX log lines)
|
|
427
|
+
let reindexStartTime = null;
|
|
428
|
+
let reindexPhase = 0; // 0=init, 1=AST, 2=embeddings, 3=HNSW
|
|
429
|
+
let reindexTotalFiles = 0;
|
|
430
|
+
let reindexItemsToEmbed = 0;
|
|
431
|
+
let reindexPhase2Start = null;
|
|
432
|
+
|
|
426
433
|
/**
|
|
427
434
|
* Check if the database file is compatible with the current binary.
|
|
428
435
|
* Uses a cached result to avoid running stats (30-60s) on every startup.
|
|
@@ -557,6 +564,11 @@ function startBackgroundReindex() {
|
|
|
557
564
|
}
|
|
558
565
|
|
|
559
566
|
reindexInProgress = true;
|
|
567
|
+
reindexStartTime = Date.now();
|
|
568
|
+
reindexPhase = 0;
|
|
569
|
+
reindexTotalFiles = 0;
|
|
570
|
+
reindexItemsToEmbed = 0;
|
|
571
|
+
reindexPhase2Start = null;
|
|
560
572
|
|
|
561
573
|
const hadExistingDb = existsSync(config.dbPath);
|
|
562
574
|
logToFile('WARN', `Starting background re-index to temp path. Old DB ${hadExistingDb ? 'preserved for queries' : 'not found'}.`);
|
|
@@ -590,18 +602,31 @@ function startBackgroundReindex() {
|
|
|
590
602
|
// entries arrive in large chunks instead of in real time.
|
|
591
603
|
const indexStdout = createInterface({ input: reindexProcess.stdout });
|
|
592
604
|
const indexStderr = createInterface({ input: reindexProcess.stderr });
|
|
605
|
+
const parseIndexProgress = (text) => {
|
|
606
|
+
const m = text.match(/Found (\d[\d,]+) files to index/);
|
|
607
|
+
if (m) reindexTotalFiles = parseInt(m[1].replace(/,/g, ''), 10);
|
|
608
|
+
if (text.includes('PHASE 1') || text.includes('AST analyzer')) reindexPhase = 1;
|
|
609
|
+
if (text.includes('PHASE 2') || text.includes('semantic embedding') || text.includes('Generating semantic')) {
|
|
610
|
+
if (reindexPhase < 2) { reindexPhase = 2; reindexPhase2Start = Date.now(); }
|
|
611
|
+
}
|
|
612
|
+
if (text.includes('PHASE 3') || text.includes('Building HNSW') || text.includes('HNSW')) reindexPhase = 3;
|
|
613
|
+
const em = text.match(/Items to embed: (\d[\d,]+)/);
|
|
614
|
+
if (em) reindexItemsToEmbed = parseInt(em[1].replace(/,/g, ''), 10);
|
|
615
|
+
};
|
|
593
616
|
indexStdout.on('line', (line) => {
|
|
594
617
|
const text = line.replace(/\x1b\[[0-9;]*m/g, '').trim();
|
|
595
|
-
if (text) logToFile('INDEX', text);
|
|
618
|
+
if (text) { logToFile('INDEX', text); parseIndexProgress(text); }
|
|
596
619
|
});
|
|
597
620
|
indexStderr.on('line', (line) => {
|
|
598
621
|
const text = line.replace(/\x1b\[[0-9;]*m/g, '').trim();
|
|
599
|
-
if (text) logToFile('INDEX', text);
|
|
622
|
+
if (text) { logToFile('INDEX', text); parseIndexProgress(text); }
|
|
600
623
|
});
|
|
601
624
|
|
|
602
625
|
reindexProcess.on('exit', (code) => {
|
|
603
626
|
reindexInProgress = false;
|
|
604
627
|
reindexProcess = null;
|
|
628
|
+
reindexStartTime = null;
|
|
629
|
+
reindexPhase = 0;
|
|
605
630
|
removeReindexPidFile();
|
|
606
631
|
if (code === 0) {
|
|
607
632
|
// Atomic swap: old → .bak, new → current
|
|
@@ -4462,7 +4487,49 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
4462
4487
|
]
|
|
4463
4488
|
}));
|
|
4464
4489
|
|
|
4465
|
-
|
|
4490
|
+
/**
|
|
4491
|
+
* Build a reindex warning string for tool responses during background re-index.
|
|
4492
|
+
* Returns null when not re-indexing.
|
|
4493
|
+
*/
|
|
4494
|
+
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. ~1–3 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';
|
|
4520
|
+
} else {
|
|
4521
|
+
etaStr = 'est. 30–60 min for this phase';
|
|
4522
|
+
}
|
|
4523
|
+
} else {
|
|
4524
|
+
phaseStr = 'phase 3/3: building HNSW vector index';
|
|
4525
|
+
etaStr = 'est. ~5–10 min remaining';
|
|
4526
|
+
}
|
|
4527
|
+
|
|
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`;
|
|
4530
|
+
}
|
|
4531
|
+
|
|
4532
|
+
const _callToolHandler = async (request) => {
|
|
4466
4533
|
const { name, arguments: args } = request.params;
|
|
4467
4534
|
const reqStart = Date.now();
|
|
4468
4535
|
logToFile('REQ', `${name}(${JSON.stringify(args || {})})`);
|
|
@@ -6928,6 +6995,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
6928
6995
|
serveQuery('feedback', { signals }).catch((err) => logToFile('WARN', `Feedback signal send failed: ${err.message}`));
|
|
6929
6996
|
}
|
|
6930
6997
|
}
|
|
6998
|
+
};
|
|
6999
|
+
|
|
7000
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
7001
|
+
const result = await _callToolHandler(request);
|
|
7002
|
+
// Append re-index warning to non-error responses during background re-index
|
|
7003
|
+
if (reindexInProgress && !result?.isError && result?.content?.[0]?.type === 'text') {
|
|
7004
|
+
const warning = getReindexWarning();
|
|
7005
|
+
if (warning) result.content[0].text = warning + result.content[0].text;
|
|
7006
|
+
}
|
|
7007
|
+
return result;
|
|
6931
7008
|
});
|
|
6932
7009
|
|
|
6933
7010
|
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|