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