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,124 +0,0 @@
1
- // Global local registry for repository graphs. Absolute paths never leave the machine; composing
2
- // extensions may use the opaque UUID. Identity is anchored in each canonical graph folder so simultaneous MCP
3
- // processes cannot mint different IDs for the same repository.
4
- import {randomUUID} from 'node:crypto'
5
- import {existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync} from 'node:fs'
6
- import {basename, join, relative, resolve} from 'node:path'
7
- import process from 'node:process'
8
- import {graphStorageKey} from './layout.js'
9
- import {atomicWriteFileSync, withFileLockSync} from './file-lock.js'
10
-
11
- const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
12
- const MARKER = '.repository-id'
13
-
14
- const normalized = (value) => {
15
- const path = String(value || '').replace(/\\/g, '/').replace(/\/+$/, '')
16
- return process.platform === 'win32' ? path.toLowerCase() : path
17
- }
18
-
19
- const realOrResolved = (value) => {
20
- try { return realpathSync.native(value) } catch { return resolve(value) }
21
- }
22
-
23
- const canonicalGraphDir = (repoPath, graphHome) => join(resolve(graphHome), graphStorageKey(repoPath))
24
- const markerPath = (graphDir) => join(graphDir, MARKER)
25
-
26
- export function registryPath(graphHome) { return join(graphHome, 'repositories.json') }
27
-
28
- export function readRepositoryRegistry(graphHome) {
29
- try {
30
- const parsed = JSON.parse(readFileSync(registryPath(graphHome), 'utf8'))
31
- return parsed?.repositoryRegistryV === 1 && Array.isArray(parsed.repositories)
32
- ? parsed.repositories.filter((item) => item && typeof item === 'object')
33
- : []
34
- } catch { return [] }
35
- }
36
-
37
- function writeRegistry(graphHome, repositories) {
38
- atomicWriteFileSync(registryPath(graphHome), JSON.stringify({repositoryRegistryV: 1, repositories}, null, 2), 'utf8')
39
- }
40
-
41
- function readMarker(graphDir) {
42
- try {
43
- const id = readFileSync(markerPath(graphDir), 'utf8').trim()
44
- return UUID.test(id) ? id : null
45
- } catch { return null }
46
- }
47
-
48
- function createOrReadMarker(graphDir, preferredId) {
49
- mkdirSync(graphDir, {recursive: true})
50
- const path = markerPath(graphDir)
51
- const existing = readMarker(graphDir)
52
- if (existing) return existing
53
- if (existsSync(path)) throw new Error(`invalid repository identity marker: ${path}`)
54
- const candidate = UUID.test(String(preferredId || '')) ? preferredId : randomUUID()
55
- try { writeFileSync(path, `${candidate}\n`, {encoding: 'utf8', flag: 'wx'}) }
56
- catch (error) {
57
- if (error?.code !== 'EEXIST') throw error
58
- const raced = readMarker(graphDir)
59
- if (!raced) throw new Error(`invalid repository identity marker after concurrent registration: ${path}`)
60
- return raced
61
- }
62
- return candidate
63
- }
64
-
65
- export function registerRepository({repoPath, graphDir, graphHome}) {
66
- mkdirSync(graphHome, {recursive: true})
67
- const real = realOrResolved(repoPath)
68
- const canonical = canonicalGraphDir(real, graphHome)
69
- if (normalized(realOrResolved(graphDir)) !== normalized(realOrResolved(canonical))) {
70
- throw new Error(`repository graphs must be registered from the canonical graph directory: ${canonical}`)
71
- }
72
- return withFileLockSync(join(graphHome, '.repositories.lock'), () => {
73
- const key = normalized(real)
74
- const repositories = readRepositoryRegistry(graphHome)
75
- let record = repositories.find((item) => normalized(item.repoPath) === key)
76
- const now = new Date().toISOString()
77
- const repositoryId = createOrReadMarker(canonical, record?.repositoryId)
78
- if (!record) {
79
- record = {repositoryId, repoPath: real, label: basename(real) || 'repo', graphDir: canonical, firstSeenAt: now, lastSeenAt: now}
80
- repositories.push(record)
81
- } else {
82
- record.repositoryId = repositoryId
83
- record.repoPath = real
84
- record.graphDir = canonical
85
- record.label = basename(real) || record.label || 'repo'
86
- record.lastSeenAt = now
87
- }
88
- const deduped = repositories.filter((item, index, all) =>
89
- normalized(item.repoPath) !== key || all.findIndex((candidate) => normalized(candidate.repoPath) === key) === index)
90
- deduped.sort((a, b) => String(a.label).localeCompare(String(b.label)) || String(a.repositoryId).localeCompare(String(b.repositoryId)))
91
- writeRegistry(graphHome, deduped)
92
- return {...record}
93
- })
94
- }
95
-
96
- export function repositoryRecord(repoPath, graphHome) {
97
- const real = realOrResolved(repoPath)
98
- const key = normalized(real)
99
- return liveRepositoryRecords(graphHome).find((item) => normalized(item.repoPath) === key) || null
100
- }
101
-
102
- function validLiveRecord(item, graphHome) {
103
- if (!UUID.test(String(item?.repositoryId || '')) || typeof item?.repoPath !== 'string' || typeof item?.graphDir !== 'string') return null
104
- let repoReal
105
- let graphHomeReal
106
- let graphReal
107
- try {
108
- repoReal = realpathSync.native(item.repoPath)
109
- graphHomeReal = realpathSync.native(graphHome)
110
- graphReal = realpathSync.native(item.graphDir)
111
- if (!statSync(repoReal).isDirectory() || !existsSync(join(repoReal, '.git'))) return null
112
- if (!statSync(graphReal).isDirectory() || !statSync(join(graphReal, 'graph.json')).isFile()) return null
113
- } catch { return null }
114
- if (normalized(graphReal) !== normalized(realOrResolved(canonicalGraphDir(repoReal, graphHomeReal)))) return null
115
- const rel = relative(graphHomeReal, graphReal)
116
- if (!rel || rel.startsWith('..') || resolve(graphHomeReal, rel) !== resolve(graphReal)) return null
117
- if (readMarker(graphReal) !== item.repositoryId) return null
118
- return {...item, repoPath: repoReal, graphDir: graphReal}
119
- }
120
-
121
- export function liveRepositoryRecords(graphHome) {
122
- if (!existsSync(graphHome)) return []
123
- return readRepositoryRegistry(graphHome).map((item) => validLiveRecord(item, graphHome)).filter(Boolean)
124
- }
@@ -1,117 +0,0 @@
1
- import {join} from 'node:path'
2
-
3
- const cleanRustRel = (path) => String(path || '').replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/+/g, '/').replace(/\/$/, '').replace(/^\.$/, '')
4
- const rustDir = (path) => {
5
- const clean = cleanRustRel(path)
6
- const index = clean.lastIndexOf('/')
7
- return index < 0 ? '' : clean.slice(0, index)
8
- }
9
- const rustBase = (path) => {
10
- const clean = cleanRustRel(path)
11
- const index = clean.lastIndexOf('/')
12
- return index < 0 ? clean : clean.slice(index + 1)
13
- }
14
- const rustJoin = (...parts) => cleanRustRel(join(...parts.filter((part) => part != null && part !== '')))
15
-
16
- export function createRustResolvers(fileSet) {
17
- const rustFiles = new Set([...fileSet].filter((file) => file.endsWith('.rs')))
18
- const rustRoots = new Map()
19
- for (const file of rustFiles) {
20
- const base = rustBase(file)
21
- if (base !== 'lib.rs' && base !== 'main.rs') continue
22
- const dir = rustDir(file)
23
- let root = rustRoots.get(dir)
24
- if (!root) rustRoots.set(dir, (root = {base: dir, lib: null, main: null}))
25
- root[base === 'lib.rs' ? 'lib' : 'main'] = file
26
- }
27
- const rustRootList = [...rustRoots.values()].sort((a, b) => b.base.length - a.base.length)
28
-
29
- const rustContext = (fromRel) => {
30
- const clean = cleanRustRel(fromRel)
31
- const base = rustBase(clean)
32
- const dir = rustDir(clean)
33
- if (base === 'lib.rs' || base === 'main.rs') return {base: dir, rootFile: clean}
34
- if (/^(?:bin|examples|tests|benches)$/.test(rustBase(dir))) return {base: dir, rootFile: clean}
35
- for (const root of rustRootList) {
36
- if (!root.base || clean.startsWith(root.base + '/')) return {base: root.base, rootFile: root.lib || root.main}
37
- }
38
- return {base: dir, rootFile: clean}
39
- }
40
- const rustModuleBase = (fromRel) => {
41
- const context = rustContext(fromRel)
42
- if (context.rootFile === cleanRustRel(fromRel)) return rustDir(fromRel)
43
- const name = rustBase(fromRel)
44
- if (name === 'lib.rs' || name === 'main.rs' || name === 'mod.rs') return rustDir(fromRel)
45
- return rustJoin(rustDir(fromRel), name.replace(/\.rs$/, ''))
46
- }
47
- const rustInlineBase = (fromRel, inlineModules = []) => {
48
- let base = rustModuleBase(fromRel)
49
- for (let index = 0; index < inlineModules.length; index++) {
50
- const module = inlineModules[index] || {}
51
- if (module.path) {
52
- const parent = index === 0 ? rustDir(fromRel) : base
53
- base = rustJoin(parent, module.path)
54
- } else base = rustJoin(base, module.name)
55
- }
56
- return base
57
- }
58
- const rustModuleFile = (moduleBase, context) => {
59
- const clean = cleanRustRel(moduleBase)
60
- if (clean === cleanRustRel(context.base) && context.rootFile && rustFiles.has(context.rootFile)) return context.rootFile
61
- const flat = clean + '.rs'
62
- if (rustFiles.has(flat)) return flat
63
- const legacy = rustJoin(clean, 'mod.rs')
64
- return rustFiles.has(legacy) ? legacy : null
65
- }
66
-
67
- const resolveRustMod = (fromRel, name, {inlineModules = [], explicitPath = ''} = {}) => {
68
- const clean = cleanRustRel(fromRel)
69
- if (explicitPath) {
70
- const parent = inlineModules.length ? rustInlineBase(clean, inlineModules) : rustDir(clean)
71
- const target = rustJoin(parent, explicitPath)
72
- return rustFiles.has(target) ? target : null
73
- }
74
- const targetBase = rustJoin(rustInlineBase(clean, inlineModules), String(name || '').replace(/^r#/, ''))
75
- return rustModuleFile(targetBase, rustContext(clean))
76
- }
77
-
78
- const resolveRustPath = (fromRel, rawSegments, {inlineModules = [], unqualified = true} = {}) => {
79
- const clean = cleanRustRel(fromRel)
80
- const segments = (Array.isArray(rawSegments) ? rawSegments : String(rawSegments || '').split('::'))
81
- .map((segment) => String(segment).trim().replace(/^r#/, '')).filter(Boolean)
82
- if (!segments.length) return null
83
- const context = rustContext(clean)
84
- const current = rustInlineBase(clean, inlineModules)
85
- const rest = [...segments]
86
- const starts = []
87
- let anchored = false
88
- if (rest[0] === 'crate') { anchored = true; rest.shift(); starts.push(context.base) }
89
- else if (rest[0] === 'self') { anchored = true; rest.shift(); starts.push(current) }
90
- else if (rest[0] === 'super') {
91
- anchored = true
92
- let base = current
93
- while (rest[0] === 'super') { rest.shift(); base = rustDir(base) }
94
- if (context.base && base !== context.base && !base.startsWith(context.base + '/')) return null
95
- starts.push(base)
96
- } else if (unqualified) {
97
- starts.push(context.base)
98
- if (current !== context.base) starts.push(current)
99
- } else return null
100
-
101
- for (const start of starts) {
102
- const minimum = anchored ? 0 : 1
103
- for (let used = rest.length; used >= minimum; used--) {
104
- const target = rustModuleFile(rustJoin(start, ...rest.slice(0, used)), context)
105
- if (target) return {
106
- targetFile: target,
107
- consumed: segments.length - rest.length + used,
108
- remaining: rest.slice(used),
109
- anchored,
110
- }
111
- }
112
- }
113
- return null
114
- }
115
-
116
- return {resolveRustMod, resolveRustPath}
117
- }
@@ -1,255 +0,0 @@
1
- // infra-items.js — extract concrete infra items (DB tables, cache keysets, queue topics, cloud files, SQL
2
- // tables, env-declared endpoints) from source text for the detected services. Split out of infra.js; it owns
3
- // the shared leaf helpers (lc/safeRead/size caps) as the lower module — infra.js imports them back.
4
- import { safeRead, MAX_FILE_BYTES } from "../util.js";
5
-
6
- const IMPORT_SCAN_MAX_FILES = 2000; // cap the synchronous import-scan pass (connector attribution only) so the
7
- const lc = (s) => String(s || "").toLowerCase();
8
-
9
- export { safeRead };
10
-
11
- const ITEM_META = {
12
- db: { label: "TABLES", unit: "rows" },
13
- ts: { label: "SERIES", unit: "pts" },
14
- cache: { label: "KEYSETS", unit: "keys" },
15
- queue: { label: "TOPICS", unit: "msg/s" },
16
- cloud: { label: "FILES", unit: "KB" },
17
- fs: { label: "FILES", unit: "KB" },
18
- logs: { label: "STREAMS", unit: "l/s" },
19
- api: { label: "ENDPOINTS", unit: "req/s" },
20
- };
21
- const ITEM_VALUE = { db: 42, ts: 120, cache: 700, queue: 22, cloud: 120, fs: 80, logs: 55, api: 24 };
22
- const SQL_RESERVED = new Set([
23
- "select", "from", "where", "join", "left", "right", "inner", "outer", "full", "cross",
24
- "on", "and", "or", "by", "group", "order", "limit", "offset", "as", "with", "values",
25
- "set", "returning", "true", "false", "null", "undefined", "if", "case", "when", "then",
26
- "else", "end", "having", "over", "partition", "distinct", "the", "is",
27
- "count", "sum", "avg", "min", "max", "uniq", "array", "date", "datetime", "string", "number",
28
- ]);
29
-
30
- export function itemMetaFor(service) {
31
- if (service.id === "mongodb") return { label: "COLLECTIONS", unit: "docs" };
32
- if (service.id === "dynamodb") return { label: "TABLES", unit: "items" };
33
- if (service.id === "elasticsearch" || service.id === "solr" || service.id === "meilisearch" || service.id === "typesense") {
34
- return { label: "INDEXES", unit: "docs" };
35
- }
36
- return ITEM_META[service.kind] || { label: "ITEMS", unit: "" };
37
- }
38
-
39
- function cleanInfraItemName(raw) {
40
- const name = String(raw || "").trim().replace(/^(?:["'`]|\[)+|(?:["'`]|])+$/g, "").replace(/[;,]+$/g, "").trim();
41
- if (!name || name.length < 2 || name.length > 64) return "";
42
- if (name.includes("://") || name.includes("${") || name.includes("#{")) return "";
43
- if (/[\s(){}+$]/.test(name)) return "";
44
- if (!/^[A-Za-z0-9_./:\-*]+$/.test(name)) return "";
45
- if (/^\d+$/.test(name) || SQL_RESERVED.has(name.toLowerCase())) return "";
46
- return name;
47
- }
48
-
49
- function addInfraItem(map, raw, weight = 1, sourcePath = "", op = "") {
50
- const name = cleanInfraItemName(raw);
51
- if (!name) return;
52
- const cur = map.get(name) || { name, refs: 0, files: new Set(), ops: new Set() };
53
- cur.refs += Math.max(1, weight);
54
- if (sourcePath) cur.files.add(sourcePath);
55
- if (op) cur.ops.add(op);
56
- map.set(name, cur);
57
- }
58
-
59
- // One regex-walk adder factory shared by the two matchers below — the only difference is how a
60
- // captured group becomes items (a single name vs a string-array body).
61
- const matchAdder = (add) => (map, text, re, group = 1, weight = 1, sourcePath = "", op = "") => {
62
- for (const m of text.matchAll(re)) add(map, m[group], weight, sourcePath, op);
63
- };
64
-
65
- function addStringArrayItems(map, raw, weight = 1, sourcePath = "", op = "") {
66
- const body = String(raw || "");
67
- for (const m of body.matchAll(/["'`]([^"'`]+)["'`]/g)) addInfraItem(map, m[1], weight, sourcePath, op);
68
- }
69
-
70
- const addMatches = matchAdder(addInfraItem);
71
- const addStructArrayMatches = matchAdder(addStringArrayItems);
72
-
73
- function addSqlTableMatches(map, text, re, cteAliases, group = 1, weight = 1, sourcePath = "", op = "") {
74
- for (const m of String(text || "").matchAll(re)) {
75
- const name = String(m[group] || "");
76
- if (cteAliases.has(name.toLowerCase())) continue;
77
- addInfraItem(map, name, weight, sourcePath, op);
78
- }
79
- }
80
-
81
- function looksLikeSqlSnippet(raw) {
82
- const text = String(raw || "").replace(/\$\{[\s\S]*?\}/g, " ");
83
- if (!/[A-Za-z]/.test(text)) return false;
84
- const statementStart = "(?:^|[\\r\\n;])\\s*";
85
- return (
86
- new RegExp(`${statementStart}(?:select|with)\\b[\\s\\S]{0,600}\\bfrom\\b`, "i").test(text) ||
87
- new RegExp(`${statementStart}(?:insert\\s+into|delete\\s+from|alter\\s+table|create\\s+(?:or\\s+replace\\s+)?table|truncate\\s+table|update\\s+["'\`\\[]?[A-Za-z_][\\w$]*(?:\\.[A-Za-z_][\\w$]*)?["'\`\\]]?\\s+set)\\b`, "i").test(text)
88
- );
89
- }
90
-
91
- function stringLiteralBody(match) {
92
- for (let i = 1; i < match.length; i++) if (match[i] != null) return match[i];
93
- return "";
94
- }
95
-
96
- function extractSqlSnippets(text) {
97
- const out = [];
98
- const src = String(text || "");
99
- const add = (body) => {
100
- const snippet = String(body || "");
101
- if (looksLikeSqlSnippet(snippet)) out.push(snippet);
102
- };
103
-
104
- for (const match of src.matchAll(/"""([\s\S]*?)"""|'''([\s\S]*?)'''/g)) add(stringLiteralBody(match));
105
- for (const match of src.matchAll(/`([\s\S]*?)`|"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'/g)) add(stringLiteralBody(match));
106
- return out.join("\n");
107
- }
108
-
109
- function sqlCteAliases(text) {
110
- const out = new Set();
111
- for (const match of String(text || "").matchAll(/(?:\bwith|,)\s+([A-Za-z_][\w$]*)\s+as\s*\(/gi)) {
112
- out.add(String(match[1] || "").toLowerCase());
113
- }
114
- return out;
115
- }
116
-
117
- function hasServiceHint(service, text) {
118
- const lower = lc(text);
119
- const tokens = [service.id, service.name, ...(service.imports || []), ...(service.deps || [])]
120
- .map((x) => lc(x))
121
- .filter((x) => x && x.length > 2);
122
- return tokens.some((token) => lower.includes(token));
123
- }
124
-
125
- function finalizeInfraItems(map, kind) {
126
- const base = ITEM_VALUE[kind] || 40;
127
- return [...map.values()]
128
- .sort((a, b) => b.refs - a.refs || a.name.localeCompare(b.name))
129
- .slice(0, 24)
130
- .map((item) => ({
131
- name: item.name,
132
- val: Math.round(Math.max(4, base * (1 + Math.log2(item.refs + 1) * 0.55))),
133
- health: Math.max(0.42, Math.min(0.96, 0.94 - Math.log2(item.refs + 1) * 0.08)),
134
- refs: item.refs,
135
- fileCount: item.files ? item.files.size : 0,
136
- files: item.files ? [...item.files].sort().slice(0, 12) : [],
137
- ops: item.ops ? [...item.ops].sort().slice(0, 12) : [],
138
- }));
139
- }
140
-
141
- function extractInfraItemsForService(service, text, out, sourcePath = "") {
142
- const id = service.id;
143
- const kind = service.kind;
144
- const hit = (re, group = 1, weight = 1, op = "") => addMatches(out, text, re, group, weight, sourcePath, op);
145
- const hitSql = (target, re, cteAliases, group = 1, weight = 1, op = "") => addSqlTableMatches(out, target, re, cteAliases, group, weight, sourcePath, op);
146
- const hitArrays = (re, group = 1, weight = 1, op = "") => addStructArrayMatches(out, text, re, group, weight, sourcePath, op);
147
- // Go/CLI services often carry their topics/keyspaces as FLAG DEFAULTS, not literals at the call
148
- // site (bgp-speaker: flag.String("bgp_update_kafka_topic", "bgp_updates", …), flag.String(
149
- // "redis_key_base", "bgp:mitigators", …)) — the flag NAME says what the default VALUE is.
150
- const hitFlagDefaults = (nameRe, weight = 2, op = "configured") => {
151
- for (const m of text.matchAll(/\b(?:flag|pflag)\.String(?:Var)?\s*\(\s*(?:&[\w.]+\s*,\s*)?"([^"]+)"\s*,\s*"([^"]+)"/g)) {
152
- if (nameRe.test(m[1])) addInfraItem(out, m[2], weight, sourcePath, op);
153
- }
154
- for (const m of text.matchAll(/\badd_argument\s*\(\s*["']--?([^"']+)["'][^)]{0,200}?\bdefault\s*=\s*["']([^"']+)["']/g)) {
155
- if (nameRe.test(m[1])) addInfraItem(out, m[2], weight, sourcePath, op);
156
- }
157
- };
158
-
159
- if (id === "mongodb") {
160
- hit(/\.collection\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/gi, 1, 2);
161
- hit(/\.Collection\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g, 1, 2);
162
- hit(/\bgetCollection\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/gi, 1, 2);
163
- hit(/\bcollection\s*:\s*["'`]([^"'`]+)["'`]/gi);
164
- hit(/\b(?:mongoose\.)?model\s*\(\s*["'`]([^"'`]+)["'`]/gi);
165
- hit(/\bdb\s*\[\s*["'`]([^"'`]+)["'`]\s*\]/gi);
166
- return;
167
- }
168
-
169
- if (id === "dynamodb") {
170
- hit(/\bTableName\s*:\s*["'`]([^"'`]+)["'`]/g, 1, 2);
171
- hit(/\btableName\s*[:=]\s*["'`]([^"'`]+)["'`]/g, 1, 2);
172
- }
173
-
174
- if (id === "elasticsearch" || id === "solr" || id === "meilisearch" || id === "typesense") {
175
- hit(/\bindex(?:Name)?\s*[:=]\s*["'`]([^"'`]+)["'`]/gi, 1, 2);
176
- hit(/\.index\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/gi, 1, 2);
177
- }
178
-
179
- if (kind === "db" || kind === "ts") {
180
- const sqlText = extractSqlSnippets(text);
181
- if (sqlText) {
182
- const cteAliases = sqlCteAliases(sqlText);
183
- hitSql(sqlText, /\b(?:insert\s+into|delete\s+from|alter\s+table|create\s+(?:or\s+replace\s+)?table|truncate\s+table)\s+(?:["'`]|\[)?([A-Za-z_][\w$]*(?:\.[A-Za-z_][\w$]*)?)(?:["'`]|])?/gi, cteAliases, 1, 2);
184
- hitSql(sqlText, /\b(?:from|join|into|update|table)\s+(?:["'`]|\[)?([A-Za-z_][\w$]*(?:\.[A-Za-z_][\w$]*)?)(?:["'`]|])?/gi, cteAliases);
185
- }
186
- if (id !== "clickhouse" && hasServiceHint(service, text)) {
187
- hit(/\b(?:table|tableName|measurement|bucket)\s*[:=]\s*["'`]([^"'`]+)["'`]/gi);
188
- }
189
- }
190
-
191
- if (kind === "cache") {
192
- hit(/\b(?:get|getBuffer|getdel|exists|ttl|pttl)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 1, "read");
193
- hit(/\b(?:set|setex|psetex|setnx|incr|decr|expire|persist)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 2, "write");
194
- hit(/\b(?:del|delete|unlink|expireat|pexpireat)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 2, "delete");
195
- hit(/\b(?:hget|hmget|hgetall|hexists)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 1, "hash read");
196
- hit(/\b(?:hset|hmset|hdel)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 2, "hash write");
197
- hit(/\b(?:lpush|rpush|lpop|rpop|sadd|srem|zadd|zrem)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 2, "collection");
198
- hit(/\b(?:xadd|xread|xreadgroup|xgroup)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 2, "stream");
199
- hit(/\b(?:publish|subscribe|psubscribe)\s*\(\s*(?:ctx\s*,\s*)?["'`]([^"'`]+)["'`]/gi, 1, 1, "pub/sub");
200
- hit(/\b(?:cacheKey|redisKey|valkeyKey|redisPrefix|valkeyPrefix|keyPrefix|lockKey|rateLimitKey|sessionKey)\s*[:=]\s*["'`]([^"'`]+)["'`]/gi, 1, 2, "key pattern");
201
- hitArrays(/\b(?:Streams|streams)\s*:\s*\[\]string\s*\{([^}]+)\}/g, 1, 2, "stream");
202
- hitFlagDefaults(/key|keyspace|prefix/i, 2, "key pattern");
203
- }
204
-
205
- if (kind === "queue") {
206
- hit(/\b(?:topic|topics|queue|subject|stream|channel|Topic|Queue|Subject|Stream|Channel)\s*[:=]\s*["'`]([^"'`]+)["'`]/g, 1, 2, "configured");
207
- hit(/\b(?:publish|produce|send|sendMessage|writeMessage|writeMessages|emit)\s*\(\s*["'`]([^"'`]+)["'`]/gi, 1, 2, "produce");
208
- hit(/\b(?:subscribe|consume|consumer|listen|readMessage|readMessages)\s*\(\s*["'`]([^"'`]+)["'`]/gi, 1, 1, "consume");
209
- hit(/\b(?:producer\.send|sendBatch)\s*\(\s*\{[\s\S]{0,500}?\btopic\s*:\s*["'`]([^"'`]+)["'`]/gi, 1, 2, "produce");
210
- hit(/\bconsumer\.subscribe\s*\(\s*\{[\s\S]{0,320}?\btopic\s*:\s*["'`]([^"'`]+)["'`]/gi, 1, 2, "consume");
211
- hit(/\b(?:KafkaConsumer|NewConsumer|NewReader|NewWriter|NewTopic)\s*\(\s*["'`]([^"'`]+)["'`]/g, 1, 2, "configured");
212
- hit(/@KafkaListener\s*\([^)]*\btopics?\s*=\s*["'`]([^"'`]+)["'`]/g, 1, 2, "consume");
213
- hit(/\bkafkaTemplate\.send\s*\(\s*["'`]([^"'`]+)["'`]/g, 1, 2, "produce");
214
- hitArrays(/\b(?:topics|Topics|GroupTopics|SubscribeTopics|streams|Streams)\s*[:=]\s*(?:\[\]string)?\s*\{([^}]+)\}/g, 1, 2, "configured");
215
- hitArrays(/\b(?:subscribe|Consume|SubscribeTopics)\s*\(\s*(?:ctx\s*,\s*)?\[\]string\s*\{([^}]+)\}/g, 1, 2, "consume");
216
- hitFlagDefaults(/topic|queue|subject|stream|channel/i, 2, "configured");
217
- }
218
-
219
- if (kind === "cloud" || kind === "fs") {
220
- hit(/\b(?:bucket|bucketName|container|containerName)\s*[:=]\s*["'`]([^"'`]+)["'`]/gi, 1, 2);
221
- }
222
- }
223
-
224
- export function collectInfraItems(scan, entries, filesByService) {
225
- const result = new Map();
226
- const allFiles = (scan.codeFiles || []).slice(0, IMPORT_SCAN_MAX_FILES);
227
- const textCache = new Map();
228
- const readText = (f) => {
229
- if (!f || !f.full) return "";
230
- if (!textCache.has(f.full)) textCache.set(f.full, safeRead(f.full));
231
- return textCache.get(f.full);
232
- };
233
-
234
- for (const { service } of entries) {
235
- const meta = itemMetaFor(service);
236
- const wanted = filesByService.get(service.id);
237
- const preferred = wanted && wanted.size ? allFiles.filter((f) => wanted.has(f.path)) : [];
238
- const candidateFiles = preferred.length ? [...preferred, ...allFiles.filter((f) => !wanted.has(f.path))] : allFiles;
239
- const itemMap = new Map();
240
- for (const f of candidateFiles) {
241
- const text = readText(f);
242
- if (!text) continue;
243
- extractInfraItemsForService(service, text, itemMap, f.path);
244
- }
245
- result.set(service.id, {
246
- itemLabel: meta.label,
247
- unit: meta.unit,
248
- items: finalizeInfraItems(itemMap, service.kind),
249
- });
250
- }
251
- return result;
252
- }
253
-
254
-
255
- export { MAX_FILE_BYTES, IMPORT_SCAN_MAX_FILES, lc };