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.
Files changed (306) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +132 -200
  3. package/bin/native/darwin-arm64/weavatrix +0 -0
  4. package/bin/native/darwin-x64/weavatrix +0 -0
  5. package/bin/native/linux-arm64/weavatrix +0 -0
  6. package/bin/native/linux-x64/weavatrix +0 -0
  7. package/bin/native/win32-arm64/weavatrix.exe +0 -0
  8. package/bin/native/win32-x64/weavatrix.exe +0 -0
  9. package/bin/resolve-binary.mjs +73 -0
  10. package/bin/run-native.mjs +26 -0
  11. package/bin/weavatrix-mcp.mjs +7 -6
  12. package/bin/weavatrix.mjs +5 -0
  13. package/package.json +10 -67
  14. package/server.json +38 -0
  15. package/skill/SKILL.md +62 -374
  16. package/skill/agents/openai.yaml +4 -0
  17. package/skill/references/tool-routing.md +45 -0
  18. package/SECURITY.md +0 -101
  19. package/docs/adr/0001-v0.3-offline-online-split.md +0 -60
  20. package/docs/agent-task-benchmark.md +0 -58
  21. package/docs/releases/v0.2.19.md +0 -33
  22. package/docs/releases/v0.3.0.md +0 -43
  23. package/docs/releases/v0.3.1.md +0 -30
  24. package/docs/releases/v0.3.10.md +0 -76
  25. package/docs/releases/v0.3.11.md +0 -55
  26. package/docs/releases/v0.3.12.md +0 -44
  27. package/docs/releases/v0.3.13.md +0 -34
  28. package/docs/releases/v0.3.14.md +0 -37
  29. package/docs/releases/v0.3.2.md +0 -15
  30. package/docs/releases/v0.3.3.md +0 -25
  31. package/docs/releases/v0.3.4.md +0 -40
  32. package/docs/releases/v0.3.5.md +0 -50
  33. package/docs/releases/v0.3.6.md +0 -44
  34. package/docs/releases/v0.3.7.md +0 -37
  35. package/docs/releases/v0.3.8.md +0 -21
  36. package/docs/releases/v0.3.9.md +0 -36
  37. package/scripts/run-agent-task-benchmark.mjs +0 -118
  38. package/src/analysis/allowed-test-runner.js +0 -70
  39. package/src/analysis/architecture/contract-graph.js +0 -119
  40. package/src/analysis/architecture/contract-schema.js +0 -110
  41. package/src/analysis/architecture/contract-storage.js +0 -35
  42. package/src/analysis/architecture/contract-verification.js +0 -168
  43. package/src/analysis/architecture-contract.js +0 -16
  44. package/src/analysis/audit-debt.js +0 -94
  45. package/src/analysis/audit-extensions.js +0 -60
  46. package/src/analysis/cargo-dependency-evidence.js +0 -108
  47. package/src/analysis/cargo-manifests.js +0 -81
  48. package/src/analysis/change-classification/diff-parser.js +0 -103
  49. package/src/analysis/change-classification/options.js +0 -40
  50. package/src/analysis/change-classification/symbol-classifier.js +0 -177
  51. package/src/analysis/change-classification.js +0 -188
  52. package/src/analysis/coverage-reports-tarpaulin.js +0 -112
  53. package/src/analysis/coverage-reports.js +0 -246
  54. package/src/analysis/cycle-route.js +0 -14
  55. package/src/analysis/data-flow-evidence.js +0 -114
  56. package/src/analysis/dead-check.js +0 -300
  57. package/src/analysis/dead-code-review/candidates.js +0 -194
  58. package/src/analysis/dead-code-review/policy.js +0 -23
  59. package/src/analysis/dead-code-review.js +0 -119
  60. package/src/analysis/dep-check-ecosystems.js +0 -205
  61. package/src/analysis/dep-check.js +0 -290
  62. package/src/analysis/dep-rules.js +0 -10
  63. package/src/analysis/dependency/conventions.js +0 -16
  64. package/src/analysis/dependency/scoped-dependencies.js +0 -51
  65. package/src/analysis/dependency/source-references.js +0 -21
  66. package/src/analysis/duplicate-groups.js +0 -104
  67. package/src/analysis/duplicates-worker.js +0 -11
  68. package/src/analysis/duplicates.compute.js +0 -269
  69. package/src/analysis/duplicates.js +0 -15
  70. package/src/analysis/duplicates.run.js +0 -52
  71. package/src/analysis/duplicates.tokenize.js +0 -199
  72. package/src/analysis/endpoints/common.js +0 -79
  73. package/src/analysis/endpoints/extract.js +0 -120
  74. package/src/analysis/endpoints/inventory.js +0 -84
  75. package/src/analysis/endpoints/mounts.js +0 -129
  76. package/src/analysis/endpoints-java.js +0 -260
  77. package/src/analysis/endpoints-rust.js +0 -124
  78. package/src/analysis/endpoints.js +0 -3
  79. package/src/analysis/findings.js +0 -70
  80. package/src/analysis/git-history/analytics.js +0 -177
  81. package/src/analysis/git-history/collector.js +0 -67
  82. package/src/analysis/git-history/options.js +0 -66
  83. package/src/analysis/git-history.js +0 -143
  84. package/src/analysis/git-ref-graph.js +0 -76
  85. package/src/analysis/go-dependency-evidence.js +0 -62
  86. package/src/analysis/graph-analysis.aggregate.js +0 -296
  87. package/src/analysis/graph-analysis.edges.js +0 -24
  88. package/src/analysis/graph-analysis.js +0 -7
  89. package/src/analysis/graph-analysis.refs.js +0 -202
  90. package/src/analysis/graph-analysis.summaries.js +0 -65
  91. package/src/analysis/health-capabilities.js +0 -83
  92. package/src/analysis/hot-path-review.js +0 -266
  93. package/src/analysis/http-contract-wrappers.js +0 -241
  94. package/src/analysis/http-contracts/analysis.js +0 -179
  95. package/src/analysis/http-contracts/client-call-detection.js +0 -82
  96. package/src/analysis/http-contracts/client-call-parser.js +0 -273
  97. package/src/analysis/http-contracts/graph-context.js +0 -143
  98. package/src/analysis/http-contracts/matching.js +0 -61
  99. package/src/analysis/http-contracts/shared.js +0 -85
  100. package/src/analysis/http-contracts.js +0 -6
  101. package/src/analysis/internal-audit/dependency-health.js +0 -113
  102. package/src/analysis/internal-audit/python-manifests.js +0 -78
  103. package/src/analysis/internal-audit/repo-files.js +0 -50
  104. package/src/analysis/internal-audit/supply-chain.js +0 -149
  105. package/src/analysis/internal-audit.collect.js +0 -213
  106. package/src/analysis/internal-audit.js +0 -9
  107. package/src/analysis/internal-audit.reach.js +0 -201
  108. package/src/analysis/internal-audit.run.js +0 -256
  109. package/src/analysis/java-source.js +0 -36
  110. package/src/analysis/jvm-artifact-index.js +0 -87
  111. package/src/analysis/jvm-dependency-evidence.js +0 -138
  112. package/src/analysis/jvm-manifests.js +0 -114
  113. package/src/analysis/manifests.js +0 -123
  114. package/src/analysis/package-reachability.js +0 -39
  115. package/src/analysis/source-complexity.ast.js +0 -97
  116. package/src/analysis/source-complexity.constants.js +0 -55
  117. package/src/analysis/source-complexity.js +0 -14
  118. package/src/analysis/source-complexity.report.js +0 -81
  119. package/src/analysis/source-complexity.walk.js +0 -228
  120. package/src/analysis/source-correctness/retry-patterns.js +0 -93
  121. package/src/analysis/source-correctness.js +0 -222
  122. package/src/analysis/static-test-reachability.js +0 -150
  123. package/src/analysis/structure/dependency-graph.js +0 -151
  124. package/src/analysis/structure/findings.js +0 -162
  125. package/src/analysis/task-retrieval.js +0 -107
  126. package/src/analysis/transport-contracts.js +0 -224
  127. package/src/analysis/transport-runtime-evidence.js +0 -155
  128. package/src/analysis-kit.mjs +0 -17
  129. package/src/bounds.js +0 -4
  130. package/src/build-graph.js +0 -209
  131. package/src/child-env.js +0 -7
  132. package/src/config.js +0 -5
  133. package/src/extension/local-services.mjs +0 -75
  134. package/src/git-exec.js +0 -67
  135. package/src/graph/build-worker.js +0 -49
  136. package/src/graph/builder/go-receiver-resolution.js +0 -112
  137. package/src/graph/builder/js/dynamic-import.js +0 -26
  138. package/src/graph/builder/js/queries.js +0 -48
  139. package/src/graph/builder/lang-csharp.js +0 -40
  140. package/src/graph/builder/lang-css.js +0 -29
  141. package/src/graph/builder/lang-go.js +0 -140
  142. package/src/graph/builder/lang-html.js +0 -29
  143. package/src/graph/builder/lang-java-calls.js +0 -142
  144. package/src/graph/builder/lang-java.js +0 -215
  145. package/src/graph/builder/lang-js.js +0 -291
  146. package/src/graph/builder/lang-python.js +0 -235
  147. package/src/graph/builder/lang-rust-calls.js +0 -63
  148. package/src/graph/builder/lang-rust.js +0 -299
  149. package/src/graph/builder/lang-solidity.js +0 -126
  150. package/src/graph/builder/lang-sql.js +0 -263
  151. package/src/graph/builder/pass2-resolution.js +0 -81
  152. package/src/graph/builder/spec-pkg.js +0 -87
  153. package/src/graph/community.js +0 -27
  154. package/src/graph/edge-provenance.js +0 -31
  155. package/src/graph/file-lock.js +0 -69
  156. package/src/graph/freshness-probe.js +0 -142
  157. package/src/graph/graph-filter.js +0 -63
  158. package/src/graph/incremental-refresh.js +0 -235
  159. package/src/graph/internal-builder.barrels.js +0 -235
  160. package/src/graph/internal-builder.build.js +0 -300
  161. package/src/graph/internal-builder.java.js +0 -33
  162. package/src/graph/internal-builder.js +0 -12
  163. package/src/graph/internal-builder.langs.js +0 -157
  164. package/src/graph/internal-builder.pass2.js +0 -163
  165. package/src/graph/internal-builder.resolvers.js +0 -286
  166. package/src/graph/layout.js +0 -51
  167. package/src/graph/node-id.js +0 -7
  168. package/src/graph/parser-artifact-boundary.js +0 -55
  169. package/src/graph/relations.js +0 -4
  170. package/src/graph/repo-registry.js +0 -124
  171. package/src/graph/resolvers/rust.js +0 -117
  172. package/src/infra/infra-items.js +0 -255
  173. package/src/infra/infra-registry.js +0 -184
  174. package/src/infra/infra.detect.js +0 -119
  175. package/src/infra/infra.js +0 -38
  176. package/src/infra/infra.match.js +0 -102
  177. package/src/infra/infra.scan.js +0 -93
  178. package/src/mcp/actions/graph-lifecycle.mjs +0 -148
  179. package/src/mcp/architecture-bootstrap.mjs +0 -168
  180. package/src/mcp/architecture-starter.mjs +0 -234
  181. package/src/mcp/catalog.mjs +0 -233
  182. package/src/mcp/company-contract-page.mjs +0 -142
  183. package/src/mcp/company-contract-reconcile.mjs +0 -87
  184. package/src/mcp/company-contract-verdict.mjs +0 -42
  185. package/src/mcp/evidence/bun-lock-graph.mjs +0 -209
  186. package/src/mcp/evidence/duplicate-member-order.mjs +0 -8
  187. package/src/mcp/evidence/package-graph-common.mjs +0 -115
  188. package/src/mcp/evidence/package-lock-graph.mjs +0 -92
  189. package/src/mcp/evidence-snapshot.architecture.mjs +0 -80
  190. package/src/mcp/evidence-snapshot.common.mjs +0 -158
  191. package/src/mcp/evidence-snapshot.duplicates.mjs +0 -213
  192. package/src/mcp/evidence-snapshot.health.mjs +0 -102
  193. package/src/mcp/evidence-snapshot.inventory.mjs +0 -148
  194. package/src/mcp/evidence-snapshot.mjs +0 -50
  195. package/src/mcp/evidence-snapshot.package-graph.mjs +0 -34
  196. package/src/mcp/evidence-snapshot.structure.mjs +0 -84
  197. package/src/mcp/extension-api.mjs +0 -77
  198. package/src/mcp/git-output.mjs +0 -7
  199. package/src/mcp/graph/context-core.mjs +0 -111
  200. package/src/mcp/graph/context-seeds.mjs +0 -207
  201. package/src/mcp/graph/context-state.mjs +0 -85
  202. package/src/mcp/graph/reverse-reach.mjs +0 -42
  203. package/src/mcp/graph/tools-core.mjs +0 -143
  204. package/src/mcp/graph/tools-query.mjs +0 -276
  205. package/src/mcp/graph-context.mjs +0 -5
  206. package/src/mcp/graph-diff.mjs +0 -218
  207. package/src/mcp/health/audit-format.mjs +0 -199
  208. package/src/mcp/health/audit.mjs +0 -199
  209. package/src/mcp/health/dead-code.mjs +0 -110
  210. package/src/mcp/health/duplicates.mjs +0 -121
  211. package/src/mcp/health/endpoints.mjs +0 -71
  212. package/src/mcp/health/structure.mjs +0 -220
  213. package/src/mcp/runtime-version.mjs +0 -31
  214. package/src/mcp/server/auto-refresh.mjs +0 -66
  215. package/src/mcp/server/runtime-config.mjs +0 -43
  216. package/src/mcp/server/shutdown.mjs +0 -40
  217. package/src/mcp/staleness-notice.mjs +0 -20
  218. package/src/mcp/sync/evidence-architecture.mjs +0 -54
  219. package/src/mcp/sync/evidence-common.mjs +0 -88
  220. package/src/mcp/sync/evidence-duplicates.mjs +0 -97
  221. package/src/mcp/sync/evidence-health.mjs +0 -56
  222. package/src/mcp/sync/evidence-packages.mjs +0 -95
  223. package/src/mcp/sync/payload-common.mjs +0 -97
  224. package/src/mcp/sync/payload-v2.mjs +0 -54
  225. package/src/mcp/sync/payload-v3.mjs +0 -79
  226. package/src/mcp/sync-evidence.mjs +0 -23
  227. package/src/mcp/sync-payload.mjs +0 -70
  228. package/src/mcp/tool-result.mjs +0 -54
  229. package/src/mcp/tools-actions.mjs +0 -11
  230. package/src/mcp/tools-architecture.mjs +0 -177
  231. package/src/mcp/tools-company.mjs +0 -251
  232. package/src/mcp/tools-context.mjs +0 -222
  233. package/src/mcp/tools-endpoints.mjs +0 -207
  234. package/src/mcp/tools-graph-hubs.mjs +0 -78
  235. package/src/mcp/tools-graph.mjs +0 -17
  236. package/src/mcp/tools-health.mjs +0 -24
  237. package/src/mcp/tools-history.mjs +0 -28
  238. package/src/mcp/tools-impact-change.mjs +0 -220
  239. package/src/mcp/tools-impact-precision.mjs +0 -89
  240. package/src/mcp/tools-impact.mjs +0 -169
  241. package/src/mcp/tools-source.mjs +0 -238
  242. package/src/mcp/tools-verified-change.mjs +0 -200
  243. package/src/mcp-rg.mjs +0 -50
  244. package/src/mcp-runtime.mjs +0 -2
  245. package/src/mcp-server.mjs +0 -298
  246. package/src/mcp-source-tools.mjs +0 -163
  247. package/src/path-classification.js +0 -226
  248. package/src/path-ignore.js +0 -69
  249. package/src/precision/lsp-client/constants.js +0 -12
  250. package/src/precision/lsp-client/environment.js +0 -20
  251. package/src/precision/lsp-client/errors.js +0 -15
  252. package/src/precision/lsp-client/lifecycle.js +0 -114
  253. package/src/precision/lsp-client/message-parser.js +0 -81
  254. package/src/precision/lsp-client/protocol.js +0 -212
  255. package/src/precision/lsp-client/registry.js +0 -59
  256. package/src/precision/lsp-client/repo-uri.js +0 -60
  257. package/src/precision/lsp-client/stdio-client.js +0 -140
  258. package/src/precision/lsp-client.js +0 -10
  259. package/src/precision/lsp-overlay/budget-policy.js +0 -78
  260. package/src/precision/lsp-overlay/build.js +0 -261
  261. package/src/precision/lsp-overlay/contract.js +0 -61
  262. package/src/precision/lsp-overlay/reference-results.js +0 -108
  263. package/src/precision/lsp-overlay/semantic-inputs.js +0 -62
  264. package/src/precision/lsp-overlay/source-session.js +0 -142
  265. package/src/precision/lsp-overlay/store.js +0 -150
  266. package/src/precision/lsp-overlay/target-index.js +0 -152
  267. package/src/precision/lsp-overlay/target-query.js +0 -55
  268. package/src/precision/lsp-overlay.js +0 -11
  269. package/src/precision/symbol-query.js +0 -224
  270. package/src/precision/typescript-lsp-provider.js +0 -12
  271. package/src/precision/typescript-provider/client.js +0 -89
  272. package/src/precision/typescript-provider/discovery.js +0 -124
  273. package/src/precision/typescript-provider/isolated-runtime.js +0 -39
  274. package/src/precision/typescript-provider/project-host.js +0 -254
  275. package/src/precision/typescript-provider/project-safety.js +0 -166
  276. package/src/precision/typescript-provider/reference-usage.js +0 -53
  277. package/src/process.js +0 -95
  278. package/src/repo-path.js +0 -53
  279. package/src/scan/discover.inventory.js +0 -78
  280. package/src/scan/discover.js +0 -5
  281. package/src/scan/discover.list.js +0 -79
  282. package/src/scan/discover.stack.js +0 -227
  283. package/src/scan/search.core.js +0 -24
  284. package/src/scan/search.git.js +0 -102
  285. package/src/scan/search.js +0 -9
  286. package/src/scan/search.node.js +0 -83
  287. package/src/scan/search.preview.js +0 -49
  288. package/src/scan/search.rg.js +0 -145
  289. package/src/security/advisory-store.js +0 -172
  290. package/src/security/installed-jvm-rust.js +0 -46
  291. package/src/security/installed.js +0 -280
  292. package/src/security/malware-file-heuristics.js +0 -121
  293. package/src/security/malware-heuristics.exclusions.js +0 -134
  294. package/src/security/malware-heuristics.js +0 -15
  295. package/src/security/malware-heuristics.roots.js +0 -145
  296. package/src/security/malware-heuristics.scan.js +0 -89
  297. package/src/security/malware-heuristics.sweep.js +0 -122
  298. package/src/security/malware-scoring.js +0 -105
  299. package/src/security/match.js +0 -85
  300. package/src/security/registry-sig.classify.js +0 -137
  301. package/src/security/registry-sig.js +0 -18
  302. package/src/security/registry-sig.rules.js +0 -192
  303. package/src/security/rust-advisory-report.js +0 -60
  304. package/src/security/typosquat.js +0 -81
  305. package/src/util.js +0 -40
  306. 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 };