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,97 +0,0 @@
1
- import {
2
- CAPS, DUPLICATE_THRESHOLDS, bool, compare, count, graphId, int, list,
3
- path, reasons, state, text, verdict,
4
- } from './evidence-common.mjs'
5
- import {compareDuplicateMember} from '../evidence/duplicate-member-order.mjs'
6
-
7
- function duplicateEvidenceId(value) {
8
- const id = text(value, 64)
9
- return id && /^[a-f0-9]{24,64}$/i.test(id) ? id : undefined
10
- }
11
-
12
- function duplicateMember(value) {
13
- if (!value || typeof value !== 'object' || Array.isArray(value)) return null
14
- const file = path(value.file)
15
- const startLine = int(value.startLine), endLine = int(value.endLine), tokens = int(value.tokens)
16
- if (!file || startLine < 1 || endLine < startLine || tokens < DUPLICATE_THRESHOLDS.clones.minTokens) return null
17
- const out = {file, startLine, endLine, tokens}
18
- const nodeId = graphId(value.graphNodeId)
19
- if (nodeId?.startsWith(`${file}#`)) out.graphNodeId = nodeId
20
- return out
21
- }
22
-
23
- function duplicateMembers(values, cap = CAPS.duplicateMembers) {
24
- const raw = Array.isArray(values) ? values : []
25
- const unique = new Map()
26
- for (const value of raw) {
27
- const item = duplicateMember(value)
28
- if (!item) continue
29
- unique.set(`${item.file}\0${item.startLine}\0${item.endLine}\0${item.graphNodeId || ''}`, item)
30
- }
31
- const all = [...unique.values()].sort(compareDuplicateMember)
32
- return {items: all.slice(0, cap), total: all.length, invalid: raw.length - all.length, truncated: all.length > cap}
33
- }
34
-
35
- function cloneGroup(value) {
36
- const id = duplicateEvidenceId(value?.id)
37
- const members = duplicateMembers(value?.members)
38
- const rawStrongestSimilarity = Number(value?.strongestSimilarity)
39
- const rawWeakestLinkedSimilarity = Number(value?.weakestLinkedSimilarity)
40
- const strongestSimilarity = Math.trunc(rawStrongestSimilarity)
41
- const weakestLinkedSimilarity = Math.trunc(rawWeakestLinkedSimilarity)
42
- if (!id || members.items.length < 2 || strongestSimilarity < DUPLICATE_THRESHOLDS.clones.minSimilarityPercent ||
43
- !Number.isFinite(rawStrongestSimilarity) || rawStrongestSimilarity > 100 ||
44
- !Number.isFinite(rawWeakestLinkedSimilarity) || weakestLinkedSimilarity < DUPLICATE_THRESHOLDS.clones.minSimilarityPercent ||
45
- rawWeakestLinkedSimilarity > 100 || weakestLinkedSimilarity > strongestSimilarity) return null
46
- const memberCount = Math.max(int(value?.memberCount), members.total)
47
- const returnedTokens = members.items.reduce((sum, member) => sum + member.tokens, 0)
48
- return {
49
- id, memberCount, totalTokens: Math.max(int(value?.totalTokens), returnedTokens),
50
- strongestSimilarity, weakestLinkedSimilarity,
51
- membersTruncated: bool(value?.membersTruncated) || members.truncated || members.invalid > 0 || memberCount > members.items.length,
52
- members: members.items,
53
- }
54
- }
55
-
56
- function divergenceCandidate(value) {
57
- const id = duplicateEvidenceId(value?.id)
58
- const symbol = text(value?.symbol, 256)
59
- const rawSimilarity = Number(value?.similarity)
60
- const similarity = Math.trunc(rawSimilarity)
61
- const members = duplicateMembers(value?.members, 2)
62
- if (!id || !symbol || !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(symbol) || members.total !== 2 || members.invalid > 0 ||
63
- !Number.isFinite(rawSimilarity) || rawSimilarity < 0 || rawSimilarity > DUPLICATE_THRESHOLDS.divergence.maxSimilarityPercent ||
64
- members.items[0].file === members.items[1].file) return null
65
- return {id, symbol, similarity, totalTokens: Math.max(int(value?.totalTokens), members.items[0].tokens + members.items[1].tokens), members: members.items}
66
- }
67
-
68
- export function sanitizeDuplicates(value) {
69
- const rawGroups = Array.isArray(value?.cloneGroups) ? value.cloneGroups : []
70
- const rawDivergence = Array.isArray(value?.divergenceCandidates) ? value.divergenceCandidates : []
71
- const cloneGroups = list(rawGroups, CAPS.duplicateGroups, cloneGroup,
72
- (a, b) => b.totalTokens - a.totalTokens || b.memberCount - a.memberCount || compare(a.id, b.id))
73
- const divergence = list(rawDivergence, CAPS.divergenceCandidates, divergenceCandidate,
74
- (a, b) => b.totalTokens - a.totalTokens || a.similarity - b.similarity || compare(a.symbol, b.symbol) || compare(a.id, b.id))
75
- const invalid = rawGroups.length - cloneGroups.total + rawDivergence.length - divergence.total
76
- const membersTruncated = cloneGroups.items.some((group) => group.membersTruncated)
77
- const groupCompleteness = count(value?.completeness?.cloneGroups, rawGroups.length, cloneGroups.items.length)
78
- const divergenceCompleteness = count(value?.completeness?.divergenceCandidates, rawDivergence.length, divergence.items.length)
79
- const truncated = cloneGroups.truncated || divergence.truncated || groupCompleteness.truncated || divergenceCompleteness.truncated || membersTruncated || invalid > 0
80
- const outReasons = reasons([
81
- ...(Array.isArray(value?.completeness?.reasons) ? value.completeness.reasons : []),
82
- ...(invalid > 0 ? ['INVALID_DUPLICATE_EVIDENCE_DROPPED'] : []),
83
- ...(membersTruncated ? ['CLONE_MEMBERS_TRUNCATED'] : []),
84
- ...(cloneGroups.truncated ? ['CLONE_GROUPS_TRUNCATED'] : []),
85
- ...(divergence.truncated ? ['DIVERGENCE_CANDIDATES_TRUNCATED'] : []),
86
- ])
87
- const rawFragments = value?.completeness?.fragments
88
- const eligible = int(rawFragments?.eligible), filtered = int(rawFragments?.filtered)
89
- const total = Math.max(int(rawFragments?.total), eligible + filtered)
90
- const outState = state(value?.state)
91
- return {
92
- state: truncated && outState === 'COMPLETE' ? 'PARTIAL' : outState,
93
- verdict: verdict(value?.verdict), thresholds: DUPLICATE_THRESHOLDS,
94
- completeness: {fragments: {total, eligible: Math.min(eligible, total), filtered: Math.max(filtered, total - eligible)}, cloneGroups: groupCompleteness, divergenceCandidates: divergenceCompleteness, reasons: outReasons},
95
- cloneGroups: cloneGroups.items, divergenceCandidates: divergence.items,
96
- }
97
- }
@@ -1,56 +0,0 @@
1
- import {
2
- CAPS, CATEGORIES, CONFIDENCE, SEVERITIES, checks, compare, count, graphId,
3
- int, list, numericRecord, packageName, path, privacySafeText, reasons, set,
4
- state, text, token, verdict,
5
- } from './evidence-common.mjs'
6
-
7
- function finding(value) {
8
- if (!value || typeof value !== 'object') return null
9
- const id = text(value.id, 64), category = token(value.category, 32), rule = token(value.rule, 64), severity = token(value.severity, 16)
10
- if (!id || !/^[a-f0-9]{8,64}$/i.test(id) || !CATEGORIES.has(category) || !rule || !SEVERITIES.has(severity)) return null
11
- const out = {id, category, rule, severity}
12
- if (CONFIDENCE.has(value.confidence)) out.confidence = value.confidence
13
- set(out, 'file', path(value.file)); set(out, 'line', Number.isFinite(value.line) && value.line >= 0 ? Math.trunc(value.line) : undefined)
14
- set(out, 'symbol', privacySafeText(value.symbol)); set(out, 'package', packageName(value.package)); set(out, 'version', token(value.version, 128)); set(out, 'graphNodeId', graphId(value.graphNodeId))
15
- return out
16
- }
17
-
18
- function hotspot(value) {
19
- const id = graphId(value?.id), file = path(value?.file), severity = token(value?.severity, 16)
20
- if (!id || !file || !['medium', 'high'].includes(severity)) return null
21
- const out = {id, file, severity, breaches: [...new Set((value.breaches || []).map((item) => token(item, 48)).filter(Boolean))].sort(compare).slice(0, 12)}
22
- set(out, 'symbol', privacySafeText(value.symbol))
23
- for (const key of ['startLine', 'endLine', 'loc', 'cyclomatic', 'params']) if (Number.isFinite(value[key]) && value[key] >= 0) out[key] = Math.trunc(value[key])
24
- return out
25
- }
26
-
27
- export function sanitizeHealth(value) {
28
- const findings = list(value?.findings, CAPS.findings, finding, (a, b) => compare(a.severity, b.severity) || compare(a.id, b.id))
29
- const hotspots = list(value?.complexity?.hotspots, CAPS.hotspots, hotspot, (a, b) => compare(a.severity, b.severity) || compare(a.id, b.id))
30
- const truncated = findings.truncated || hotspots.truncated
31
- const outState = state(value?.state)
32
- return {
33
- state: truncated && outState === 'COMPLETE' ? 'PARTIAL' : outState, verdict: verdict(value?.verdict),
34
- completeness: {findings: count(value?.completeness?.findings, findings.total, findings.items.length), hotspots: count(value?.completeness?.hotspots, hotspots.total, hotspots.items.length), reasons: reasons(value?.completeness?.reasons)},
35
- summary: {
36
- bySeverity: numericRecord(value?.summary?.bySeverity, ['critical', 'high', 'medium', 'low', 'info']),
37
- byCategory: numericRecord(value?.summary?.byCategory, ['unused', 'structure', 'vulnerability', 'malware']),
38
- dead: numericRecord(value?.summary?.dead, ['deadSymbols', 'deadFiles', 'unusedExports']),
39
- structure: numericRecord(value?.summary?.structure, ['runtimeImportEdges', 'typeOnlyImportEdges', 'compileOnlyImportEdges', 'runtimeCycles', 'compileTimeCouplings', 'largestCycle', 'largestCompileTimeCoupling', 'orphans', 'boundaryViolations']),
40
- },
41
- checks: checks(value?.checks), findings: findings.items,
42
- complexity: {thresholds: {loc: {warning: int(value?.complexity?.thresholds?.loc?.warning), high: int(value?.complexity?.thresholds?.loc?.high)}, cyclomatic: {warning: int(value?.complexity?.thresholds?.cyclomatic?.warning), high: int(value?.complexity?.thresholds?.cyclomatic?.high)}, params: {warning: int(value?.complexity?.thresholds?.params?.warning), high: int(value?.complexity?.thresholds?.params?.high)}}, analyzed: int(value?.complexity?.analyzed), hotspots: hotspots.items},
43
- }
44
- }
45
-
46
- function badge(value) {
47
- const category = token(value?.category, 32), id = token(value?.id, 128)
48
- if (!['languages', 'runtimes', 'tests', 'infra', 'deploy'].includes(category) || !id) return null
49
- const out = {category, id}; set(out, 'kind', token(value.kind, 64)); set(out, 'version', token(value.version, 64)); return out
50
- }
51
-
52
- export function sanitizeTechnologies(value) {
53
- const badges = list(value?.badges, CAPS.badges, badge, (a, b) => compare(a.category, b.category) || compare(a.id, b.id))
54
- const outState = state(value?.state)
55
- return {state: badges.truncated && outState === 'COMPLETE' ? 'PARTIAL' : outState, verdict: verdict(value?.verdict), completeness: {badges: count(value?.completeness?.badges, badges.total, badges.items.length), reasons: reasons(value?.completeness?.reasons)}, badges: badges.items}
56
- }
@@ -1,95 +0,0 @@
1
- import {
2
- CAPS, PACKAGE_DEPENDENCY_KINDS, bool, checks, compare, count, int, list,
3
- numericRecord, packageName, packageVersion, path, reasons, set, state, text,
4
- token, verdict,
5
- } from './evidence-common.mjs'
6
-
7
- const PACKAGE_SOURCES = new Set(['package-lock', 'yarn-lock', 'requirements', 'venv', 'poetry-lock', 'uv-lock', 'pipfile-lock', 'go-sum', 'go-mod', 'node_modules'])
8
-
9
- function packageSource(value) {
10
- const source = text(value, 512)
11
- if (PACKAGE_SOURCES.has(source)) return source
12
- const relative = path(source, 512)
13
- return relative && /(^|\/)(?:package-lock\.json|npm-shrinkwrap\.json|yarn\.lock|pnpm-lock\.ya?ml|requirements[\w.-]*\.(?:txt|in)|poetry\.lock|uv\.lock|Pipfile\.lock|go\.(?:mod|sum))$/i.test(relative) ? relative : undefined
14
- }
15
-
16
- function packageFact(value) {
17
- const name = packageName(value?.name), version = token(value?.version, 128), ecosystem = token(value?.ecosystem, 64), source = packageSource(value?.source)
18
- return name && version && ecosystem && source ? {name, version, ecosystem, dev: bool(value.dev), source} : null
19
- }
20
-
21
- function usage(value) {
22
- const name = packageName(value?.name), ecosystem = token(value?.ecosystem, 64)
23
- if (!name || !ecosystem) return null
24
- const files = [...new Set((value.files || []).map((item) => path(item)).filter(Boolean))].sort(compare)
25
- return {name, ecosystem, importCount: int(value.importCount), fileCount: int(value.fileCount), files: files.slice(0, CAPS.files), filesTruncated: bool(value.filesTruncated) || files.length > CAPS.files, kinds: [...new Set((value.kinds || []).map((item) => token(item, 64)).filter(Boolean))].sort(compare).slice(0, 32)}
26
- }
27
-
28
- function packageGraphNode(value) {
29
- const name = packageName(value?.name), version = packageVersion(value?.version), id = text(value?.id, 512)
30
- if (!name || !version || !id) return null
31
- const prefix = `npm:${name}@${version}:`
32
- if (!id.startsWith(prefix) || !/^[a-f0-9]{12}$/i.test(id.slice(prefix.length))) return null
33
- return {id, name, version, direct: bool(value.direct), dev: bool(value.dev), optional: bool(value.optional), peer: bool(value.peer)}
34
- }
35
-
36
- function sanitizePackageDependencyGraph(value) {
37
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
38
- return {
39
- state: 'NOT_CHECKED', ecosystem: 'npm', root: '(root)',
40
- completeness: {nodes: count(null, 0, 0), edges: count(null, 0, 0), declarations: numericRecord(null, ['total', 'resolved', 'unresolved', 'local', 'optionalMissing']), reasons: ['DEPENDENCY_GRAPH_NOT_PROVIDED']},
41
- nodes: [], edges: [],
42
- }
43
- }
44
- const nodes = list(value.nodes, CAPS.packageGraphNodes, packageGraphNode,
45
- (a, b) => Number(b.direct) - Number(a.direct) || compare(a.name, b.name) || compare(a.version, b.version) || compare(a.id, b.id))
46
- const nodeIds = new Set(nodes.items.map((node) => node.id))
47
- const edge = (candidate) => {
48
- const from = candidate?.from === '(root)' ? '(root)' : text(candidate?.from, 512)
49
- const to = text(candidate?.to, 512), kind = token(candidate?.kind, 32)
50
- if (!from || !to || !PACKAGE_DEPENDENCY_KINDS.has(kind) || from === to ||
51
- (from !== '(root)' && !nodeIds.has(from)) || !nodeIds.has(to)) return null
52
- return {from, to, kind}
53
- }
54
- const edges = list(value.edges, CAPS.packageGraphEdges, edge,
55
- (a, b) => compare(a.from, b.from) || compare(a.to, b.to) || compare(a.kind, b.kind))
56
- const lockfile = path(value.lockfile, 512)
57
- const safeLockfile = lockfile && /(^|\/)(?:package-lock\.json|npm-shrinkwrap\.json)$/i.test(lockfile) ? lockfile : undefined
58
- const graphState = state(value.state)
59
- const truncated = nodes.truncated || edges.truncated
60
- const out = {
61
- state: truncated && graphState === 'COMPLETE' ? 'PARTIAL' : graphState,
62
- ecosystem: 'npm', root: '(root)',
63
- completeness: {
64
- nodes: count(value?.completeness?.nodes, nodes.total, nodes.items.length),
65
- edges: count(value?.completeness?.edges, edges.total, edges.items.length),
66
- declarations: numericRecord(value?.completeness?.declarations, ['total', 'resolved', 'unresolved', 'local', 'optionalMissing']),
67
- reasons: reasons(value?.completeness?.reasons),
68
- },
69
- nodes: nodes.items, edges: edges.items,
70
- }
71
- set(out, 'lockfile', safeLockfile)
72
- const lockfileVersion = int(value.lockfileVersion)
73
- if (lockfileVersion > 0) out.lockfileVersion = lockfileVersion
74
- return out
75
- }
76
-
77
- export function sanitizePackages(value) {
78
- const inventory = list(value?.inventory, CAPS.packages, packageFact, (a, b) => compare(a.ecosystem, b.ecosystem) || compare(a.name, b.name) || compare(a.version, b.version))
79
- const directUsage = list(value?.directUsage, CAPS.usage, usage, (a, b) => compare(a.ecosystem, b.ecosystem) || compare(a.name, b.name))
80
- const dependencyGraph = sanitizePackageDependencyGraph(value?.dependencyGraph)
81
- const outState = state(value?.state)
82
- const truncated = inventory.truncated || directUsage.truncated || (dependencyGraph.state === 'PARTIAL' && value?.dependencyGraph?.state === 'COMPLETE')
83
- return {
84
- state: truncated && outState === 'COMPLETE' ? 'PARTIAL' : outState,
85
- verdict: verdict(value?.verdict),
86
- completeness: {
87
- inventory: count(value?.completeness?.inventory, inventory.total, inventory.items.length),
88
- directUsage: count(value?.completeness?.directUsage, directUsage.total, directUsage.items.length),
89
- dependencyGraphNodes: count(value?.completeness?.dependencyGraphNodes, dependencyGraph.completeness.nodes.total, dependencyGraph.nodes.length),
90
- dependencyGraphEdges: count(value?.completeness?.dependencyGraphEdges, dependencyGraph.completeness.edges.total, dependencyGraph.edges.length),
91
- reasons: reasons(value?.completeness?.reasons),
92
- },
93
- checks: checks(value?.checks), inventory: inventory.items, directUsage: directUsage.items, dependencyGraph,
94
- }
95
- }
@@ -1,97 +0,0 @@
1
- const CONTROL_CHARS = /[\u0000-\u001f\u007f]/;
2
- const ABSOLUTE_PATH_FRAGMENT = /(?:^|[\/\s"'`(=])[a-z]:[\\/]|(?:^|[\s"'`(=])(?:\\\\[^\\/\s]+(?:[\\/]|$)|file:(?:\/\/)?[\\/]|\/(?!\/)[^\s])/i;
3
-
4
- export const MAX_SYNC_BODY_BYTES = 8 * 1024 * 1024;
5
- export const MAX_SYNC_NODES = 25_000;
6
- export const MAX_SYNC_LINKS = 100_000;
7
- export const MAX_SYNC_EXTERNAL_IMPORTS = 50_000;
8
-
9
- export function metadataString(value, max = 4096) {
10
- return typeof value === 'string' && value.length > 0 && value.length <= max && !CONTROL_CHARS.test(value)
11
- ? value : undefined;
12
- }
13
-
14
- export function repoRelativePathString(value, max = 4096) {
15
- const path = metadataString(value, max);
16
- if (!path || /^(?:[a-z][a-z0-9+.-]*:|[\\/])/i.test(path)) return undefined;
17
- const segments = path.split(/[\\/]/);
18
- if (segments.some((segment) => segment === '.' || segment === '..')) return undefined;
19
- return path;
20
- }
21
-
22
- export function graphIdString(value) {
23
- const id = metadataString(value);
24
- if (!id) return undefined;
25
- const hash = id.indexOf('#');
26
- const file = hash < 0 ? id : id.slice(0, hash);
27
- return repoRelativePathString(file) ? id : undefined;
28
- }
29
-
30
- export function privacySafeText(value, max = 4096) {
31
- const text = metadataString(value, max);
32
- return text && !ABSOLUTE_PATH_FRAGMENT.test(text) ? text : undefined;
33
- }
34
-
35
- export function repoPathV3(value, max = 4096) {
36
- const path = repoRelativePathString(value, max);
37
- return path ? path.replace(/\\/g, '/') : undefined;
38
- }
39
-
40
- export function graphIdV3(value) {
41
- const id = metadataString(value);
42
- if (!id) return undefined;
43
- const hash = id.indexOf('#');
44
- const file = hash < 0 ? id : id.slice(0, hash);
45
- const safeFile = repoPathV3(file);
46
- if (!safeFile) return undefined;
47
- if (hash < 0) return safeFile;
48
- const suffix = id.slice(hash);
49
- if (suffix.length > 512 || !/^#[^\\/\s\u0000-\u001f\u007f]{1,511}$/u.test(suffix)) return undefined;
50
- return `${safeFile}${suffix}`;
51
- }
52
-
53
- export function safeToken(value, max = 256) {
54
- const token = metadataString(value, max);
55
- return token && /^[\p{L}\p{N}_.:@+\-#$<>()\[\],]+$/u.test(token) ? token : undefined;
56
- }
57
-
58
- export function packageName(value) {
59
- const name = metadataString(value, 256);
60
- return name && /^(?:@[a-z0-9._-]+\/)?[a-z0-9][a-z0-9._-]*$/i.test(name) ? name : undefined;
61
- }
62
-
63
- export function externalSpecifier(value) {
64
- const spec = metadataString(value, 512);
65
- if (!spec || ABSOLUTE_PATH_FRAGMENT.test(spec) || /^(?:[a-z]:[\\/]|[\\/]|\.\.?[\\/])/i.test(spec)) return undefined;
66
- return /^[a-z0-9@][a-z0-9@._:/+\-]*$/i.test(spec) ? spec : undefined;
67
- }
68
-
69
- export function finiteNumber(value) {
70
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
71
- }
72
-
73
- export function setIf(out, key, value) {
74
- if (value !== undefined) out[key] = value;
75
- }
76
-
77
- const COMPLEXITY_NUMBERS = [
78
- 'startLine', 'endLine', 'loc', 'params', 'objectFields', 'branches', 'cyclomatic',
79
- 'loops', 'maxLoopDepth', 'returns', 'awaits', 'callCount', 'externalCalls',
80
- 'asyncBoundaries', 'allocations', 'objectLiterals', 'spreadCopies', 'sorts',
81
- 'linearOps', 'allocationsInLoops', 'copiesInLoops', 'linearOpsInLoops',
82
- 'sortsInLoops', 'recursionInLoops', 'timeRank', 'timeScore', 'memoryRank', 'memoryScore',
83
- ];
84
-
85
- export function sanitizeComplexity(value) {
86
- if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
87
- const out = {};
88
- for (const key of COMPLEXITY_NUMBERS) setIf(out, key, finiteNumber(value[key]));
89
- if (typeof value.recursion === 'boolean') out.recursion = value.recursion;
90
- for (const key of ['family', 'scope', 'complexityScope', 'confidence']) setIf(out, key, metadataString(value[key], 32));
91
- return Object.keys(out).length ? out : undefined;
92
- }
93
-
94
- export function assertArrayLimit(raw, key, limit) {
95
- const count = Array.isArray(raw[key]) ? raw[key].length : 0;
96
- if (count > limit) throw new Error(`${key} has ${count} entries; maximum is ${limit}`);
97
- }
@@ -1,54 +0,0 @@
1
- import {
2
- finiteNumber, graphIdString, metadataString, repoRelativePathString,
3
- sanitizeComplexity, setIf,
4
- } from './payload-common.mjs';
5
-
6
- export function sanitizeNode(value) {
7
- if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
8
- const id = graphIdString(value.id);
9
- if (!id) return null;
10
- const out = {id};
11
- setIf(out, 'label', metadataString(value.label, 1024));
12
- setIf(out, 'file_type', metadataString(value.file_type, 32));
13
- setIf(out, 'source_file', repoRelativePathString(value.source_file));
14
- const sourceLocation = metadataString(value.source_location, 32);
15
- const sourceEnd = metadataString(value.source_end, 32);
16
- if (sourceLocation && /^L\d+$/.test(sourceLocation)) out.source_location = sourceLocation;
17
- if (sourceEnd && /^L\d+$/.test(sourceEnd)) out.source_end = sourceEnd;
18
- const community = finiteNumber(value.community);
19
- if (community !== undefined && Number.isInteger(community) && community >= 0) out.community = community;
20
- if (typeof value.exported === 'boolean') out.exported = value.exported;
21
- if (typeof value.decorated === 'boolean') out.decorated = value.decorated;
22
- if (value.test_surface === true) out.test_surface = true;
23
- setIf(out, 'complexity', sanitizeComplexity(value.complexity));
24
- return out;
25
- }
26
-
27
- export function sanitizeLink(value) {
28
- if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
29
- const source = graphIdString(value.source);
30
- const target = graphIdString(value.target);
31
- if (!source || !target) return null;
32
- const out = {source, target};
33
- setIf(out, 'relation', metadataString(value.relation, 32));
34
- setIf(out, 'confidence', metadataString(value.confidence, 32));
35
- if (value.typeOnly === true) out.typeOnly = true;
36
- if (value.compileOnly === true) out.compileOnly = true;
37
- const line = finiteNumber(value.line);
38
- if (line !== undefined && Number.isInteger(line) && line >= 0) out.line = line;
39
- setIf(out, 'specifier', metadataString(value.specifier));
40
- return out;
41
- }
42
-
43
- export function sanitizeExternalImport(value) {
44
- if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
45
- const file = repoRelativePathString(value.file);
46
- if (!file) return null;
47
- const out = {file};
48
- for (const key of ['spec', 'target']) setIf(out, key, metadataString(value[key]));
49
- for (const key of ['pkg', 'kind', 'ecosystem']) setIf(out, key, metadataString(value[key], 256));
50
- const line = finiteNumber(value.line);
51
- if (line !== undefined && Number.isInteger(line) && line >= 0) out.line = line;
52
- for (const key of ['builtin', 'dynamic', 'unresolved']) if (typeof value[key] === 'boolean') out[key] = value[key];
53
- return out;
54
- }
@@ -1,79 +0,0 @@
1
- import {edgeProvenance} from '../../graph/edge-provenance.js';
2
- import {
3
- externalSpecifier, graphIdV3, packageName, privacySafeText, repoPathV3,
4
- safeToken, setIf,
5
- } from './payload-common.mjs';
6
- import {sanitizeExternalImport, sanitizeLink, sanitizeNode} from './payload-v2.mjs';
7
-
8
- export function sanitizeNodeV3(value) {
9
- const out = sanitizeNode(value);
10
- if (!out) return null;
11
- const id = graphIdV3(value.id);
12
- if (!id) return null;
13
- const sourceFile = value.source_file == null ? undefined : repoPathV3(value.source_file);
14
- if (value.source_file != null && !sourceFile) return null;
15
- const hash = id.indexOf('#');
16
- const idFile = hash < 0 ? id : id.slice(0, hash);
17
- if (sourceFile && idFile !== sourceFile) return null;
18
- out.id = id;
19
- const label = privacySafeText(value.label, 1024);
20
- if (label) out.label = label;
21
- else delete out.label;
22
- const fileType = safeToken(value.file_type, 32);
23
- if (fileType) out.file_type = fileType;
24
- else delete out.file_type;
25
- if (sourceFile) out.source_file = sourceFile;
26
- else delete out.source_file;
27
- for (const key of ['symbol_kind', 'symbol_space', 'member_of', 'visibility']) setIf(out, key, safeToken(value[key], 128));
28
- if (out.complexity) for (const key of ['family', 'scope', 'complexityScope', 'confidence']) {
29
- const safe = safeToken(value.complexity?.[key], 32);
30
- if (safe) out.complexity[key] = safe;
31
- else delete out.complexity[key];
32
- }
33
- return out;
34
- }
35
-
36
- export function sanitizeLinkV3(value) {
37
- const out = sanitizeLink(value);
38
- if (!out) return null;
39
- const source = graphIdV3(value.source);
40
- const target = graphIdV3(value.target);
41
- if (!source || !target) return null;
42
- out.source = source;
43
- out.target = target;
44
- for (const key of ['relation', 'confidence']) {
45
- const safe = safeToken(value[key], 32);
46
- if (safe) out[key] = safe;
47
- else delete out[key];
48
- }
49
- const provenance = edgeProvenance(value);
50
- if (provenance !== 'UNKNOWN') out.provenance = provenance;
51
- const specifier = privacySafeText(value.specifier, 1024);
52
- if (specifier) out.specifier = specifier;
53
- else delete out.specifier;
54
- return out;
55
- }
56
-
57
- export function sanitizeExternalImportV3(value) {
58
- const out = sanitizeExternalImport(value);
59
- if (!out) return null;
60
- const file = repoPathV3(value.file);
61
- if (!file) return null;
62
- out.file = file;
63
- setIf(out, 'spec', externalSpecifier(value.spec));
64
- if (!externalSpecifier(value.spec)) delete out.spec;
65
- setIf(out, 'pkg', packageName(value.pkg));
66
- if (!packageName(value.pkg)) delete out.pkg;
67
- for (const key of ['kind', 'ecosystem']) {
68
- const safe = safeToken(value[key], 64);
69
- if (safe) out[key] = safe;
70
- else delete out[key];
71
- }
72
- if (value.target != null) {
73
- const target = repoPathV3(value.target);
74
- if (target) out.target = target;
75
- else delete out.target;
76
- }
77
- if (value.typeOnly === true) out.typeOnly = true;
78
- return out;
79
- }
@@ -1,23 +0,0 @@
1
- // Defense-in-depth wire sanitizer for evidence snapshots. Each section owns its
2
- // allowlist; this facade only assembles and hashes the versioned wire envelope.
3
- import {createHash} from 'node:crypto'
4
- import {sanitizeArchitecture} from './sync/evidence-architecture.mjs'
5
- import {stableStringify} from './sync/evidence-common.mjs'
6
- import {sanitizeDuplicates} from './sync/evidence-duplicates.mjs'
7
- import {sanitizeHealth, sanitizeTechnologies} from './sync/evidence-health.mjs'
8
- import {sanitizePackages} from './sync/evidence-packages.mjs'
9
-
10
- export function sanitizeEvidenceSnapshot(value) {
11
- if (!value || typeof value !== 'object' || Array.isArray(value) || value.evidenceSnapshotV !== 1) throw new Error('invalid evidence snapshot')
12
- const sections = {
13
- architecture: sanitizeArchitecture(value.sections?.architecture),
14
- duplicates: sanitizeDuplicates(value.sections?.duplicates),
15
- health: sanitizeHealth(value.sections?.health),
16
- technologies: sanitizeTechnologies(value.sections?.technologies),
17
- packages: sanitizePackages(value.sections?.packages),
18
- }
19
- const states = Object.values(sections).map((section) => section.state)
20
- const snapshotState = states.every((item) => item === 'ERROR') ? 'ERROR' : states.every((item) => item === 'COMPLETE' || item === 'NOT_APPLICABLE') ? 'COMPLETE' : 'PARTIAL'
21
- const snapshot = {evidenceSnapshotV: 1, state: snapshotState, sections}
22
- return {...snapshot, snapshotHash: createHash('sha256').update(stableStringify(snapshot)).digest('hex')}
23
- }
@@ -1,70 +0,0 @@
1
- // Versioned, explicit source-free extension schema. Never forward graph.json wholesale.
2
- import {sanitizeEvidenceSnapshot} from './sync-evidence.mjs';
3
- import {
4
- MAX_SYNC_EXTERNAL_IMPORTS, MAX_SYNC_LINKS, MAX_SYNC_NODES, assertArrayLimit,
5
- } from './sync/payload-common.mjs';
6
- import {sanitizeExternalImport, sanitizeLink, sanitizeNode} from './sync/payload-v2.mjs';
7
- import {sanitizeExternalImportV3, sanitizeLinkV3, sanitizeNodeV3} from './sync/payload-v3.mjs';
8
-
9
- export {
10
- MAX_SYNC_BODY_BYTES, MAX_SYNC_EXTERNAL_IMPORTS, MAX_SYNC_LINKS, MAX_SYNC_NODES,
11
- } from './sync/payload-common.mjs';
12
-
13
- export function createSyncPayload(raw) {
14
- if (!raw || typeof raw !== 'object' || Array.isArray(raw) || raw.repoBoundaryV !== 1) {
15
- throw new Error('graph predates repository-boundary hardening');
16
- }
17
- if (!Number.isInteger(raw.edgeTypesV) || raw.edgeTypesV < 2) {
18
- throw new Error('graph predates compile-only edge metadata');
19
- }
20
- const nodes = Array.isArray(raw.nodes) ? raw.nodes.map(sanitizeNode).filter(Boolean) : [];
21
- const links = Array.isArray(raw.links) ? raw.links.map(sanitizeLink).filter(Boolean) : [];
22
- const externalImports = Array.isArray(raw.externalImports)
23
- ? raw.externalImports.map(sanitizeExternalImport).filter(Boolean) : [];
24
- return {
25
- syncPayloadV: 2,
26
- repoBoundaryV: 1,
27
- edgeTypesV: 2,
28
- extImportsV: Number.isInteger(raw.extImportsV) ? raw.extImportsV : 0,
29
- complexityV: Number.isInteger(raw.complexityV) ? raw.complexityV : 0,
30
- nodes,
31
- links,
32
- externalImports,
33
- };
34
- }
35
-
36
- export function createSyncPayloadV3(raw, evidence) {
37
- const base = createSyncPayload(raw);
38
- if (!Number.isInteger(raw.edgeProvenanceV) || raw.edgeProvenanceV < 1) {
39
- throw new Error('graph predates edge provenance metadata');
40
- }
41
- assertArrayLimit(raw, 'nodes', MAX_SYNC_NODES);
42
- assertArrayLimit(raw, 'links', MAX_SYNC_LINKS);
43
- assertArrayLimit(raw, 'externalImports', MAX_SYNC_EXTERNAL_IMPORTS);
44
- const nodes = (raw.nodes || []).map(sanitizeNodeV3).filter(Boolean);
45
- const nodeIds = new Set();
46
- for (const node of nodes) {
47
- if (nodeIds.has(node.id)) throw new Error(`duplicate node id in graph: ${node.id}`);
48
- nodeIds.add(node.id);
49
- }
50
- const links = (raw.links || []).map(sanitizeLinkV3).filter(Boolean);
51
- for (const link of links) {
52
- if (!nodeIds.has(link.source) || !nodeIds.has(link.target)) {
53
- throw new Error(`dangling link in graph: ${link.source} -> ${link.target}`);
54
- }
55
- }
56
- const externalImports = (raw.externalImports || []).map(sanitizeExternalImportV3).filter(Boolean);
57
- return {
58
- syncPayloadV: 3,
59
- repoBoundaryV: base.repoBoundaryV,
60
- edgeTypesV: base.edgeTypesV,
61
- edgeProvenanceV: Number.isInteger(raw.edgeProvenanceV) ? raw.edgeProvenanceV : 0,
62
- extImportsV: base.extImportsV,
63
- complexityV: base.complexityV,
64
- evidenceV: 1,
65
- nodes,
66
- links,
67
- externalImports,
68
- evidence: sanitizeEvidenceSnapshot(evidence),
69
- };
70
- }
@@ -1,54 +0,0 @@
1
- // Text mode stays genuinely compact for agents and older clients: it returns TextContent only.
2
- // JSON mode adds the stable machine-readable structuredContent envelope and mirrors that envelope
3
- // into TextContent for workflow runners that cannot consume structured results directly.
4
-
5
- const TOOL_RESULT_SCHEMA = 'weavatrix.tool.v1'
6
-
7
- export function toolResult(text, result, extra = {}) {
8
- return {
9
- __weavatrixToolResult: true,
10
- text: String(text ?? ''),
11
- result: result && typeof result === 'object' ? result : {},
12
- warnings: Array.isArray(extra.warnings) ? extra.warnings : [],
13
- page: extra.page && typeof extra.page === 'object' ? extra.page : undefined,
14
- completeness: extra.completeness && typeof extra.completeness === 'object' ? extra.completeness : undefined,
15
- }
16
- }
17
-
18
- function repoName(repoRoot) {
19
- const parts = String(repoRoot || '').replace(/[\\/]+$/, '').split(/[\\/]/)
20
- const name = parts.pop() || 'unknown'
21
- return name.normalize('NFKC').replace(/[^a-z0-9._-]+/gi, '-').replace(/^-+|-+$/g, '').slice(0, 128) || 'unknown'
22
- }
23
-
24
- export function normalizeToolResult({toolName, value, args, ctx, refresh, warnings = [], freshness = 'unknown'}) {
25
- const rich = value && typeof value === 'object' && value.__weavatrixToolResult === true
26
- const text = rich ? value.text : String(value ?? '')
27
- const resultWarnings = [...(rich ? value.warnings : []), ...warnings]
28
- if (refresh?.notice) resultWarnings.unshift({code: 'GRAPH_AUTO_REFRESHED', message: refresh.notice})
29
- if (refresh?.error) resultWarnings.unshift({code: 'GRAPH_AUTO_REFRESH_FAILED', message: refresh.error})
30
- const structured = {
31
- schemaVersion: TOOL_RESULT_SCHEMA,
32
- tool: String(toolName || ''),
33
- repo: {name: repoName(ctx?.repoRoot)},
34
- graph: {
35
- revision: refresh?.revision || null,
36
- freshness: refresh?.error ? 'stale' : (refresh?.kind ? 'fresh' : freshness),
37
- update: refresh?.kind || 'none',
38
- changedFiles: Number(refresh?.changedFiles) || 0,
39
- },
40
- result: rich ? value.result : {text},
41
- evidence: [],
42
- warnings: resultWarnings,
43
- page: rich ? (value.page || {}) : {},
44
- ...(rich && value.completeness ? {completeness: value.completeness} : {}),
45
- }
46
- const json = args?.output_format === 'json'
47
- return {
48
- text: json ? JSON.stringify(structured, null, 2) : `Repository: ${structured.repo.name}\n${text}`,
49
- // MCP output schemas apply to every invocation of a tool. The catalog intentionally does not
50
- // advertise one because text mode must not attach a second, potentially very large payload.
51
- // JSON callers still receive the stable structured result as an optional MCP extension.
52
- structured: json ? structured : undefined,
53
- }
54
- }
@@ -1,11 +0,0 @@
1
- // Propagate catalog.mjs's cache-busting query to owner modules so development hot reload remains
2
- // behaviorally identical to the former single-file implementation.
3
- const version = new URL(import.meta.url).search
4
- const load = (path) => import(new URL(`${path}${version}`, import.meta.url).href)
5
- const [lifecycle] = await Promise.all([
6
- load('./actions/graph-lifecycle.mjs'),
7
- ])
8
-
9
- export const tOpenRepo = lifecycle.tOpenRepo
10
- export const tListKnownRepos = lifecycle.tListKnownRepos
11
- export const tRebuildGraph = lifecycle.tRebuildGraph