magector 1.2.13 → 1.2.15
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 +138 -148
- package/package.json +5 -5
- package/src/mcp-server.js +87 -36
package/README.md
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
# Magector
|
|
2
2
|
|
|
3
|
-
**Semantic code search engine for Magento 2, powered by ONNX embeddings and HNSW vector search.**
|
|
3
|
+
**Semantic code search engine for Magento 2 and Adobe Commerce, powered by ONNX embeddings and HNSW vector search.**
|
|
4
4
|
|
|
5
|
-
Magector indexes an entire Magento 2 codebase and lets you search it with natural language. Instead of grepping for keywords, ask questions like *"how are checkout totals calculated?"* or *"where is the product price determined?"* and get ranked, relevant results in under 50ms.
|
|
5
|
+
Magector indexes an entire Magento 2 or Adobe Commerce codebase and lets you search it with natural language. Instead of grepping for keywords, ask questions like *"how are checkout totals calculated?"* or *"where is the product price determined?"* and get ranked, relevant results in under 50ms.
|
|
6
6
|
|
|
7
7
|
[](https://www.rust-lang.org)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
9
|
[](https://magento.com)
|
|
10
|
-
[](https://business.adobe.com/products/magento/magento-commerce.html)
|
|
11
|
+
[](#validation)
|
|
11
12
|
[](LICENSE)
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
## Why Magector
|
|
16
17
|
|
|
17
|
-
Magento 2
|
|
18
|
+
Magento 2 and Adobe Commerce have **18,000+ source files** across hundreds of modules. Finding the right code is slow:
|
|
18
19
|
|
|
19
20
|
| Approach | Finds semantic matches | Understands Magento patterns | Speed (18K files) |
|
|
20
21
|
|----------|:---------------------:|:---------------------------:|:-----------------:|
|
|
@@ -29,7 +30,7 @@ Magector understands that a query about *"payment capture"* should return `Sales
|
|
|
29
30
|
|
|
30
31
|
## Magector vs Built-in AI Search
|
|
31
32
|
|
|
32
|
-
Claude Code and Cursor both have built-in code search -- but they rely on keyword matching (`grep`/`ripgrep`) and file-tree heuristics. On a Magento 2 codebase with 18,000+ files, that approach breaks down fast.
|
|
33
|
+
Claude Code and Cursor both have built-in code search -- but they rely on keyword matching (`grep`/`ripgrep`) and file-tree heuristics. On a Magento 2 / Adobe Commerce codebase with 18,000+ files, that approach breaks down fast.
|
|
33
34
|
|
|
34
35
|
| Capability | Claude Code / Cursor (built-in) | Magector |
|
|
35
36
|
|---|---|---|
|
|
@@ -52,13 +53,14 @@ Without Magector, asking Claude Code or Cursor *"how are checkout totals calcula
|
|
|
52
53
|
## Features
|
|
53
54
|
|
|
54
55
|
- **Semantic search** -- find code by meaning, not exact keywords
|
|
55
|
-
- **
|
|
56
|
+
- **99.2% accuracy** -- validated with 101 E2E test queries across 16 tool categories, plus 557 Rust-level test cases
|
|
56
57
|
- **Hybrid search** -- combines semantic vector similarity with keyword re-ranking for best-of-both-worlds results
|
|
57
58
|
- **Structured JSON output** -- results include file path, class name, methods list, role badges, and content snippets for minimal round-trips
|
|
58
59
|
- **Persistent serve mode** -- keeps ONNX model and HNSW index resident in memory, eliminating cold-start latency
|
|
59
60
|
- **ONNX embeddings** -- native 384-dim transformer embeddings via ONNX Runtime
|
|
60
|
-
- **36K+ vectors** -- indexes the complete Magento 2 codebase including framework internals
|
|
61
|
+
- **36K+ vectors** -- indexes the complete Magento 2 / Adobe Commerce codebase including framework internals
|
|
61
62
|
- **Magento-aware** -- understands controllers, plugins, observers, blocks, resolvers, repositories, and 20+ Magento patterns
|
|
63
|
+
- **Adobe Commerce compatible** -- works with both Magento Open Source and Adobe Commerce (B2B, Staging, and all Commerce-specific modules)
|
|
62
64
|
- **AST-powered** -- tree-sitter parsing for PHP and JavaScript extracts classes, methods, namespaces, and inheritance
|
|
63
65
|
- **Cross-tool discovery** -- tool descriptions include keywords and "See also" references so AI clients find the right tool on the first try
|
|
64
66
|
- **Diff analysis** -- risk scoring and change classification for git commits and staged changes
|
|
@@ -72,19 +74,22 @@ Without Magector, asking Claude Code or Cursor *"how are checkout totals calcula
|
|
|
72
74
|
## Architecture
|
|
73
75
|
|
|
74
76
|
```mermaid
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
flowchart TD
|
|
78
|
+
subgraph rust ["Rust Core"]
|
|
79
|
+
A["AST Parser · PHP + JS"]
|
|
80
|
+
B["Pattern Detection · 20+"]
|
|
81
|
+
C["ONNX Embedder · 384d"]
|
|
82
|
+
D["HNSW + Reranking"]
|
|
83
|
+
A --> B --> C --> D
|
|
82
84
|
end
|
|
83
|
-
|
|
84
|
-
E["MCP Server
|
|
85
|
-
F["Persistent Serve
|
|
86
|
-
G["CLI
|
|
85
|
+
subgraph node ["Node.js Layer"]
|
|
86
|
+
E["MCP Server · 19 tools"]
|
|
87
|
+
F["Persistent Serve"]
|
|
88
|
+
G["CLI · init/index/search"]
|
|
89
|
+
E --> F
|
|
90
|
+
G --> F
|
|
87
91
|
end
|
|
92
|
+
node -->|stdin/stdout JSON| rust
|
|
88
93
|
|
|
89
94
|
style rust fill:#f4a460,color:#000
|
|
90
95
|
style node fill:#68b684,color:#000
|
|
@@ -93,26 +98,25 @@ block-beta
|
|
|
93
98
|
### Indexing Pipeline
|
|
94
99
|
|
|
95
100
|
```mermaid
|
|
96
|
-
flowchart
|
|
97
|
-
A[Source File
|
|
98
|
-
B --> C[
|
|
99
|
-
C --> D[
|
|
100
|
-
D --> E[ONNX
|
|
101
|
-
E --> F[
|
|
102
|
-
A --> G[Metadata
|
|
103
|
-
|
|
104
|
-
G --> H
|
|
101
|
+
flowchart TD
|
|
102
|
+
A[Source File] --> B[AST Parser]
|
|
103
|
+
B --> C[Pattern Detection]
|
|
104
|
+
C --> D[Text Enrichment]
|
|
105
|
+
D --> E[ONNX Embedding]
|
|
106
|
+
E --> F[(HNSW Index)]
|
|
107
|
+
A --> G[Metadata]
|
|
108
|
+
G --> F
|
|
105
109
|
```
|
|
106
110
|
|
|
107
111
|
### Search Pipeline
|
|
108
112
|
|
|
109
113
|
```mermaid
|
|
110
|
-
flowchart
|
|
111
|
-
Q[Query
|
|
112
|
-
E1 --> E2[ONNX Embedding
|
|
113
|
-
E2 --> H[HNSW
|
|
114
|
-
H --> R[Hybrid
|
|
115
|
-
R --> J[Structured JSON
|
|
114
|
+
flowchart TD
|
|
115
|
+
Q[Query] --> E1[Synonym Enrichment]
|
|
116
|
+
E1 --> E2[ONNX Embedding]
|
|
117
|
+
E2 --> H[HNSW Search]
|
|
118
|
+
H --> R[Hybrid Reranking]
|
|
119
|
+
R --> J[Structured JSON]
|
|
116
120
|
```
|
|
117
121
|
|
|
118
122
|
### Components
|
|
@@ -135,22 +139,22 @@ flowchart LR
|
|
|
135
139
|
|
|
136
140
|
- [Node.js 18+](https://nodejs.org)
|
|
137
141
|
|
|
138
|
-
### 1. Initialize in Your
|
|
142
|
+
### 1. Initialize in Your Project
|
|
139
143
|
|
|
140
144
|
```bash
|
|
141
|
-
cd /path/to/your/magento2
|
|
145
|
+
cd /path/to/your/magento2 # or Adobe Commerce project
|
|
142
146
|
npx magector init
|
|
143
147
|
```
|
|
144
148
|
|
|
145
149
|
This single command handles the entire setup:
|
|
146
150
|
|
|
147
151
|
```mermaid
|
|
148
|
-
flowchart
|
|
149
|
-
A["npx magector init"] --> B[Verify
|
|
150
|
-
B --> C[Download
|
|
151
|
-
C --> D[Index Codebase
|
|
152
|
-
D --> E[Detect IDE
|
|
153
|
-
E --> F[Write Config
|
|
152
|
+
flowchart TD
|
|
153
|
+
A["npx magector init"] --> B[Verify Project]
|
|
154
|
+
B --> C[Download Model]
|
|
155
|
+
C --> D[Index Codebase]
|
|
156
|
+
D --> E[Detect IDE]
|
|
157
|
+
E --> F[Write Config]
|
|
154
158
|
F --> G[Update .gitignore]
|
|
155
159
|
```
|
|
156
160
|
|
|
@@ -265,7 +269,7 @@ npx magector help # Show help
|
|
|
265
269
|
|
|
266
270
|
## MCP Server Tools
|
|
267
271
|
|
|
268
|
-
The MCP server exposes 19 tools for AI-assisted Magento development. All search tools return **structured JSON** with file paths, class names, methods, role badges, and content snippets -- enabling AI clients to parse results programmatically and minimize file-read round-trips.
|
|
272
|
+
The MCP server exposes 19 tools for AI-assisted Magento 2 and Adobe Commerce development. All search tools return **structured JSON** with file paths, class names, methods, role badges, and content snippets -- enabling AI clients to parse results programmatically and minimize file-read round-trips.
|
|
269
273
|
|
|
270
274
|
### Output Format
|
|
271
275
|
|
|
@@ -341,35 +345,35 @@ All search tools return structured JSON:
|
|
|
341
345
|
Each tool description includes "See also" hints to help AI clients chain tools effectively:
|
|
342
346
|
|
|
343
347
|
```mermaid
|
|
344
|
-
graph
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
style
|
|
362
|
-
style
|
|
363
|
-
style
|
|
364
|
-
style
|
|
365
|
-
style
|
|
366
|
-
style
|
|
348
|
+
graph TD
|
|
349
|
+
cls["find_class"] --> plg["find_plugin"]
|
|
350
|
+
cls --> prf["find_preference"]
|
|
351
|
+
cls --> mtd["find_method"]
|
|
352
|
+
cfg["find_config"] --> obs["find_observer"]
|
|
353
|
+
cfg --> prf
|
|
354
|
+
cfg --> api["find_api"]
|
|
355
|
+
plg --> cls
|
|
356
|
+
plg --> mtd
|
|
357
|
+
tpl["find_template"] --> blk["find_block"]
|
|
358
|
+
blk --> tpl
|
|
359
|
+
blk --> cfg
|
|
360
|
+
dbs["find_db_schema"] --> cls
|
|
361
|
+
gql["find_graphql"] --> cls
|
|
362
|
+
gql --> mtd
|
|
363
|
+
ctl["find_controller"] --> cfg
|
|
364
|
+
|
|
365
|
+
style cls fill:#4a90d9,color:#fff
|
|
366
|
+
style mtd fill:#4a90d9,color:#fff
|
|
367
|
+
style cfg fill:#e8a838,color:#000
|
|
368
|
+
style plg fill:#d94a4a,color:#fff
|
|
369
|
+
style obs fill:#d94a4a,color:#fff
|
|
370
|
+
style prf fill:#e8a838,color:#000
|
|
367
371
|
style api fill:#e8a838,color:#000
|
|
368
|
-
style
|
|
369
|
-
style
|
|
370
|
-
style
|
|
371
|
-
style
|
|
372
|
-
style
|
|
372
|
+
style tpl fill:#68b684,color:#000
|
|
373
|
+
style blk fill:#68b684,color:#000
|
|
374
|
+
style dbs fill:#9b59b6,color:#fff
|
|
375
|
+
style gql fill:#9b59b6,color:#fff
|
|
376
|
+
style ctl fill:#4a90d9,color:#fff
|
|
373
377
|
```
|
|
374
378
|
|
|
375
379
|
### Query Examples
|
|
@@ -425,24 +429,20 @@ Magector is validated at two levels:
|
|
|
425
429
|
config:
|
|
426
430
|
themeVariables:
|
|
427
431
|
pie1: "#4caf50"
|
|
428
|
-
pie2: "#
|
|
429
|
-
pie3: "#2196f3"
|
|
430
|
-
pie4: "#9c27b0"
|
|
432
|
+
pie2: "#f44336"
|
|
431
433
|
---
|
|
432
|
-
pie title
|
|
433
|
-
"
|
|
434
|
-
"
|
|
435
|
-
"MRR (99.2%)" : 99.2
|
|
436
|
-
"NDCG@10 (85.5%)" : 85.5
|
|
434
|
+
pie title Test Pass Rate (101 queries)
|
|
435
|
+
"Passed (101)" : 101
|
|
436
|
+
"Failed (0)" : 0
|
|
437
437
|
```
|
|
438
438
|
|
|
439
439
|
| Metric | Value |
|
|
440
440
|
|--------|-------|
|
|
441
|
-
| **Grade** | **A (
|
|
441
|
+
| **Grade** | **A+ (99.2/100)** |
|
|
442
442
|
| **Pass rate** | 101/101 (100%) |
|
|
443
|
-
| **Precision** |
|
|
444
|
-
| **MRR** | 99.
|
|
445
|
-
| **NDCG@10** |
|
|
443
|
+
| **Precision** | 98.7% |
|
|
444
|
+
| **MRR** | 99.3% |
|
|
445
|
+
| **NDCG@10** | 98.7% |
|
|
446
446
|
| **Index size** | 35,795 vectors |
|
|
447
447
|
| **Query time** | 10-45ms |
|
|
448
448
|
|
|
@@ -451,19 +451,20 @@ pie title Accuracy Breakdown (94.9/100)
|
|
|
451
451
|
| Tool | Pass | Precision | MRR | NDCG |
|
|
452
452
|
|------|------|-----------|-----|------|
|
|
453
453
|
| find_class | 100% | 100% | 100% | 100% |
|
|
454
|
-
| find_method | 100% |
|
|
455
|
-
| find_controller | 100% | 100% | 100% |
|
|
454
|
+
| find_method | 100% | 98% | 92% | 97% |
|
|
455
|
+
| find_controller | 100% | 100% | 100% | 100% |
|
|
456
456
|
| find_observer | 100% | 100% | 100% | 100% |
|
|
457
|
-
| find_plugin | 100% |
|
|
457
|
+
| find_plugin | 100% | 100% | 100% | 100% |
|
|
458
458
|
| find_preference | 100% | 100% | 100% | 100% |
|
|
459
459
|
| find_api | 100% | 100% | 100% | 100% |
|
|
460
460
|
| find_cron | 100% | 100% | 100% | 100% |
|
|
461
461
|
| find_db_schema | 100% | 100% | 100% | 100% |
|
|
462
462
|
| find_graphql | 100% | 100% | 100% | 100% |
|
|
463
463
|
| find_block | 100% | 100% | 100% | 100% |
|
|
464
|
-
| find_config | 100% |
|
|
465
|
-
| find_template | 100% |
|
|
466
|
-
| search | 100% |
|
|
464
|
+
| find_config | 100% | 100% | 100% | 100% |
|
|
465
|
+
| find_template | 100% | 100% | 100% | 100% |
|
|
466
|
+
| search | 100% | 100% | 100% | 100% |
|
|
467
|
+
| module_structure | 100% | 100% | 100% | 100% |
|
|
467
468
|
|
|
468
469
|
### Integration Tests
|
|
469
470
|
|
|
@@ -548,7 +549,7 @@ magector/
|
|
|
548
549
|
|
|
549
550
|
### 1. Indexing
|
|
550
551
|
|
|
551
|
-
Magector scans every `.php`, `.js`, `.xml`, `.phtml`, and `.graphqls` file in a Magento codebase:
|
|
552
|
+
Magector scans every `.php`, `.js`, `.xml`, `.phtml`, and `.graphqls` file in a Magento 2 or Adobe Commerce codebase:
|
|
552
553
|
|
|
553
554
|
1. **AST parsing** -- Tree-sitter extracts class names, namespaces, methods, inheritance, and interface implementations from PHP and JavaScript files
|
|
554
555
|
2. **Pattern detection** -- Identifies Magento-specific patterns: controllers, models, repositories, plugins, observers, blocks, GraphQL resolvers, admin grids, cron jobs, and more
|
|
@@ -569,23 +570,20 @@ Magector scans every `.php`, `.js`, `.xml`, `.phtml`, and `.graphqls` file in a
|
|
|
569
570
|
The MCP server spawns a persistent Rust process (`magector-core serve`) that keeps the ONNX model and HNSW index loaded in memory. Queries are sent as JSON over stdin and responses returned via stdout -- eliminating the ~2.6s cold-start overhead of loading the model per query. Falls back to single-shot `execFileSync` if the serve process is unavailable.
|
|
570
571
|
|
|
571
572
|
```mermaid
|
|
572
|
-
flowchart
|
|
573
|
+
flowchart TD
|
|
573
574
|
subgraph startup ["Startup (once)"]
|
|
574
|
-
S1[Load
|
|
575
|
-
S2 --> S3[
|
|
575
|
+
S1[Load Model] --> S2[Load Index]
|
|
576
|
+
S2 --> S3[Ready Signal]
|
|
576
577
|
end
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
Q4 --> Q5["stdout: JSON response"]
|
|
578
|
+
subgraph query ["Per Query (10-45ms)"]
|
|
579
|
+
Q1[stdin JSON] --> Q2[Embed]
|
|
580
|
+
Q2 --> Q3[HNSW Search]
|
|
581
|
+
Q3 --> Q4[Rerank]
|
|
582
|
+
Q4 --> Q5[stdout JSON]
|
|
583
583
|
end
|
|
584
|
-
|
|
585
584
|
startup --> query
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
F1["execFileSync\n~2.6s cold start"]
|
|
585
|
+
subgraph fallback ["Fallback"]
|
|
586
|
+
F1[execFileSync ~2.6s]
|
|
589
587
|
end
|
|
590
588
|
|
|
591
589
|
style startup fill:#e8f4e8,color:#000
|
|
@@ -599,20 +597,20 @@ The MCP server delegates all search/index operations to the Rust core binary. An
|
|
|
599
597
|
|
|
600
598
|
```mermaid
|
|
601
599
|
sequenceDiagram
|
|
602
|
-
participant Dev
|
|
603
|
-
participant AI
|
|
604
|
-
participant MCP
|
|
605
|
-
participant Rust
|
|
606
|
-
participant HNSW
|
|
607
|
-
|
|
608
|
-
Dev->>AI: "
|
|
609
|
-
AI->>MCP: magento_search(
|
|
610
|
-
MCP->>Rust:
|
|
611
|
-
Rust->>HNSW:
|
|
612
|
-
HNSW-->>Rust:
|
|
613
|
-
Rust-->>MCP:
|
|
614
|
-
MCP-->>AI:
|
|
615
|
-
AI-->>Dev: TotalsCollector.php
|
|
600
|
+
participant Dev
|
|
601
|
+
participant AI
|
|
602
|
+
participant MCP
|
|
603
|
+
participant Rust
|
|
604
|
+
participant HNSW
|
|
605
|
+
|
|
606
|
+
Dev->>AI: "checkout totals?"
|
|
607
|
+
AI->>MCP: magento_search(...)
|
|
608
|
+
MCP->>Rust: JSON query
|
|
609
|
+
Rust->>HNSW: embed + search
|
|
610
|
+
HNSW-->>Rust: candidates
|
|
611
|
+
Rust-->>MCP: JSON results
|
|
612
|
+
MCP-->>AI: paths, methods, badges
|
|
613
|
+
AI-->>Dev: TotalsCollector.php
|
|
616
614
|
```
|
|
617
615
|
|
|
618
616
|
---
|
|
@@ -621,38 +619,29 @@ sequenceDiagram
|
|
|
621
619
|
|
|
622
620
|
```mermaid
|
|
623
621
|
mindmap
|
|
624
|
-
root((
|
|
625
|
-
PHP
|
|
622
|
+
root((Patterns))
|
|
623
|
+
PHP
|
|
626
624
|
Controller
|
|
627
625
|
Model
|
|
628
626
|
Repository
|
|
629
627
|
Block
|
|
630
628
|
Helper
|
|
631
629
|
ViewModel
|
|
632
|
-
Console Command
|
|
633
|
-
Data Provider
|
|
634
630
|
Interception
|
|
635
631
|
Plugin
|
|
636
632
|
Observer
|
|
637
633
|
Preference
|
|
638
|
-
XML
|
|
634
|
+
XML
|
|
639
635
|
di.xml
|
|
640
636
|
events.xml
|
|
641
637
|
webapi.xml
|
|
642
638
|
routes.xml
|
|
643
|
-
system.xml
|
|
644
|
-
layout XML
|
|
645
|
-
module.xml
|
|
646
639
|
crontab.xml
|
|
647
640
|
db_schema.xml
|
|
648
641
|
Frontend
|
|
649
|
-
|
|
642
|
+
Template
|
|
650
643
|
JavaScript
|
|
651
|
-
GraphQL
|
|
652
|
-
GraphQL Resolver
|
|
653
|
-
Database
|
|
654
|
-
Setup Patch
|
|
655
|
-
Declarative Schema
|
|
644
|
+
GraphQL
|
|
656
645
|
```
|
|
657
646
|
|
|
658
647
|
Magector understands these Magento 2 architectural patterns:
|
|
@@ -856,23 +845,24 @@ struct IndexMetadata {
|
|
|
856
845
|
|
|
857
846
|
```mermaid
|
|
858
847
|
gantt
|
|
859
|
-
title
|
|
848
|
+
title Roadmap
|
|
860
849
|
dateFormat YYYY-MM
|
|
861
|
-
axisFormat %b
|
|
862
|
-
section
|
|
863
|
-
Hybrid search
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
Cross-tool
|
|
867
|
-
E2E
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
850
|
+
axisFormat %b
|
|
851
|
+
section Done
|
|
852
|
+
Hybrid search :done, 2025-01, 30d
|
|
853
|
+
Serve mode :done, 2025-02, 30d
|
|
854
|
+
JSON output :done, 2025-03, 15d
|
|
855
|
+
Cross-tool hints :done, 2025-03, 15d
|
|
856
|
+
E2E tests :done, 2025-03, 15d
|
|
857
|
+
Adobe Commerce :done, 2025-03, 15d
|
|
858
|
+
section Next
|
|
859
|
+
Method chunking :active, 2025-04, 30d
|
|
860
|
+
Intent detection :2025-05, 30d
|
|
861
|
+
Type filtering :2025-06, 30d
|
|
862
|
+
Incremental index :2025-07, 30d
|
|
863
|
+
section Future
|
|
864
|
+
VSCode extension :2025-08, 60d
|
|
865
|
+
Web UI :2025-10, 60d
|
|
876
866
|
```
|
|
877
867
|
|
|
878
868
|
- [x] Hybrid search (semantic + keyword re-ranking)
|
|
@@ -880,13 +870,13 @@ gantt
|
|
|
880
870
|
- [x] Structured JSON output (methods, badges, snippets)
|
|
881
871
|
- [x] Cross-tool discovery hints for AI clients
|
|
882
872
|
- [x] E2E accuracy test suite (101 queries)
|
|
873
|
+
- [x] Adobe Commerce support (B2B, Staging, and all Commerce-specific modules)
|
|
883
874
|
- [ ] Method-level chunking (per-method vectors for direct method search)
|
|
884
875
|
- [ ] Query intent classification (auto-detect "give me XML" vs "give me PHP")
|
|
885
876
|
- [ ] Filtered search by file type at the vector level
|
|
886
877
|
- [ ] Incremental indexing (only re-index changed files)
|
|
887
878
|
- [ ] VSCode extension
|
|
888
879
|
- [ ] Web UI for browsing results
|
|
889
|
-
- [ ] Support for Magento 2 Commerce (B2B, Staging modules)
|
|
890
880
|
|
|
891
881
|
---
|
|
892
882
|
|
|
@@ -908,4 +898,4 @@ Contributions are welcome. Please:
|
|
|
908
898
|
|
|
909
899
|
---
|
|
910
900
|
|
|
911
|
-
Built with Rust and Node.js for the Magento community.
|
|
901
|
+
Built with Rust and Node.js for the Magento and Adobe Commerce community.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magector",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.15",
|
|
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": "1.2.
|
|
37
|
-
"@magector/cli-linux-x64": "1.2.
|
|
38
|
-
"@magector/cli-linux-arm64": "1.2.
|
|
39
|
-
"@magector/cli-win32-x64": "1.2.
|
|
36
|
+
"@magector/cli-darwin-arm64": "1.2.15",
|
|
37
|
+
"@magector/cli-linux-x64": "1.2.15",
|
|
38
|
+
"@magector/cli-linux-arm64": "1.2.15",
|
|
39
|
+
"@magector/cli-win32-x64": "1.2.15"
|
|
40
40
|
},
|
|
41
41
|
"keywords": [
|
|
42
42
|
"magento",
|
package/src/mcp-server.js
CHANGED
|
@@ -697,19 +697,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
697
697
|
|
|
698
698
|
case 'magento_find_method': {
|
|
699
699
|
const query = `method ${args.methodName} function ${args.className || ''}`.trim();
|
|
700
|
-
const raw = await rustSearchAsync(query,
|
|
700
|
+
const raw = await rustSearchAsync(query, 50);
|
|
701
701
|
const methodLower = args.methodName.toLowerCase();
|
|
702
|
+
// Hard-filter: only results that actually define/contain this method
|
|
702
703
|
let results = raw.map(normalizeResult).filter(r =>
|
|
703
704
|
r.methodName?.toLowerCase() === methodLower ||
|
|
704
|
-
r.
|
|
705
|
-
r.methods?.some(m => m.toLowerCase() === methodLower || m.toLowerCase().includes(methodLower)) ||
|
|
706
|
-
r.path?.toLowerCase().includes(methodLower)
|
|
705
|
+
r.methods?.some(m => m.toLowerCase() === methodLower || m.toLowerCase().includes(methodLower))
|
|
707
706
|
);
|
|
707
|
+
// If not enough results from methods[], fall back to path-based matching
|
|
708
|
+
if (results.length < 3) {
|
|
709
|
+
const pathFallback = raw.map(normalizeResult).filter(r =>
|
|
710
|
+
r.path?.toLowerCase().includes(methodLower) &&
|
|
711
|
+
!results.some(existing => existing.path === r.path)
|
|
712
|
+
);
|
|
713
|
+
results = results.concat(pathFallback);
|
|
714
|
+
}
|
|
708
715
|
// Boost exact method matches to top
|
|
709
716
|
results = results.map(r => {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
717
|
+
let bonus = 0;
|
|
718
|
+
if (r.methods?.some(m => m.toLowerCase() === methodLower)) bonus += 0.5;
|
|
719
|
+
if (r.methodName?.toLowerCase() === methodLower) bonus += 0.3;
|
|
720
|
+
return { ...r, score: (r.score || 0) + bonus };
|
|
713
721
|
}).sort((a, b) => b.score - a.score);
|
|
714
722
|
return {
|
|
715
723
|
content: [{
|
|
@@ -722,18 +730,24 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
722
730
|
case 'magento_find_config': {
|
|
723
731
|
let query = args.query;
|
|
724
732
|
if (args.configType && args.configType !== 'other') {
|
|
725
|
-
query = `${args.configType}.xml ${args.query}`;
|
|
733
|
+
query = `${args.configType}.xml xml config ${args.query}`;
|
|
726
734
|
}
|
|
727
|
-
const raw = await rustSearchAsync(query,
|
|
728
|
-
const pathBoost = args.configType ? [`${args.configType}.xml`] : ['.xml'];
|
|
735
|
+
const raw = await rustSearchAsync(query, 100);
|
|
729
736
|
let normalized = raw.map(normalizeResult);
|
|
730
|
-
//
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
737
|
+
// Hard-filter to XML results
|
|
738
|
+
const xmlOnly = normalized.filter(r =>
|
|
739
|
+
r.type === 'xml' || r.path?.endsWith('.xml') || r.path?.includes('.xml')
|
|
740
|
+
);
|
|
741
|
+
if (xmlOnly.length > 0) normalized = xmlOnly;
|
|
742
|
+
// Hard-filter to specific config type when specified
|
|
743
|
+
if (args.configType && args.configType !== 'other') {
|
|
744
|
+
const configTypeFile = `${args.configType}.xml`;
|
|
745
|
+
const typeSpecific = normalized.filter(r =>
|
|
746
|
+
r.path?.includes(configTypeFile)
|
|
734
747
|
);
|
|
735
|
-
if (
|
|
748
|
+
if (typeSpecific.length >= 3) normalized = typeSpecific;
|
|
736
749
|
}
|
|
750
|
+
const pathBoost = args.configType ? [`${args.configType}.xml`] : ['.xml'];
|
|
737
751
|
const results = rerank(normalized, { fileType: 'xml', pathContains: pathBoost });
|
|
738
752
|
return {
|
|
739
753
|
content: [{
|
|
@@ -747,8 +761,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
747
761
|
let query = args.query;
|
|
748
762
|
if (args.area) query = `${args.area} ${query}`;
|
|
749
763
|
query += ' template phtml';
|
|
750
|
-
const raw = await rustSearchAsync(query,
|
|
751
|
-
|
|
764
|
+
const raw = await rustSearchAsync(query, 50);
|
|
765
|
+
// Hard-filter to .phtml template files only
|
|
766
|
+
let results = raw.map(normalizeResult).filter(r =>
|
|
767
|
+
r.path?.includes('.phtml') || r.type === 'template'
|
|
768
|
+
);
|
|
769
|
+
results = rerank(results, { pathContains: ['.phtml'] });
|
|
752
770
|
return {
|
|
753
771
|
content: [{
|
|
754
772
|
type: 'text',
|
|
@@ -850,10 +868,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
850
868
|
const namespaceParts = parts.map(p => p.charAt(0).toUpperCase() + p.slice(1));
|
|
851
869
|
const query = `${namespaceParts.join(' ')} controller execute action`;
|
|
852
870
|
|
|
853
|
-
const raw = await rustSearchAsync(query,
|
|
871
|
+
const raw = await rustSearchAsync(query, 50);
|
|
872
|
+
// Prefer path-based controller detection, fall back to isController flag
|
|
854
873
|
let results = raw.map(normalizeResult).filter(r =>
|
|
855
|
-
r.
|
|
874
|
+
r.path?.includes('/Controller/')
|
|
856
875
|
);
|
|
876
|
+
if (results.length < 5) {
|
|
877
|
+
// Add isController-flagged results not already included
|
|
878
|
+
const extra = raw.map(normalizeResult).filter(r =>
|
|
879
|
+
r.isController && !results.some(e => e.path === r.path)
|
|
880
|
+
);
|
|
881
|
+
results = results.concat(extra);
|
|
882
|
+
}
|
|
857
883
|
|
|
858
884
|
// Boost results whose path matches the route segments
|
|
859
885
|
if (parts.length >= 2) {
|
|
@@ -947,11 +973,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
947
973
|
}
|
|
948
974
|
|
|
949
975
|
case 'magento_module_structure': {
|
|
950
|
-
const raw = await rustSearchAsync(args.moduleName,
|
|
951
|
-
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
|
|
976
|
+
const raw = await rustSearchAsync(args.moduleName, 200);
|
|
977
|
+
// Support both app/code (Magento/Catalog/) and vendor (module-catalog/) paths
|
|
978
|
+
const modulePath = args.moduleName.replace('_', '/') + '/';
|
|
979
|
+
const parts = args.moduleName.split('_');
|
|
980
|
+
const vendorPath = parts.length === 2
|
|
981
|
+
? `module-${parts[1].toLowerCase()}/`
|
|
982
|
+
: '';
|
|
983
|
+
const results = raw.map(normalizeResult).filter(r => {
|
|
984
|
+
const path = r.path || '';
|
|
985
|
+
const mod = r.module || '';
|
|
986
|
+
// Exact module match or directory-level path match (trailing slash prevents Catalog matching CatalogRule)
|
|
987
|
+
return mod === args.moduleName ||
|
|
988
|
+
path.includes(modulePath) ||
|
|
989
|
+
(vendorPath && path.toLowerCase().includes(vendorPath));
|
|
990
|
+
});
|
|
955
991
|
|
|
956
992
|
const structure = {
|
|
957
993
|
controllers: results.filter(r => r.isController || r.path?.includes('/Controller/')),
|
|
@@ -970,24 +1006,39 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
970
1006
|
)
|
|
971
1007
|
};
|
|
972
1008
|
|
|
973
|
-
|
|
974
|
-
|
|
1009
|
+
// Build structured JSON output for module structure
|
|
1010
|
+
const structureOutput = {
|
|
1011
|
+
module: args.moduleName,
|
|
1012
|
+
totalFiles: results.length,
|
|
1013
|
+
categories: {}
|
|
1014
|
+
};
|
|
975
1015
|
for (const [category, items] of Object.entries(structure)) {
|
|
976
1016
|
if (items.length > 0) {
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1017
|
+
structureOutput.categories[category] = {
|
|
1018
|
+
count: items.length,
|
|
1019
|
+
files: items.slice(0, 10).map(item => ({
|
|
1020
|
+
path: item.path,
|
|
1021
|
+
className: item.className || null,
|
|
1022
|
+
methods: item.methods?.length > 0 ? item.methods : undefined
|
|
1023
|
+
}))
|
|
1024
|
+
};
|
|
983
1025
|
}
|
|
984
1026
|
}
|
|
985
1027
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1028
|
+
// Return both JSON and formatted summary
|
|
1029
|
+
const jsonOutput = JSON.stringify({
|
|
1030
|
+
results: results.slice(0, 50).map((r, i) => ({
|
|
1031
|
+
rank: i + 1,
|
|
1032
|
+
path: r.path,
|
|
1033
|
+
className: r.className || undefined,
|
|
1034
|
+
magentoType: r.magentoType || undefined,
|
|
1035
|
+
module: r.module || undefined
|
|
1036
|
+
})),
|
|
1037
|
+
count: results.length,
|
|
1038
|
+
structure: structureOutput.categories
|
|
1039
|
+
});
|
|
989
1040
|
|
|
990
|
-
return { content: [{ type: 'text', text }] };
|
|
1041
|
+
return { content: [{ type: 'text', text: jsonOutput }] };
|
|
991
1042
|
}
|
|
992
1043
|
|
|
993
1044
|
case 'magento_analyze_diff': {
|