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