magector 1.0.0 → 1.2.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.
- package/README.md +42 -6
- package/package.json +1 -1
- package/src/binary.js +5 -1
- package/src/model.js +11 -6
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Magector indexes an entire Magento 2 codebase and lets you search it with natura
|
|
|
7
7
|
[](https://www.rust-lang.org)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
9
|
[](https://magento.com)
|
|
10
|
-
[](#validation)
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
|
|
13
13
|
---
|
|
@@ -27,10 +27,32 @@ Magector understands that a query about *"payment capture"* should return `Sales
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
+
## Magector vs Built-in AI Search
|
|
31
|
+
|
|
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
|
+
|
|
34
|
+
| Capability | Claude Code / Cursor (built-in) | Magector |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| **Search method** | Keyword grep / ripgrep | Semantic vector search (ONNX embeddings) |
|
|
37
|
+
| **Understands intent** | No — literal string matching only | Yes — "payment capture" finds `CaptureOperation.php` |
|
|
38
|
+
| **Magento pattern awareness** | None — treats all PHP the same | Detects controllers, plugins, observers, blocks, resolvers, cron, and 20+ patterns |
|
|
39
|
+
| **Query speed (18K files)** | 200-1000ms per grep pass; multiple rounds needed | 15-45ms single pass |
|
|
40
|
+
| **Context window cost** | Reads many wrong files → burns tokens | Returns ranked results → AI reads only what matters |
|
|
41
|
+
| **Works offline** | Yes | Yes — local ONNX model, no API calls |
|
|
42
|
+
| **Setup** | Built-in | `npx magector init` (one command) |
|
|
43
|
+
|
|
44
|
+
### What this means in practice
|
|
45
|
+
|
|
46
|
+
Without Magector, asking Claude Code or Cursor *"how are checkout totals calculated?"* triggers multiple grep searches, reads dozens of files, and still may miss the right ones. With Magector, the AI calls `magento_search("checkout totals calculation")` and gets the exact files ranked by relevance in one step — saving tokens and time.
|
|
47
|
+
|
|
48
|
+
**Magector doesn't replace your AI tool — it gives it a better search engine.**
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
30
52
|
## Features
|
|
31
53
|
|
|
32
54
|
- **Semantic search** -- find code by meaning, not exact keywords
|
|
33
|
-
- **
|
|
55
|
+
- **96.1% accuracy** -- validated with 557 test cases across 50+ categories
|
|
34
56
|
- **ONNX embeddings** -- native 384-dim transformer embeddings via ONNX Runtime for higher quality search
|
|
35
57
|
- **Parallel processing** -- batch embedding with parallel intelligence for faster indexing
|
|
36
58
|
- **Magento-aware** -- understands controllers, plugins, observers, blocks, resolvers, repositories, and 20+ Magento patterns
|
|
@@ -271,6 +293,21 @@ magento_complexity({ module: "Magento_Catalog", threshold: 10 })
|
|
|
271
293
|
|
|
272
294
|
---
|
|
273
295
|
|
|
296
|
+
## Supported Platforms
|
|
297
|
+
|
|
298
|
+
Pre-built binaries are provided for the following platforms:
|
|
299
|
+
|
|
300
|
+
| Platform | Architecture | Package |
|
|
301
|
+
|----------|-------------|---------|
|
|
302
|
+
| macOS | ARM64 (Apple Silicon) | `@magector/cli-darwin-arm64` |
|
|
303
|
+
| Linux | x86_64 | `@magector/cli-linux-x64` |
|
|
304
|
+
| Linux | ARM64 | `@magector/cli-linux-arm64` |
|
|
305
|
+
| Windows | x86_64 | `@magector/cli-win32-x64` |
|
|
306
|
+
|
|
307
|
+
> **Note:** macOS Intel (x86_64) is not supported as a pre-built binary. Intel Mac users can [build from source](#building-from-source).
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
274
311
|
## Validation
|
|
275
312
|
|
|
276
313
|
Magector is validated against the complete Magento 2.4.7 codebase with **557 test cases** across **50+ categories**.
|
|
@@ -279,8 +316,8 @@ Magector is validated against the complete Magento 2.4.7 codebase with **557 tes
|
|
|
279
316
|
|
|
280
317
|
| Metric | Value |
|
|
281
318
|
|--------|-------|
|
|
282
|
-
| **Accuracy** | **
|
|
283
|
-
| Tests passed |
|
|
319
|
+
| **Accuracy** | **96.1%** |
|
|
320
|
+
| Tests passed | 535 / 557 |
|
|
284
321
|
| Index size | 17,891 vectors |
|
|
285
322
|
| Query time | 15-45ms |
|
|
286
323
|
| Indexing time | ~3 minutes |
|
|
@@ -338,7 +375,6 @@ magector/
|
|
|
338
375
|
│ └── mcp-server.test.js # MCP server tests (Rust core + analysis tools)
|
|
339
376
|
├── platforms/ # Platform-specific binary packages
|
|
340
377
|
│ ├── darwin-arm64/ # macOS ARM (Apple Silicon)
|
|
341
|
-
│ ├── darwin-x64/ # macOS Intel
|
|
342
378
|
│ ├── linux-x64/ # Linux x64
|
|
343
379
|
│ ├── linux-arm64/ # Linux ARM64
|
|
344
380
|
│ └── win32-x64/ # Windows x64
|
|
@@ -596,7 +632,7 @@ struct IndexMetadata {
|
|
|
596
632
|
|
|
597
633
|
## Roadmap
|
|
598
634
|
|
|
599
|
-
- [
|
|
635
|
+
- [x] Hybrid search (semantic + keyword re-ranking)
|
|
600
636
|
- [ ] Query intent classification (auto-detect "give me XML" vs "give me PHP")
|
|
601
637
|
- [ ] Filtered search by file type at the vector level
|
|
602
638
|
- [ ] Incremental indexing (only re-index changed files)
|
package/package.json
CHANGED
package/src/binary.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 3. rust-core/target/release/magector-core (dev fallback)
|
|
8
8
|
* 4. magector-core in PATH
|
|
9
9
|
*/
|
|
10
|
-
import { existsSync } from 'fs';
|
|
10
|
+
import { existsSync, chmodSync } from 'fs';
|
|
11
11
|
import { execFileSync } from 'child_process';
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
@@ -33,6 +33,10 @@ export function resolveBinary() {
|
|
|
33
33
|
const pkgDir = path.dirname(require.resolve(`${platformPkg}/package.json`));
|
|
34
34
|
const binPath = path.join(pkgDir, 'bin', BINARY_NAME);
|
|
35
35
|
if (existsSync(binPath)) {
|
|
36
|
+
// npm doesn't preserve execute permissions — ensure the binary is executable
|
|
37
|
+
if (process.platform !== 'win32') {
|
|
38
|
+
try { chmodSync(binPath, 0o755); } catch {}
|
|
39
|
+
}
|
|
36
40
|
return binPath;
|
|
37
41
|
}
|
|
38
42
|
} catch {
|
package/src/model.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Downloads from HuggingFace if not found.
|
|
10
10
|
*/
|
|
11
|
-
import { existsSync, mkdirSync, createWriteStream } from 'fs';
|
|
11
|
+
import { existsSync, statSync, mkdirSync, createWriteStream, unlinkSync } from 'fs';
|
|
12
12
|
import { get as httpsGet } from 'https';
|
|
13
13
|
import path from 'path';
|
|
14
14
|
import os from 'os';
|
|
@@ -60,7 +60,10 @@ export function resolveModels() {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function hasModels(dir) {
|
|
63
|
-
return MODEL_FILES.every(f =>
|
|
63
|
+
return MODEL_FILES.every(f => {
|
|
64
|
+
const p = path.join(dir, f.name);
|
|
65
|
+
return existsSync(p) && statSync(p).size > 0;
|
|
66
|
+
});
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
/**
|
|
@@ -79,7 +82,8 @@ export async function ensureModels({ silent = false } = {}) {
|
|
|
79
82
|
|
|
80
83
|
for (const file of MODEL_FILES) {
|
|
81
84
|
const dest = path.join(targetDir, file.name);
|
|
82
|
-
if (existsSync(dest)) continue;
|
|
85
|
+
if (existsSync(dest) && statSync(dest).size > 0) continue;
|
|
86
|
+
if (existsSync(dest)) unlinkSync(dest);
|
|
83
87
|
|
|
84
88
|
if (!silent) {
|
|
85
89
|
process.stdout.write(` ${file.description} ... `);
|
|
@@ -101,10 +105,11 @@ function downloadFile(url, dest) {
|
|
|
101
105
|
return new Promise((resolve, reject) => {
|
|
102
106
|
const file = createWriteStream(dest);
|
|
103
107
|
|
|
104
|
-
function follow(
|
|
105
|
-
httpsGet(
|
|
108
|
+
function follow(currentUrl) {
|
|
109
|
+
httpsGet(currentUrl, (res) => {
|
|
106
110
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
107
|
-
|
|
111
|
+
const next = new URL(res.headers.location, currentUrl).href;
|
|
112
|
+
follow(next);
|
|
108
113
|
return;
|
|
109
114
|
}
|
|
110
115
|
if (res.statusCode !== 200) {
|