weavatrix 0.1.0 → 0.1.1
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
CHANGED
|
@@ -10,7 +10,7 @@ never leaves it.**
|
|
|
10
10
|
|
|
11
11
|
- Website: [weavatrix.com](https://weavatrix.com)
|
|
12
12
|
- Source: [github.com/sergii-ziborov/weavatrix](https://github.com/sergii-ziborov/weavatrix)
|
|
13
|
-
-
|
|
13
|
+
- npm: [`weavatrix`](https://www.npmjs.com/package/weavatrix) — `npx -y weavatrix <repoRoot>`
|
|
14
14
|
|
|
15
15
|
## Why
|
|
16
16
|
|
|
@@ -125,7 +125,7 @@ Graphs are derived data and never live inside your repo: they go to a `weavatrix
|
|
|
125
125
|
|
|
126
126
|
```sh
|
|
127
127
|
npm install
|
|
128
|
-
npm test # node --test
|
|
128
|
+
npm test # node --test
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
Design rule: **no source file exceeds 300 lines.** Larger concerns split into dotted-suffix modules
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weavatrix",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Weavatrix — code graph & blast-radius MCP server for AI coding agents: change impact, transitive dependents, health audit, duplicate detection, and coverage mapping over any local repository.",
|
|
6
6
|
"author": "Sergii Ziborov <sergii@edgehawk.io>",
|
|
@@ -11,13 +11,16 @@ import { buildResolvers } from "./internal-builder.resolvers.js";
|
|
|
11
11
|
|
|
12
12
|
// Parse a repo directory into a graph-builder-compatible { nodes, links } graph.
|
|
13
13
|
export async function buildInternalGraph(repoDir, opts = {}) {
|
|
14
|
-
const
|
|
14
|
+
const files = walk(repoDir);
|
|
15
|
+
// Lazy grammar loading: compile only the WASMs for languages this repo actually contains.
|
|
16
|
+
const wanted = new Set();
|
|
17
|
+
for (const f of files) { const g = EXT_LANG[extname(f)]; if (g) wanted.add(g); }
|
|
18
|
+
const langs = await ensureParser(opts, wanted);
|
|
15
19
|
const qc = new Map();
|
|
16
20
|
const q = (grammar, src) => { const k = grammar + ":" + src; if (qc.has(k)) return qc.get(k); let x = null; try { x = new Query(langs[grammar], src); } catch { x = null; } qc.set(k, x); return x; };
|
|
17
21
|
const caps = (grammar, src, root) => { const query = src && q(grammar, src); return query ? query.captures(root) : []; };
|
|
18
22
|
const field = (n, f) => (n && n.childForFieldName ? n.childForFieldName(f) : null);
|
|
19
23
|
|
|
20
|
-
const files = walk(repoDir);
|
|
21
24
|
const rel = (p) => relative(repoDir, p).replace(/\\/g, "/");
|
|
22
25
|
const fileSet = new Set(files.map(rel));
|
|
23
26
|
const nodes = []; const links = []; const nodeIds = new Set(); const nodeById = new Map();
|
|
@@ -52,11 +52,15 @@ const MAX_PARSE_BYTES = 1_500_000; // skip parsing files above this (minified
|
|
|
52
52
|
|
|
53
53
|
let _ready = null;
|
|
54
54
|
const _langs = {};
|
|
55
|
-
|
|
55
|
+
// `wanted` (a Set of grammar names) makes loading LAZY: only grammars for extensions actually present
|
|
56
|
+
// in the repo get compiled. The heavy WASMs (rust ~3MB, c_sharp ~4MB) cost seconds to compile — a tax
|
|
57
|
+
// a JS-only repo must never pay. Omit `wanted` to load everything (old behavior).
|
|
58
|
+
async function ensureParser(opts = {}, wanted = null) {
|
|
56
59
|
if (!_ready) _ready = Parser.init({ locateFile: () => opts.runtimeWasm || DEFAULT_RUNTIME_WASM });
|
|
57
60
|
await _ready;
|
|
58
61
|
const wasmDir = opts.wasmDir || DEFAULT_WASM_DIR;
|
|
59
|
-
|
|
62
|
+
const list = wanted ? GRAMMARS.filter((g) => wanted.has(g)) : GRAMMARS;
|
|
63
|
+
for (const g of list) if (!_langs[g]) { try { _langs[g] = await Language.load(join(wasmDir, `tree-sitter-${g}.wasm`)); } catch { _langs[g] = null; } }
|
|
60
64
|
return _langs;
|
|
61
65
|
}
|
|
62
66
|
|
|
@@ -78,7 +82,9 @@ function walk(dir, acc = [], seen = new Set(), depth = 0) {
|
|
|
78
82
|
const full = join(dir, name);
|
|
79
83
|
let st; try { st = statSync(full); } catch { continue; }
|
|
80
84
|
if (st.isDirectory()) walk(full, acc, seen, depth + 1);
|
|
81
|
-
|
|
85
|
+
// include by KNOWN extension, not by loaded grammar — grammars now load lazily AFTER the walk
|
|
86
|
+
// (the parse passes skip files whose grammar failed to load, so the guarantee is unchanged)
|
|
87
|
+
else { const e = extname(name); if (EXT_LANG[e] || isDataFile(name) || isDocFile(name)) acc.push(full); }
|
|
82
88
|
}
|
|
83
89
|
return acc;
|
|
84
90
|
}
|
package/src/mcp-server.mjs
CHANGED
|
@@ -22,8 +22,11 @@ import process from 'node:process'
|
|
|
22
22
|
import {loadGraph} from './mcp/graph-context.mjs'
|
|
23
23
|
import {loadHotApi, HOT_FILES} from './mcp/catalog.mjs'
|
|
24
24
|
import {graphOutDirForRepo} from './graph/layout.js'
|
|
25
|
+
import {createRequire} from 'node:module'
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
// version comes from package.json so serverInfo can never drift from the published package again
|
|
28
|
+
const PKG_VERSION = (() => { try { return createRequire(import.meta.url)('../package.json').version } catch { return '0.0.0' } })()
|
|
29
|
+
const SERVER_INFO = {name: 'weavatrix', version: PKG_VERSION}
|
|
27
30
|
const DEFAULT_PROTOCOL = '2024-11-05'
|
|
28
31
|
const log = (...a) => process.stderr.write(`[weavatrix] ${a.join(' ')}\n`)
|
|
29
32
|
|