weavatrix 0.3.14 → 1.1.0
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/LICENSE +1 -0
- package/README.md +132 -200
- package/bin/native/darwin-arm64/weavatrix +0 -0
- package/bin/native/darwin-x64/weavatrix +0 -0
- package/bin/native/linux-arm64/weavatrix +0 -0
- package/bin/native/linux-x64/weavatrix +0 -0
- package/bin/native/win32-arm64/weavatrix.exe +0 -0
- package/bin/native/win32-x64/weavatrix.exe +0 -0
- package/bin/resolve-binary.mjs +73 -0
- package/bin/run-native.mjs +26 -0
- package/bin/weavatrix-mcp.mjs +7 -6
- package/bin/weavatrix.mjs +5 -0
- package/package.json +10 -67
- package/server.json +38 -0
- package/skill/SKILL.md +62 -374
- package/skill/agents/openai.yaml +4 -0
- package/skill/references/tool-routing.md +45 -0
- package/SECURITY.md +0 -101
- package/docs/adr/0001-v0.3-offline-online-split.md +0 -60
- package/docs/agent-task-benchmark.md +0 -58
- package/docs/releases/v0.2.19.md +0 -33
- package/docs/releases/v0.3.0.md +0 -43
- package/docs/releases/v0.3.1.md +0 -30
- package/docs/releases/v0.3.10.md +0 -76
- package/docs/releases/v0.3.11.md +0 -55
- package/docs/releases/v0.3.12.md +0 -44
- package/docs/releases/v0.3.13.md +0 -34
- package/docs/releases/v0.3.14.md +0 -37
- package/docs/releases/v0.3.2.md +0 -15
- package/docs/releases/v0.3.3.md +0 -25
- package/docs/releases/v0.3.4.md +0 -40
- package/docs/releases/v0.3.5.md +0 -50
- package/docs/releases/v0.3.6.md +0 -44
- package/docs/releases/v0.3.7.md +0 -37
- package/docs/releases/v0.3.8.md +0 -21
- package/docs/releases/v0.3.9.md +0 -36
- package/scripts/run-agent-task-benchmark.mjs +0 -118
- package/src/analysis/allowed-test-runner.js +0 -70
- package/src/analysis/architecture/contract-graph.js +0 -119
- package/src/analysis/architecture/contract-schema.js +0 -110
- package/src/analysis/architecture/contract-storage.js +0 -35
- package/src/analysis/architecture/contract-verification.js +0 -168
- package/src/analysis/architecture-contract.js +0 -16
- package/src/analysis/audit-debt.js +0 -94
- package/src/analysis/audit-extensions.js +0 -60
- package/src/analysis/cargo-dependency-evidence.js +0 -108
- package/src/analysis/cargo-manifests.js +0 -81
- package/src/analysis/change-classification/diff-parser.js +0 -103
- package/src/analysis/change-classification/options.js +0 -40
- package/src/analysis/change-classification/symbol-classifier.js +0 -177
- package/src/analysis/change-classification.js +0 -188
- package/src/analysis/coverage-reports-tarpaulin.js +0 -112
- package/src/analysis/coverage-reports.js +0 -246
- package/src/analysis/cycle-route.js +0 -14
- package/src/analysis/data-flow-evidence.js +0 -114
- package/src/analysis/dead-check.js +0 -300
- package/src/analysis/dead-code-review/candidates.js +0 -194
- package/src/analysis/dead-code-review/policy.js +0 -23
- package/src/analysis/dead-code-review.js +0 -119
- package/src/analysis/dep-check-ecosystems.js +0 -205
- package/src/analysis/dep-check.js +0 -290
- package/src/analysis/dep-rules.js +0 -10
- package/src/analysis/dependency/conventions.js +0 -16
- package/src/analysis/dependency/scoped-dependencies.js +0 -51
- package/src/analysis/dependency/source-references.js +0 -21
- package/src/analysis/duplicate-groups.js +0 -104
- package/src/analysis/duplicates-worker.js +0 -11
- package/src/analysis/duplicates.compute.js +0 -269
- package/src/analysis/duplicates.js +0 -15
- package/src/analysis/duplicates.run.js +0 -52
- package/src/analysis/duplicates.tokenize.js +0 -199
- package/src/analysis/endpoints/common.js +0 -79
- package/src/analysis/endpoints/extract.js +0 -120
- package/src/analysis/endpoints/inventory.js +0 -84
- package/src/analysis/endpoints/mounts.js +0 -129
- package/src/analysis/endpoints-java.js +0 -260
- package/src/analysis/endpoints-rust.js +0 -124
- package/src/analysis/endpoints.js +0 -3
- package/src/analysis/findings.js +0 -70
- package/src/analysis/git-history/analytics.js +0 -177
- package/src/analysis/git-history/collector.js +0 -67
- package/src/analysis/git-history/options.js +0 -66
- package/src/analysis/git-history.js +0 -143
- package/src/analysis/git-ref-graph.js +0 -76
- package/src/analysis/go-dependency-evidence.js +0 -62
- package/src/analysis/graph-analysis.aggregate.js +0 -296
- package/src/analysis/graph-analysis.edges.js +0 -24
- package/src/analysis/graph-analysis.js +0 -7
- package/src/analysis/graph-analysis.refs.js +0 -202
- package/src/analysis/graph-analysis.summaries.js +0 -65
- package/src/analysis/health-capabilities.js +0 -83
- package/src/analysis/hot-path-review.js +0 -266
- package/src/analysis/http-contract-wrappers.js +0 -241
- package/src/analysis/http-contracts/analysis.js +0 -179
- package/src/analysis/http-contracts/client-call-detection.js +0 -82
- package/src/analysis/http-contracts/client-call-parser.js +0 -273
- package/src/analysis/http-contracts/graph-context.js +0 -143
- package/src/analysis/http-contracts/matching.js +0 -61
- package/src/analysis/http-contracts/shared.js +0 -85
- package/src/analysis/http-contracts.js +0 -6
- package/src/analysis/internal-audit/dependency-health.js +0 -113
- package/src/analysis/internal-audit/python-manifests.js +0 -78
- package/src/analysis/internal-audit/repo-files.js +0 -50
- package/src/analysis/internal-audit/supply-chain.js +0 -149
- package/src/analysis/internal-audit.collect.js +0 -213
- package/src/analysis/internal-audit.js +0 -9
- package/src/analysis/internal-audit.reach.js +0 -201
- package/src/analysis/internal-audit.run.js +0 -256
- package/src/analysis/java-source.js +0 -36
- package/src/analysis/jvm-artifact-index.js +0 -87
- package/src/analysis/jvm-dependency-evidence.js +0 -138
- package/src/analysis/jvm-manifests.js +0 -114
- package/src/analysis/manifests.js +0 -123
- package/src/analysis/package-reachability.js +0 -39
- package/src/analysis/source-complexity.ast.js +0 -97
- package/src/analysis/source-complexity.constants.js +0 -55
- package/src/analysis/source-complexity.js +0 -14
- package/src/analysis/source-complexity.report.js +0 -81
- package/src/analysis/source-complexity.walk.js +0 -228
- package/src/analysis/source-correctness/retry-patterns.js +0 -93
- package/src/analysis/source-correctness.js +0 -222
- package/src/analysis/static-test-reachability.js +0 -150
- package/src/analysis/structure/dependency-graph.js +0 -151
- package/src/analysis/structure/findings.js +0 -162
- package/src/analysis/task-retrieval.js +0 -107
- package/src/analysis/transport-contracts.js +0 -224
- package/src/analysis/transport-runtime-evidence.js +0 -155
- package/src/analysis-kit.mjs +0 -17
- package/src/bounds.js +0 -4
- package/src/build-graph.js +0 -209
- package/src/child-env.js +0 -7
- package/src/config.js +0 -5
- package/src/extension/local-services.mjs +0 -75
- package/src/git-exec.js +0 -67
- package/src/graph/build-worker.js +0 -49
- package/src/graph/builder/go-receiver-resolution.js +0 -112
- package/src/graph/builder/js/dynamic-import.js +0 -26
- package/src/graph/builder/js/queries.js +0 -48
- package/src/graph/builder/lang-csharp.js +0 -40
- package/src/graph/builder/lang-css.js +0 -29
- package/src/graph/builder/lang-go.js +0 -140
- package/src/graph/builder/lang-html.js +0 -29
- package/src/graph/builder/lang-java-calls.js +0 -142
- package/src/graph/builder/lang-java.js +0 -215
- package/src/graph/builder/lang-js.js +0 -291
- package/src/graph/builder/lang-python.js +0 -235
- package/src/graph/builder/lang-rust-calls.js +0 -63
- package/src/graph/builder/lang-rust.js +0 -299
- package/src/graph/builder/lang-solidity.js +0 -126
- package/src/graph/builder/lang-sql.js +0 -263
- package/src/graph/builder/pass2-resolution.js +0 -81
- package/src/graph/builder/spec-pkg.js +0 -87
- package/src/graph/community.js +0 -27
- package/src/graph/edge-provenance.js +0 -31
- package/src/graph/file-lock.js +0 -69
- package/src/graph/freshness-probe.js +0 -142
- package/src/graph/graph-filter.js +0 -63
- package/src/graph/incremental-refresh.js +0 -235
- package/src/graph/internal-builder.barrels.js +0 -235
- package/src/graph/internal-builder.build.js +0 -300
- package/src/graph/internal-builder.java.js +0 -33
- package/src/graph/internal-builder.js +0 -12
- package/src/graph/internal-builder.langs.js +0 -157
- package/src/graph/internal-builder.pass2.js +0 -163
- package/src/graph/internal-builder.resolvers.js +0 -286
- package/src/graph/layout.js +0 -51
- package/src/graph/node-id.js +0 -7
- package/src/graph/parser-artifact-boundary.js +0 -55
- package/src/graph/relations.js +0 -4
- package/src/graph/repo-registry.js +0 -124
- package/src/graph/resolvers/rust.js +0 -117
- package/src/infra/infra-items.js +0 -255
- package/src/infra/infra-registry.js +0 -184
- package/src/infra/infra.detect.js +0 -119
- package/src/infra/infra.js +0 -38
- package/src/infra/infra.match.js +0 -102
- package/src/infra/infra.scan.js +0 -93
- package/src/mcp/actions/graph-lifecycle.mjs +0 -148
- package/src/mcp/architecture-bootstrap.mjs +0 -168
- package/src/mcp/architecture-starter.mjs +0 -234
- package/src/mcp/catalog.mjs +0 -233
- package/src/mcp/company-contract-page.mjs +0 -142
- package/src/mcp/company-contract-reconcile.mjs +0 -87
- package/src/mcp/company-contract-verdict.mjs +0 -42
- package/src/mcp/evidence/bun-lock-graph.mjs +0 -209
- package/src/mcp/evidence/duplicate-member-order.mjs +0 -8
- package/src/mcp/evidence/package-graph-common.mjs +0 -115
- package/src/mcp/evidence/package-lock-graph.mjs +0 -92
- package/src/mcp/evidence-snapshot.architecture.mjs +0 -80
- package/src/mcp/evidence-snapshot.common.mjs +0 -158
- package/src/mcp/evidence-snapshot.duplicates.mjs +0 -213
- package/src/mcp/evidence-snapshot.health.mjs +0 -102
- package/src/mcp/evidence-snapshot.inventory.mjs +0 -148
- package/src/mcp/evidence-snapshot.mjs +0 -50
- package/src/mcp/evidence-snapshot.package-graph.mjs +0 -34
- package/src/mcp/evidence-snapshot.structure.mjs +0 -84
- package/src/mcp/extension-api.mjs +0 -77
- package/src/mcp/git-output.mjs +0 -7
- package/src/mcp/graph/context-core.mjs +0 -111
- package/src/mcp/graph/context-seeds.mjs +0 -207
- package/src/mcp/graph/context-state.mjs +0 -85
- package/src/mcp/graph/reverse-reach.mjs +0 -42
- package/src/mcp/graph/tools-core.mjs +0 -143
- package/src/mcp/graph/tools-query.mjs +0 -276
- package/src/mcp/graph-context.mjs +0 -5
- package/src/mcp/graph-diff.mjs +0 -218
- package/src/mcp/health/audit-format.mjs +0 -199
- package/src/mcp/health/audit.mjs +0 -199
- package/src/mcp/health/dead-code.mjs +0 -110
- package/src/mcp/health/duplicates.mjs +0 -121
- package/src/mcp/health/endpoints.mjs +0 -71
- package/src/mcp/health/structure.mjs +0 -220
- package/src/mcp/runtime-version.mjs +0 -31
- package/src/mcp/server/auto-refresh.mjs +0 -66
- package/src/mcp/server/runtime-config.mjs +0 -43
- package/src/mcp/server/shutdown.mjs +0 -40
- package/src/mcp/staleness-notice.mjs +0 -20
- package/src/mcp/sync/evidence-architecture.mjs +0 -54
- package/src/mcp/sync/evidence-common.mjs +0 -88
- package/src/mcp/sync/evidence-duplicates.mjs +0 -97
- package/src/mcp/sync/evidence-health.mjs +0 -56
- package/src/mcp/sync/evidence-packages.mjs +0 -95
- package/src/mcp/sync/payload-common.mjs +0 -97
- package/src/mcp/sync/payload-v2.mjs +0 -54
- package/src/mcp/sync/payload-v3.mjs +0 -79
- package/src/mcp/sync-evidence.mjs +0 -23
- package/src/mcp/sync-payload.mjs +0 -70
- package/src/mcp/tool-result.mjs +0 -54
- package/src/mcp/tools-actions.mjs +0 -11
- package/src/mcp/tools-architecture.mjs +0 -177
- package/src/mcp/tools-company.mjs +0 -251
- package/src/mcp/tools-context.mjs +0 -222
- package/src/mcp/tools-endpoints.mjs +0 -207
- package/src/mcp/tools-graph-hubs.mjs +0 -78
- package/src/mcp/tools-graph.mjs +0 -17
- package/src/mcp/tools-health.mjs +0 -24
- package/src/mcp/tools-history.mjs +0 -28
- package/src/mcp/tools-impact-change.mjs +0 -220
- package/src/mcp/tools-impact-precision.mjs +0 -89
- package/src/mcp/tools-impact.mjs +0 -169
- package/src/mcp/tools-source.mjs +0 -238
- package/src/mcp/tools-verified-change.mjs +0 -200
- package/src/mcp-rg.mjs +0 -50
- package/src/mcp-runtime.mjs +0 -2
- package/src/mcp-server.mjs +0 -298
- package/src/mcp-source-tools.mjs +0 -163
- package/src/path-classification.js +0 -226
- package/src/path-ignore.js +0 -69
- package/src/precision/lsp-client/constants.js +0 -12
- package/src/precision/lsp-client/environment.js +0 -20
- package/src/precision/lsp-client/errors.js +0 -15
- package/src/precision/lsp-client/lifecycle.js +0 -114
- package/src/precision/lsp-client/message-parser.js +0 -81
- package/src/precision/lsp-client/protocol.js +0 -212
- package/src/precision/lsp-client/registry.js +0 -59
- package/src/precision/lsp-client/repo-uri.js +0 -60
- package/src/precision/lsp-client/stdio-client.js +0 -140
- package/src/precision/lsp-client.js +0 -10
- package/src/precision/lsp-overlay/budget-policy.js +0 -78
- package/src/precision/lsp-overlay/build.js +0 -261
- package/src/precision/lsp-overlay/contract.js +0 -61
- package/src/precision/lsp-overlay/reference-results.js +0 -108
- package/src/precision/lsp-overlay/semantic-inputs.js +0 -62
- package/src/precision/lsp-overlay/source-session.js +0 -142
- package/src/precision/lsp-overlay/store.js +0 -150
- package/src/precision/lsp-overlay/target-index.js +0 -152
- package/src/precision/lsp-overlay/target-query.js +0 -55
- package/src/precision/lsp-overlay.js +0 -11
- package/src/precision/symbol-query.js +0 -224
- package/src/precision/typescript-lsp-provider.js +0 -12
- package/src/precision/typescript-provider/client.js +0 -89
- package/src/precision/typescript-provider/discovery.js +0 -124
- package/src/precision/typescript-provider/isolated-runtime.js +0 -39
- package/src/precision/typescript-provider/project-host.js +0 -254
- package/src/precision/typescript-provider/project-safety.js +0 -166
- package/src/precision/typescript-provider/reference-usage.js +0 -53
- package/src/process.js +0 -95
- package/src/repo-path.js +0 -53
- package/src/scan/discover.inventory.js +0 -78
- package/src/scan/discover.js +0 -5
- package/src/scan/discover.list.js +0 -79
- package/src/scan/discover.stack.js +0 -227
- package/src/scan/search.core.js +0 -24
- package/src/scan/search.git.js +0 -102
- package/src/scan/search.js +0 -9
- package/src/scan/search.node.js +0 -83
- package/src/scan/search.preview.js +0 -49
- package/src/scan/search.rg.js +0 -145
- package/src/security/advisory-store.js +0 -172
- package/src/security/installed-jvm-rust.js +0 -46
- package/src/security/installed.js +0 -280
- package/src/security/malware-file-heuristics.js +0 -121
- package/src/security/malware-heuristics.exclusions.js +0 -134
- package/src/security/malware-heuristics.js +0 -15
- package/src/security/malware-heuristics.roots.js +0 -145
- package/src/security/malware-heuristics.scan.js +0 -89
- package/src/security/malware-heuristics.sweep.js +0 -122
- package/src/security/malware-scoring.js +0 -105
- package/src/security/match.js +0 -85
- package/src/security/registry-sig.classify.js +0 -137
- package/src/security/registry-sig.js +0 -18
- package/src/security/registry-sig.rules.js +0 -192
- package/src/security/rust-advisory-report.js +0 -60
- package/src/security/typosquat.js +0 -81
- package/src/util.js +0 -40
- package/src/version.js +0 -7
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
// Orchestrator for the internal graph builder: the two-pass parse loop, community bucketing, and the
|
|
2
|
-
// graph.json writer. (Split from internal-builder.js — see its doc comment for the overall architecture;
|
|
3
|
-
// the language registry / parser lifecycle / walk live in ./internal-builder.langs.js and the per-repo
|
|
4
|
-
// resolvers in ./internal-builder.resolvers.js.)
|
|
5
|
-
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
6
|
-
import { extname, relative, dirname } from "node:path";
|
|
7
|
-
import { specToPkg } from "./builder/spec-pkg.js";
|
|
8
|
-
import { analyzeSyntaxComplexity } from "../analysis/source-complexity.js";
|
|
9
|
-
import { Parser, Query, GRAMMARS, LANGS, EXT_LANG, FAMILY, isDataFile, isDocFile, MAX_PARSE_BYTES, ensureParser, walk } from "./internal-builder.langs.js";
|
|
10
|
-
import { buildResolvers } from "./internal-builder.resolvers.js";
|
|
11
|
-
import { scanEmbeddedSql, resolveSqlReferences } from "./builder/lang-sql.js";
|
|
12
|
-
import { assignDeterministicCommunities } from "./community.js";
|
|
13
|
-
import { snapshotRepository } from "./incremental-refresh.js";
|
|
14
|
-
import { EDGE_PROVENANCE_V, stampEdgeProvenance } from "./edge-provenance.js";
|
|
15
|
-
import {runInternalGraphPass2} from './internal-builder.pass2.js'
|
|
16
|
-
|
|
17
|
-
function physicalLineCount(text) {
|
|
18
|
-
if (!text.length) return 0;
|
|
19
|
-
let lines = 1;
|
|
20
|
-
for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 10) lines++;
|
|
21
|
-
return text.endsWith("\n") ? lines - 1 : lines;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Parse a repo directory into a graph-builder-compatible { nodes, links } graph.
|
|
25
|
-
export async function buildInternalGraph(repoDir, opts = {}) {
|
|
26
|
-
const rel = (p) => relative(repoDir, p).replace(/\\/g, "/");
|
|
27
|
-
const allFiles = walk(repoDir);
|
|
28
|
-
const snapshot = snapshotRepository(repoDir, allFiles);
|
|
29
|
-
const requestedFiles = Array.isArray(opts.includeFiles)
|
|
30
|
-
? new Set(opts.includeFiles.map((file) => String(file).replace(/\\/g, "/").replace(/^\.\//, "")))
|
|
31
|
-
: null;
|
|
32
|
-
const files = requestedFiles ? allFiles.filter((file) => requestedFiles.has(rel(file))) : allFiles;
|
|
33
|
-
// Lazy grammar loading: compile only the WASMs for languages this repo actually contains.
|
|
34
|
-
const wanted = new Set();
|
|
35
|
-
for (const f of files) { const g = EXT_LANG[extname(f)]; if (g) wanted.add(g); }
|
|
36
|
-
const langs = await ensureParser(opts, wanted);
|
|
37
|
-
const qc = new Map();
|
|
38
|
-
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; };
|
|
39
|
-
const caps = (grammar, src, root) => { const query = src && q(grammar, src); return query ? query.captures(root) : []; };
|
|
40
|
-
const field = (n, f) => (n && n.childForFieldName ? n.childForFieldName(f) : null);
|
|
41
|
-
|
|
42
|
-
const fileSet = new Set(allFiles.map(rel));
|
|
43
|
-
const nodes = []; const links = []; const nodeIds = new Set(); const nodeById = new Map();
|
|
44
|
-
const addNode = (n) => { if (!nodeIds.has(n.id)) { nodeIds.add(n.id); nodes.push(n); nodeById.set(n.id, n); } };
|
|
45
|
-
const perFileSymbols = new Map();
|
|
46
|
-
const symByFileName = new Map();
|
|
47
|
-
const symIdsByFileName = new Map();
|
|
48
|
-
const importedLocals = new Map();
|
|
49
|
-
const jsExports = new Map();
|
|
50
|
-
if (requestedFiles && opts.baseGraph?.jsExportRecords) {
|
|
51
|
-
for (const [file, records] of Object.entries(opts.baseGraph.jsExportRecords)) {
|
|
52
|
-
if (!requestedFiles.has(file) && Array.isArray(records)) jsExports.set(file, records.map((record) => ({ ...record })));
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (requestedFiles && Array.isArray(opts.baseGraph?.nodes)) {
|
|
56
|
-
for (const node of opts.baseGraph.nodes) {
|
|
57
|
-
const id = String(node?.id || "");
|
|
58
|
-
const file = String(node?.source_file || (id.includes("#") ? id.slice(0, id.indexOf("#")) : id)).replace(/\\/g, "/");
|
|
59
|
-
if (!id.includes("#") || requestedFiles.has(file) || !fileSet.has(file)) continue;
|
|
60
|
-
const match = id.match(/#([A-Za-z_$][\w$]*)@\d+/);
|
|
61
|
-
if (!match) continue;
|
|
62
|
-
let names = symByFileName.get(file);
|
|
63
|
-
if (!names) symByFileName.set(file, (names = new Map()));
|
|
64
|
-
if (!names.has(match[1])) names.set(match[1], id);
|
|
65
|
-
let idsByName = symIdsByFileName.get(file);
|
|
66
|
-
if (!idsByName) symIdsByFileName.set(file, (idsByName = new Map()));
|
|
67
|
-
const ids = idsByName.get(match[1]) || [];
|
|
68
|
-
ids.push(id);
|
|
69
|
-
idsByName.set(match[1], ids);
|
|
70
|
-
nodeById.set(id, node);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// Bare-package imports (axios, node:fs, @scope/x) — the graph can't resolve them to a repo file, but
|
|
74
|
-
// dependency analysis NEEDS them (unused/missing deps). Additive top-level array; nodes/links untouched.
|
|
75
|
-
const externalImports = [];
|
|
76
|
-
// SQL references (from .sql statements AND string literals in host-language code) collect during
|
|
77
|
-
// pass 1 and resolve after both passes, once every schema object the repo declares is indexed.
|
|
78
|
-
const sqlRefs = [];
|
|
79
|
-
|
|
80
|
-
const resolvers = buildResolvers(repoDir, fileSet); // aliases, go.mod, java index, href, selectors
|
|
81
|
-
const { selectorIndex, htmlUsages } = resolvers;
|
|
82
|
-
|
|
83
|
-
// ---- pass 1: files + symbols + imports (dispatched to each language module) ----
|
|
84
|
-
// This runs on Electron's MAIN thread (the worker path hung web-tree-sitter's WASM in an Electron worker
|
|
85
|
-
// thread → the infinite "BUILDING GRAPH…"). Parsing is synchronous CPU, so we YIELD the event loop every
|
|
86
|
-
// few dozen files to keep the window responsive during a big-repo build, and SKIP giant/minified files
|
|
87
|
-
// (a multi-MB single-line bundle can wedge the tree-sitter parse).
|
|
88
|
-
let _parsed = 0;
|
|
89
|
-
for (const abs of files) {
|
|
90
|
-
const fileRel = rel(abs); const ext = extname(abs);
|
|
91
|
-
const fileNode = { id: fileRel, label: fileRel.split("/").pop(), file_type: "code", source_file: fileRel, source_location: "L1" };
|
|
92
|
-
if (isDataFile(fileRel) || isDocFile(fileRel)) {
|
|
93
|
-
addNode(fileNode); perFileSymbols.set(fileRel, []); symByFileName.set(fileRel, new Map()); symIdsByFileName.set(fileRel, new Map()); continue;
|
|
94
|
-
} // config/infra/docs file-only node
|
|
95
|
-
let code; try { code = readFileSync(abs, "utf8"); } catch { addNode(fileNode); continue; }
|
|
96
|
-
addNode({ ...fileNode, physical_loc: physicalLineCount(code) });
|
|
97
|
-
const grammar = EXT_LANG[ext]; const lang = LANGS[FAMILY[grammar]]; if (!lang || (!langs[grammar] && !lang.textOnly)) continue;
|
|
98
|
-
// giant / generated / minified file → keep the file NODE but don't parse symbols (avoids a wedged parse)
|
|
99
|
-
if (code.length > MAX_PARSE_BYTES) { perFileSymbols.set(fileRel, []); symByFileName.set(fileRel, new Map()); symIdsByFileName.set(fileRel, new Map()); continue; }
|
|
100
|
-
if ((++_parsed % 24) === 0) await new Promise((r) => setImmediate(r)); // breathe: let the UI paint between chunks
|
|
101
|
-
if (typeof opts.onParseFile === "function") opts.onParseFile(fileRel);
|
|
102
|
-
let tree = null; // textOnly languages (SQL) scan `code` directly — no grammar, no parse
|
|
103
|
-
if (!lang.textOnly) {
|
|
104
|
-
const parser = new Parser(); parser.setLanguage(langs[grammar]);
|
|
105
|
-
try { tree = parser.parse(code); } catch { continue; }
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const syms = []; const nameToId = new Map(); const nameToIds = new Map(); const moduleNameToId = new Map();
|
|
109
|
-
const addSym = (name, line, callable, extra) => {
|
|
110
|
-
if (!name || !/^[A-Za-z_$][\w$]*$/.test(name)) return;
|
|
111
|
-
const suffix = /^:[A-Za-z0-9_-]+$/.test(extra?.idSuffix || "") ? extra.idSuffix : "";
|
|
112
|
-
const id = `${fileRel}#${name}@${line}${suffix}`; if (nodeIds.has(id)) return;
|
|
113
|
-
const sourceNode = extra && extra.sourceNode;
|
|
114
|
-
const selectionNode = extra && extra.selectionNode;
|
|
115
|
-
const endLine = sourceNode?.endPosition ? sourceNode.endPosition.row + 1 : 0;
|
|
116
|
-
let complexity = null;
|
|
117
|
-
if (callable && sourceNode) {
|
|
118
|
-
try { complexity = analyzeSyntaxComplexity(sourceNode, { family: lang.family, name }); }
|
|
119
|
-
catch { complexity = null; }
|
|
120
|
-
}
|
|
121
|
-
addNode({
|
|
122
|
-
id,
|
|
123
|
-
label: callable ? `${name}()` : name,
|
|
124
|
-
...(callable ? { callable: true } : {}),
|
|
125
|
-
file_type: "code",
|
|
126
|
-
source_file: fileRel,
|
|
127
|
-
source_location: `L${line}`,
|
|
128
|
-
...(endLine >= line ? { source_end: `L${endLine}` } : {}),
|
|
129
|
-
...(sourceNode?.startPosition && sourceNode?.endPosition ? {
|
|
130
|
-
// web-tree-sitter Point columns are zero-based UTF-16 code-unit offsets. Keep the
|
|
131
|
-
// declaration body range as well as the identifier selection so LSP reference
|
|
132
|
-
// locations on a boundary line cannot be attributed to the wrong symbol.
|
|
133
|
-
source_range: {
|
|
134
|
-
start: {
|
|
135
|
-
line: sourceNode.startPosition.row,
|
|
136
|
-
character: sourceNode.startPosition.column,
|
|
137
|
-
},
|
|
138
|
-
end: {
|
|
139
|
-
line: sourceNode.endPosition.row,
|
|
140
|
-
character: sourceNode.endPosition.column,
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
} : {}),
|
|
144
|
-
...(selectionNode?.startPosition && selectionNode?.endPosition ? {
|
|
145
|
-
// web-tree-sitter's JavaScript Point columns are already zero-based UTF-16 code-unit
|
|
146
|
-
// offsets, matching LSP positions exactly (including text before non-ASCII identifiers).
|
|
147
|
-
selection_start: {
|
|
148
|
-
line: selectionNode.startPosition.row,
|
|
149
|
-
character: selectionNode.startPosition.column,
|
|
150
|
-
},
|
|
151
|
-
selection_end: {
|
|
152
|
-
line: selectionNode.endPosition.row,
|
|
153
|
-
character: selectionNode.endPosition.column,
|
|
154
|
-
},
|
|
155
|
-
} : {}),
|
|
156
|
-
...(complexity ? { complexity } : {}),
|
|
157
|
-
...(extra && extra.exported ? { exported: true } : {}),
|
|
158
|
-
...(extra && extra.testSurface ? { test_surface: true } : {}),
|
|
159
|
-
...(extra && extra.decorated ? { decorated: true } : {}),
|
|
160
|
-
...(extra && extra.symbolKind ? { symbol_kind: extra.symbolKind } : {}),
|
|
161
|
-
...(extra && extra.symbolSpace ? { symbol_space: extra.symbolSpace } : {}),
|
|
162
|
-
...(extra && extra.memberOf ? { member_of: extra.memberOf } : {}),
|
|
163
|
-
...(extra && extra.visibility ? { visibility: extra.visibility } : {}),
|
|
164
|
-
...(Number.isInteger(extra?.parameterCount) ? { parameter_count: extra.parameterCount } : {}),
|
|
165
|
-
...(extra?.receiverType ? { receiver_type: extra.receiverType } : {}),
|
|
166
|
-
...(extra?.returnType ? { return_type: extra.returnType } : {}),
|
|
167
|
-
...(extra?.fieldTypes && Object.keys(extra.fieldTypes).length ? { field_types: extra.fieldTypes } : {})
|
|
168
|
-
});
|
|
169
|
-
links.push({ source: fileRel, target: id, relation: "contains", confidence: "EXTRACTED" });
|
|
170
|
-
syms.push({
|
|
171
|
-
id,
|
|
172
|
-
name,
|
|
173
|
-
start: line,
|
|
174
|
-
end: endLine >= line ? endLine : 0,
|
|
175
|
-
...(extra?.memberOf ? {memberOf: extra.memberOf} : {}),
|
|
176
|
-
...(extra?.symbolKind ? {symbolKind: extra.symbolKind} : {}),
|
|
177
|
-
...(extra?.symbolSpace ? {symbolSpace: extra.symbolSpace} : {}),
|
|
178
|
-
...(Number.isInteger(extra?.parameterCount) ? {parameterCount: extra.parameterCount} : {}),
|
|
179
|
-
});
|
|
180
|
-
if (!nameToId.has(name)) nameToId.set(name, id);
|
|
181
|
-
const ids = nameToIds.get(name) || [];
|
|
182
|
-
ids.push(id);
|
|
183
|
-
nameToIds.set(name, ids);
|
|
184
|
-
if (extra?.moduleDeclaration && !moduleNameToId.has(name)) moduleNameToId.set(name, id);
|
|
185
|
-
return id;
|
|
186
|
-
};
|
|
187
|
-
const imports = new Map(); importedLocals.set(fileRel, imports);
|
|
188
|
-
const recordJsExport = (record) => {
|
|
189
|
-
if (!record) return;
|
|
190
|
-
const records = jsExports.get(fileRel) || [];
|
|
191
|
-
records.push(record);
|
|
192
|
-
jsExports.set(fileRel, records);
|
|
193
|
-
};
|
|
194
|
-
const addImportEdge = (tgt, meta = {}) => {
|
|
195
|
-
if (!tgt || tgt === fileRel) return;
|
|
196
|
-
links.push({
|
|
197
|
-
source: fileRel,
|
|
198
|
-
target: tgt,
|
|
199
|
-
relation: meta.relation || "imports",
|
|
200
|
-
confidence: "EXTRACTED",
|
|
201
|
-
provenance: meta.provenance || "RESOLVED",
|
|
202
|
-
...(typeof meta.typeOnly === "boolean" ? { typeOnly: meta.typeOnly } : {}),
|
|
203
|
-
...(meta.compileOnly === true ? { compileOnly: true } : {}),
|
|
204
|
-
...(meta.line ? { line: meta.line } : {}),
|
|
205
|
-
...(meta.specifier ? { specifier: meta.specifier } : {}),
|
|
206
|
-
});
|
|
207
|
-
};
|
|
208
|
-
// rec: {spec, kind, line} bare-pkg import · {dynamic:true, spec?, target?} dynamic import marker
|
|
209
|
-
// (target = internally-resolved dynamic import; suppresses false "unused file" in dep analysis) ·
|
|
210
|
-
// {unresolved:true, spec} broken local import (relative or alias path that resolves to no file).
|
|
211
|
-
const addExternalImport = (rec) => {
|
|
212
|
-
if (!rec) return;
|
|
213
|
-
if (rec.dynamic) { externalImports.push({ file: fileRel, spec: rec.spec || null, kind: rec.kind || "dynamic", dynamic: true, line: rec.line || 0, ...(rec.target ? { target: rec.target } : {}), ...(rec.typeOnly ? { typeOnly: true } : {}) }); return; }
|
|
214
|
-
if (rec.unresolved) { externalImports.push({ file: fileRel, spec: rec.spec, kind: rec.kind || "esm", unresolved: true, line: rec.line || 0, ...(rec.typeOnly ? { typeOnly: true } : {}) }); return; }
|
|
215
|
-
// non-npm extractors (go/python) classify their own specs and pass pkg/builtin/ecosystem precomputed
|
|
216
|
-
if (rec.pkg) { externalImports.push({ file: fileRel, spec: rec.spec, pkg: rec.pkg, builtin: !!rec.builtin, kind: rec.kind || "import", line: rec.line || 0, ...(rec.ecosystem ? { ecosystem: rec.ecosystem } : {}), ...(rec.typeOnly ? { typeOnly: true } : {}) }); return; }
|
|
217
|
-
const r = specToPkg(rec.spec);
|
|
218
|
-
if (!r) return;
|
|
219
|
-
externalImports.push({ file: fileRel, spec: rec.spec, pkg: r.pkg, builtin: !!r.builtin, kind: rec.kind || "esm", line: rec.line || 0, ...(rec.typeOnly ? { typeOnly: true } : {}) });
|
|
220
|
-
};
|
|
221
|
-
// Post-hoc export flag (export {a}, export default X, CJS module.exports) — declarations are flagged at addSym time.
|
|
222
|
-
const markExported = (name) => { const id = moduleNameToId.get(name); const n = id && nodeById.get(id); if (n) n.exported = true; };
|
|
223
|
-
|
|
224
|
-
try { lang.pass1({ grammar, tree, fileRel, code, caps, field, addSym, addNode, links, nodeIds, syms, nameToId, imports, addImportEdge, addExternalImport, markExported, recordJsExport, fileSet, sqlRefs, ...resolvers }); }
|
|
225
|
-
catch (e) { /* one bad file never sinks the whole build */ void e; }
|
|
226
|
-
// string-literal SQL in host-language code → schema reference candidates (resolved post-pass-2)
|
|
227
|
-
if (!lang.textOnly && !lang.isWeb) try { scanEmbeddedSql(code, fileRel, sqlRefs); } catch { /* never sinks the build */ }
|
|
228
|
-
|
|
229
|
-
syms.sort((a, b) => a.start - b.start);
|
|
230
|
-
const eof = code.split("\n").length;
|
|
231
|
-
for (let i = 0; i < syms.length; i++) {
|
|
232
|
-
if (!syms[i].end || syms[i].end < syms[i].start) syms[i].end = i + 1 < syms.length ? syms[i + 1].start - 1 : eof;
|
|
233
|
-
}
|
|
234
|
-
perFileSymbols.set(fileRel, syms); symByFileName.set(fileRel, nameToId); symIdsByFileName.set(fileRel, nameToIds);
|
|
235
|
-
if (tree) tree.delete();
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// ---- pass 2: scope-aware calls + inheritance (Go package = whole dir → same-dir symbols share scope;
|
|
239
|
-
// C# gets the same treatment: one folder ≈ one namespace by convention, and `using` names namespaces,
|
|
240
|
-
// not files, so the folder map is the only reliable cross-file resolver) ----
|
|
241
|
-
const {reExportOccurrences} = runInternalGraphPass2({
|
|
242
|
-
files, rel, langs, caps, field, links, nodeById, perFileSymbols, symByFileName,
|
|
243
|
-
symIdsByFileName, importedLocals, jsExports, resolvers,
|
|
244
|
-
});
|
|
245
|
-
// HTML class/id usage → the CSS file(s) defining that selector: file-level reference edges (deduped per pair).
|
|
246
|
-
const htmlRefSeen = new Set();
|
|
247
|
-
for (const u of htmlUsages) {
|
|
248
|
-
const defs = selectorIndex.get(u.label); if (!defs) continue;
|
|
249
|
-
for (const cssFile of defs) {
|
|
250
|
-
if (cssFile === u.htmlFile) continue;
|
|
251
|
-
const key = u.htmlFile + ">" + cssFile; if (htmlRefSeen.has(key)) continue; htmlRefSeen.add(key);
|
|
252
|
-
links.push({ source: u.htmlFile, target: cssFile, relation: "references", confidence: "INFERRED" });
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
// code/SQL → schema-object edges (tables/views/functions declared in .sql files)
|
|
256
|
-
try { resolveSqlReferences({ sqlRefs, links, nodeById, perFileSymbols }); } catch { /* never sinks the build */ }
|
|
257
|
-
|
|
258
|
-
// community = folder bucket (top 2 path parts) — deterministic, mirrors the folder-based module grouping the
|
|
259
|
-
// app already uses (graph-builder-analysis.js). Populates Modules/community cards without a heavy clustering pass.
|
|
260
|
-
assignDeterministicCommunities(nodes);
|
|
261
|
-
stampEdgeProvenance(links);
|
|
262
|
-
|
|
263
|
-
// extImportsV: bump when the externalImports schema/coverage changes (v3 = Java/Rust ecosystems) —
|
|
264
|
-
// deps-engine rebuilds in memory when a saved graph is older than this.
|
|
265
|
-
// edgeTypesV 2 adds language-neutral compile-only edges (currently Rust mod/use/re-export) on top
|
|
266
|
-
// of v1's TypeScript typeOnly classification.
|
|
267
|
-
return {
|
|
268
|
-
nodes,
|
|
269
|
-
links,
|
|
270
|
-
externalImports,
|
|
271
|
-
extImportsV: 3,
|
|
272
|
-
edgeTypesV: 2,
|
|
273
|
-
edgeProvenanceV: EDGE_PROVENANCE_V,
|
|
274
|
-
complexityV: 2,
|
|
275
|
-
physicalFileLocV: 1,
|
|
276
|
-
repoBoundaryV: 1,
|
|
277
|
-
barrelResolutionV: 1,
|
|
278
|
-
reExportOccurrencesV: 1,
|
|
279
|
-
symbolSpacesV: 1,
|
|
280
|
-
extractorSchemaV: 7, // v7 = Solidity + SQL indexing (schema objects, embedded-SQL edges)
|
|
281
|
-
reExportOccurrences,
|
|
282
|
-
jsExportRecords: Object.fromEntries([...jsExports.entries()].sort(([a], [b]) => a.localeCompare(b))),
|
|
283
|
-
fileHashes: snapshot.fileHashes,
|
|
284
|
-
fileExportSignatures: snapshot.fileExportSignatures,
|
|
285
|
-
controlHashes: snapshot.controlHashes,
|
|
286
|
-
graphRevision: snapshot.revision,
|
|
287
|
-
...(requestedFiles ? { incrementalScope: true } : {}),
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Build + write graph.json to outPath (creating the dir). Returns { ok, nodes, links, graphJson }.
|
|
292
|
-
export async function writeInternalGraph(repoDir, outPath, opts = {}) {
|
|
293
|
-
if (Array.isArray(opts.includeFiles)) throw new Error("refusing to write a scoped incremental graph as a complete graph");
|
|
294
|
-
const graph = await buildInternalGraph(repoDir, opts);
|
|
295
|
-
mkdirSync(dirname(outPath), { recursive: true });
|
|
296
|
-
writeFileSync(outPath, JSON.stringify(graph), "utf8");
|
|
297
|
-
return { ok: true, nodes: graph.nodes.length, links: graph.links.length, graphJson: outPath };
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
export const INTERNAL_BUILDER_LANGS = GRAMMARS;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// Resolve Java type usages only when they land on declarations that exist in the graph. Synthetic nodes for
|
|
2
|
-
// String/List/annotations inflate metrics without adding navigation value, so unresolved/external types vanish.
|
|
3
|
-
export function addJavaReferences({ grammar, tree, fileRel, caps, resolveJavaType, enclosing, links }) {
|
|
4
|
-
const refSeen = new Set();
|
|
5
|
-
const isHeritage = (node) => {
|
|
6
|
-
let current = node?.parent;
|
|
7
|
-
for (let hops = 0; current && hops < 8; hops++, current = current.parent) {
|
|
8
|
-
if (["superclass", "super_interfaces", "extends_interfaces"].includes(current.type)) return true;
|
|
9
|
-
if (["class_declaration", "interface_declaration", "enum_declaration", "record_declaration"].includes(current.type)) return false;
|
|
10
|
-
}
|
|
11
|
-
return false;
|
|
12
|
-
};
|
|
13
|
-
const emitTypeRef = (name, node) => {
|
|
14
|
-
if (!name || isHeritage(node)) return;
|
|
15
|
-
const target = resolveJavaType(name, fileRel);
|
|
16
|
-
if (!target) return;
|
|
17
|
-
const owner = enclosing(fileRel, node.startPosition.row + 1);
|
|
18
|
-
const source = owner?.id || fileRel;
|
|
19
|
-
if (source === target) return;
|
|
20
|
-
const key = `${source}>${target}`;
|
|
21
|
-
if (refSeen.has(key)) return;
|
|
22
|
-
refSeen.add(key);
|
|
23
|
-
links.push({ source, target, relation: "references", confidence: "INFERRED", usage: "type", line: node.startPosition.row + 1 });
|
|
24
|
-
};
|
|
25
|
-
for (const cap of caps(grammar, `(type_identifier) @type`, tree.rootNode)) {
|
|
26
|
-
// A qualified type is handled once by its outer scoped_type_identifier. Inner package segments could
|
|
27
|
-
// otherwise bind to unrelated same-named project types.
|
|
28
|
-
if (cap.node.parent?.type !== "scoped_type_identifier") emitTypeRef(cap.node.text, cap.node);
|
|
29
|
-
}
|
|
30
|
-
for (const cap of caps(grammar, `(scoped_type_identifier) @type`, tree.rootNode)) {
|
|
31
|
-
if (cap.node.parent?.type !== "scoped_type_identifier") emitTypeRef(cap.node.text.split(".").pop(), cap.node);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Built-in, dependency-free code-graph builder: parses a repo with web-tree-sitter (WASM grammars,
|
|
2
|
-
// no Python/native tooling) and emits graph.json ({nodes: files+symbols, links:
|
|
3
|
-
// contains/imports/calls/inherits}) for the analysis pipeline.
|
|
4
|
-
//
|
|
5
|
-
// ARCHITECTURE: this file is a slim FACADE so external import paths stay unchanged. The orchestrator
|
|
6
|
-
// (file walk dispatch, the two-pass loop, community, graph.json writer) lives in ./internal-builder.build.js;
|
|
7
|
-
// the language registry, web-tree-sitter parser lifecycle, and the cycle-safe file walk live in
|
|
8
|
-
// ./internal-builder.langs.js; the per-repo resolvers (JS/TS aliases, go.mod, java index, href, CSS
|
|
9
|
-
// selector index) live in ./internal-builder.resolvers.js. Each language lives in its OWN module under
|
|
10
|
-
// ./builder/lang-*.js and declares its grammars, file extensions, tree-sitter queries, and a pass1(ctx)
|
|
11
|
-
// extractor. To add/fix a language, edit only its module (or add one to LANG_MODULES).
|
|
12
|
-
export { buildInternalGraph, writeInternalGraph, INTERNAL_BUILDER_LANGS } from "./internal-builder.build.js";
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
// Language registry, parser lifecycle (web-tree-sitter init + grammar loading), and the cycle-safe
|
|
2
|
-
// repo file walk for the internal graph builder (split from internal-builder.js — see its doc comment).
|
|
3
|
-
//
|
|
4
|
-
// Loaded via createRequire: web-tree-sitter's ESM build throws on fs/promises in pure-ESM Node, but its CJS
|
|
5
|
-
// build works — and Electron main runs Node, so this needs no external runtime.
|
|
6
|
-
import { readdirSync, statSync, realpathSync } from "node:fs";
|
|
7
|
-
import { join, extname, dirname } from "node:path";
|
|
8
|
-
import { createRequire } from "node:module";
|
|
9
|
-
import { isPathInside } from "../repo-path.js";
|
|
10
|
-
import { runGit } from "../git-exec.js";
|
|
11
|
-
import { filterWeavatrixIgnored } from "../path-ignore.js";
|
|
12
|
-
import {trustedGrammarWasm, trustedRuntimeWasm} from './parser-artifact-boundary.js'
|
|
13
|
-
import LANG_JS from "./builder/lang-js.js";
|
|
14
|
-
import LANG_PY from "./builder/lang-python.js";
|
|
15
|
-
import LANG_GO from "./builder/lang-go.js";
|
|
16
|
-
import LANG_JAVA from "./builder/lang-java.js";
|
|
17
|
-
import LANG_CSHARP from "./builder/lang-csharp.js";
|
|
18
|
-
import LANG_RUST from "./builder/lang-rust.js";
|
|
19
|
-
import LANG_SOLIDITY from "./builder/lang-solidity.js";
|
|
20
|
-
import LANG_SQL from "./builder/lang-sql.js";
|
|
21
|
-
import LANG_HTML from "./builder/lang-html.js";
|
|
22
|
-
import LANG_CSS from "./builder/lang-css.js";
|
|
23
|
-
|
|
24
|
-
const require = createRequire(import.meta.url);
|
|
25
|
-
const { Parser, Language, Query } = require("web-tree-sitter");
|
|
26
|
-
|
|
27
|
-
const WTS_DIR = dirname(require.resolve("web-tree-sitter"));
|
|
28
|
-
const NODE_MODULES = dirname(WTS_DIR);
|
|
29
|
-
const DEFAULT_WASM_DIR = join(NODE_MODULES, "tree-sitter-wasms", "out");
|
|
30
|
-
|
|
31
|
-
// ---- language registry (derived from the per-language modules) ----
|
|
32
|
-
const LANG_MODULES = [LANG_JS, LANG_PY, LANG_GO, LANG_JAVA, LANG_CSHARP, LANG_RUST, LANG_SOLIDITY, LANG_SQL, LANG_HTML, LANG_CSS];
|
|
33
|
-
const LANGS = {}; // family -> module
|
|
34
|
-
const EXT_LANG = {}; // ext -> grammar
|
|
35
|
-
const FAMILY = {}; // grammar -> family
|
|
36
|
-
const GRAMMARS_SET = new Set();
|
|
37
|
-
for (const L of LANG_MODULES) {
|
|
38
|
-
LANGS[L.family] = L;
|
|
39
|
-
for (const g of L.grammars) GRAMMARS_SET.add(g);
|
|
40
|
-
for (const [ext, g] of Object.entries(L.exts)) { EXT_LANG[ext] = g; FAMILY[g] = L.family; }
|
|
41
|
-
}
|
|
42
|
-
const GRAMMARS = [...GRAMMARS_SET];
|
|
43
|
-
|
|
44
|
-
// non-code files graph-builder also indexes as nodes (config/data/scripts) — added as file-only nodes (no symbols),
|
|
45
|
-
// so file counts + import targets (e.g. import cfg from "./x.json") match graph-builder.
|
|
46
|
-
const DATA_EXT = new Set([".json", ".sh", ".ps1", ".yaml", ".yml"]); // config/data/scripts + k8s/skaffold/CI yaml
|
|
47
|
-
const INFRA_NAME = /(^|[\\/])(Dockerfile|Containerfile)(\.[\w.-]+)?$|\.dockerfile$/i; // Dockerfile[.prod], *.dockerfile (no ext)
|
|
48
|
-
const isDataFile = (p) => DATA_EXT.has(extname(p)) || INFRA_NAME.test(String(p));
|
|
49
|
-
// Docs/prose (README, CLAUDE.md, AGENTS.md, docs/*.md, …) are indexed as file-only nodes so the GUI board can
|
|
50
|
-
// render them as NEUTRAL pillars (never dead-code scored) and wire the agent-instruction ones UP to the
|
|
51
|
-
// Claude Code / Codex node. AGENT_DOTFILE lets a few AI-agent instruction dotfiles past the dotfile skip below.
|
|
52
|
-
const DOC_EXT = new Set([".md", ".mdx", ".markdown", ".mdown", ".mkd", ".mkdn", ".rst", ".adoc", ".asciidoc"]);
|
|
53
|
-
const AGENT_DOTFILE = /^\.(cursorrules|windsurfrules|clinerules)$/i;
|
|
54
|
-
const RUNTIME_EVIDENCE = /^\.weavatrix\/(?:reports\/)?transport-runtime\.json$/i;
|
|
55
|
-
const isDocFile = (p) => DOC_EXT.has(extname(p)) || AGENT_DOTFILE.test(String(p).split(/[\\/]/).pop() || "");
|
|
56
|
-
const SKIP = new Set(["node_modules", ".git", "dist", "build", "coverage", "vendor", "weavatrix-graphs", "weavatrix-graphs", ".next", "out", "__pycache__", ".venv", "venv", "env", ".tox", "site-packages", ".mypy_cache", ".pytest_cache"]);
|
|
57
|
-
const MAX_PARSE_BYTES = 1_500_000; // skip parsing files above this (minified bundles / generated blobs wedge tree-sitter)
|
|
58
|
-
|
|
59
|
-
let _ready = null;
|
|
60
|
-
const _langs = {};
|
|
61
|
-
// `wanted` (a Set of grammar names) makes loading LAZY: only grammars for extensions actually present
|
|
62
|
-
// in the repo get compiled. The heavy WASMs (rust ~3MB, c_sharp ~4MB) cost seconds to compile — a tax
|
|
63
|
-
// a JS-only repo must never pay. Omit `wanted` to load everything (old behavior).
|
|
64
|
-
async function ensureParser(opts = {}, wanted = null) {
|
|
65
|
-
if (opts.runtimeWasm != null || opts.wasmDir != null) {
|
|
66
|
-
throw new Error('custom parser artifacts are not supported; Weavatrix loads only pinned package-owned WASM')
|
|
67
|
-
}
|
|
68
|
-
if (!_ready) {
|
|
69
|
-
const runtimeWasm = trustedRuntimeWasm(WTS_DIR)
|
|
70
|
-
_ready = Parser.init({ locateFile: () => runtimeWasm });
|
|
71
|
-
}
|
|
72
|
-
await _ready;
|
|
73
|
-
const list = wanted ? GRAMMARS.filter((g) => wanted.has(g)) : GRAMMARS;
|
|
74
|
-
for (const g of list) if (!_langs[g]) {
|
|
75
|
-
const grammarWasm = trustedGrammarWasm(DEFAULT_WASM_DIR, g)
|
|
76
|
-
try { _langs[g] = await Language.load(grammarWasm); } catch { _langs[g] = null; }
|
|
77
|
-
}
|
|
78
|
-
return _langs;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Cycle-safe directory walk. statSync FOLLOWS symlinks/junctions, so a link pointing at an ancestor would
|
|
82
|
-
// otherwise recurse forever (a/b/link/b/link/…). We dedupe by REAL path (a visited dir is never re-entered)
|
|
83
|
-
// and cap depth as a backstop, so a symlink loop can't wedge the build.
|
|
84
|
-
function walkFallback(dir, acc = [], seen = new Set(), depth = 0, rootReal = null) {
|
|
85
|
-
if (depth > 40) return acc;
|
|
86
|
-
let real; try { real = realpathSync.native(dir); } catch { return acc; }
|
|
87
|
-
if (rootReal == null) rootReal = real;
|
|
88
|
-
if (!isPathInside(rootReal, real)) return acc;
|
|
89
|
-
if (seen.has(real)) return acc;
|
|
90
|
-
seen.add(real);
|
|
91
|
-
let entries;
|
|
92
|
-
try { entries = readdirSync(dir); } catch { return acc; }
|
|
93
|
-
for (const name of entries) {
|
|
94
|
-
if (SKIP.has(name)) continue;
|
|
95
|
-
// dotfiles/dot-dirs are skipped EXCEPT a few AI-agent instruction dotfiles (.cursorrules etc.); dot-DIRS
|
|
96
|
-
// never match AGENT_DOTFILE, so we still never recurse into them (.git/.github/.cursor stay out).
|
|
97
|
-
if (name.startsWith(".") && !AGENT_DOTFILE.test(name)) continue;
|
|
98
|
-
const full = join(dir, name);
|
|
99
|
-
let entryReal; try { entryReal = realpathSync.native(full); } catch { continue; }
|
|
100
|
-
if (!isPathInside(rootReal, entryReal)) continue;
|
|
101
|
-
let st; try { st = statSync(full); } catch { continue; }
|
|
102
|
-
if (st.isDirectory()) walkFallback(full, acc, seen, depth + 1, rootReal);
|
|
103
|
-
// include by KNOWN extension, not by loaded grammar — grammars now load lazily AFTER the walk
|
|
104
|
-
// (the parse passes skip files whose grammar failed to load, so the guarantee is unchanged)
|
|
105
|
-
else { const e = extname(name); if (EXT_LANG[e] || isDataFile(name) || isDocFile(name)) acc.push(full); }
|
|
106
|
-
}
|
|
107
|
-
return acc;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Git already owns the repository's file-universe rules. Asking it for tracked files plus untracked,
|
|
111
|
-
// non-ignored files prevents generated outputs (Electron release/, custom cache dirs, ignored agent files,
|
|
112
|
-
// etc.) from contaminating graph/duplicate/audit results while still indexing new source before it is staged.
|
|
113
|
-
// A repository may be opened without Git (or Git may be unavailable), so failure is deliberately a signal to
|
|
114
|
-
// use the boundary-safe walker above rather than a build failure.
|
|
115
|
-
function gitFileUniverse(dir) {
|
|
116
|
-
const lsFiles = runGit(dir, ["ls-files", "--cached", "--others", "--exclude-standard", "-z"], {
|
|
117
|
-
stdio: ["ignore", "pipe", "ignore"], timeout: 15_000, maxBuffer: 64 * 1024 * 1024,
|
|
118
|
-
});
|
|
119
|
-
if (lsFiles.status !== 0 || lsFiles.error) return null;
|
|
120
|
-
const raw = lsFiles.stdout;
|
|
121
|
-
|
|
122
|
-
// `git -C <dir>` also succeeds when <dir> is merely nested under some parent repository. If that
|
|
123
|
-
// nested directory is ignored by the parent, `ls-files` is empty even though <dir> can be a valid
|
|
124
|
-
// standalone repository root selected by the user (or a repository staged by a test/tool). In
|
|
125
|
-
// that one ambiguous case, fall back to the boundary-safe walker. Preserve an empty universe for
|
|
126
|
-
// an actual Git root so ignored files do not leak back into its graph.
|
|
127
|
-
if (!raw) {
|
|
128
|
-
const top = runGit(dir, ["rev-parse", "--show-toplevel"], {
|
|
129
|
-
stdio: ["ignore", "pipe", "ignore"], timeout: 15_000, maxBuffer: 1024 * 1024,
|
|
130
|
-
});
|
|
131
|
-
if (top.status !== 0 || top.error) return null;
|
|
132
|
-
if (realpathSync.native(String(top.stdout).trim()) !== realpathSync.native(dir)) return null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
let rootReal;
|
|
136
|
-
try { rootReal = realpathSync.native(dir); } catch { return null; }
|
|
137
|
-
const files = [];
|
|
138
|
-
for (const rel of raw.split("\0")) {
|
|
139
|
-
if (!rel) continue;
|
|
140
|
-
if (RUNTIME_EVIDENCE.test(rel.replace(/\\/g, "/"))) continue; // runtime output must not change the source revision it attests
|
|
141
|
-
const full = join(dir, rel);
|
|
142
|
-
let real; try { real = realpathSync.native(full); } catch { continue; } // deleted index entry
|
|
143
|
-
if (!isPathInside(rootReal, real)) continue; // tracked symlink/junction escaping the repo
|
|
144
|
-
let st; try { st = statSync(full); } catch { continue; }
|
|
145
|
-
if (!st.isFile()) continue; // includes neither submodule dirs nor directory-like junctions
|
|
146
|
-
const name = rel.split(/[\\/]/).pop() || "";
|
|
147
|
-
const ext = extname(name);
|
|
148
|
-
if (EXT_LANG[ext] || isDataFile(name) || isDocFile(name)) files.push(full);
|
|
149
|
-
}
|
|
150
|
-
return files;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function walk(dir) {
|
|
154
|
-
return filterWeavatrixIgnored(dir, gitFileUniverse(dir) ?? walkFallback(dir));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export { Parser, Query, GRAMMARS, LANGS, EXT_LANG, FAMILY, isDataFile, isDocFile, MAX_PARSE_BYTES, ensureParser, walk };
|