weavatrix 0.2.13 → 0.2.14

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 (130) hide show
  1. package/README.md +83 -39
  2. package/SECURITY.md +2 -2
  3. package/docs/releases/v0.2.14.md +93 -0
  4. package/package.json +2 -2
  5. package/skill/SKILL.md +57 -38
  6. package/src/analysis/architecture/contract-graph.js +119 -0
  7. package/src/analysis/architecture/contract-schema.js +110 -0
  8. package/src/analysis/architecture/contract-storage.js +35 -0
  9. package/src/analysis/architecture/contract-verification.js +168 -0
  10. package/src/analysis/architecture-contract.js +16 -343
  11. package/src/analysis/change-classification/diff-parser.js +103 -0
  12. package/src/analysis/change-classification/options.js +40 -0
  13. package/src/analysis/change-classification/symbol-classifier.js +177 -0
  14. package/src/analysis/change-classification.js +120 -519
  15. package/src/analysis/dead-code-review/policy.js +23 -0
  16. package/src/analysis/dead-code-review.js +9 -19
  17. package/src/analysis/dep-check.js +10 -57
  18. package/src/analysis/dep-rules.js +10 -303
  19. package/src/analysis/dependency/scoped-dependencies.js +40 -0
  20. package/src/analysis/endpoints/common.js +62 -0
  21. package/src/analysis/endpoints/extract.js +107 -0
  22. package/src/analysis/endpoints/inventory.js +84 -0
  23. package/src/analysis/endpoints/mounts.js +129 -0
  24. package/src/analysis/endpoints-java.js +80 -3
  25. package/src/analysis/endpoints.js +3 -448
  26. package/src/analysis/git-history/analytics.js +177 -0
  27. package/src/analysis/git-history/collector.js +109 -0
  28. package/src/analysis/git-history/options.js +68 -0
  29. package/src/analysis/git-history.js +128 -577
  30. package/src/analysis/health-capabilities.js +82 -0
  31. package/src/analysis/http-contracts/analysis.js +169 -0
  32. package/src/analysis/http-contracts/client-call-detection.js +81 -0
  33. package/src/analysis/http-contracts/client-call-parser.js +255 -0
  34. package/src/analysis/http-contracts/graph-context.js +143 -0
  35. package/src/analysis/http-contracts/matching.js +61 -0
  36. package/src/analysis/http-contracts/shared.js +86 -0
  37. package/src/analysis/http-contracts.js +6 -822
  38. package/src/analysis/internal-audit/dependency-health.js +111 -0
  39. package/src/analysis/internal-audit/python-manifests.js +65 -0
  40. package/src/analysis/internal-audit/repo-files.js +55 -0
  41. package/src/analysis/internal-audit/supply-chain.js +132 -0
  42. package/src/analysis/internal-audit.collect.js +5 -106
  43. package/src/analysis/internal-audit.run.js +113 -200
  44. package/src/analysis/jvm-dependency-evidence.js +69 -0
  45. package/src/analysis/source-correctness/retry-patterns.js +93 -0
  46. package/src/analysis/source-correctness.js +225 -0
  47. package/src/analysis/structure/dependency-graph.js +156 -0
  48. package/src/analysis/structure/findings.js +142 -0
  49. package/src/graph/builder/go-receiver-resolution.js +112 -0
  50. package/src/graph/builder/js/queries.js +48 -0
  51. package/src/graph/builder/lang-go.js +89 -4
  52. package/src/graph/builder/lang-js.js +4 -44
  53. package/src/graph/builder/pass2-resolution.js +68 -0
  54. package/src/graph/freshness-probe.js +2 -1
  55. package/src/graph/incremental-refresh.js +3 -2
  56. package/src/graph/internal-builder.build.js +22 -183
  57. package/src/graph/internal-builder.pass2.js +161 -0
  58. package/src/graph/internal-builder.resolvers.js +2 -105
  59. package/src/graph/resolvers/rust.js +117 -0
  60. package/src/mcp/actions/advisories.mjs +18 -0
  61. package/src/mcp/actions/graph-lifecycle.mjs +148 -0
  62. package/src/mcp/actions/graph-sync.mjs +195 -0
  63. package/src/mcp/actions/hosted-architecture.mjs +57 -0
  64. package/src/mcp/architecture-bootstrap.mjs +168 -0
  65. package/src/mcp/architecture-starter.mjs +234 -0
  66. package/src/mcp/catalog.mjs +20 -6
  67. package/src/mcp/evidence/bun-lock-graph.mjs +209 -0
  68. package/src/mcp/evidence/package-graph-common.mjs +115 -0
  69. package/src/mcp/evidence/package-lock-graph.mjs +92 -0
  70. package/src/mcp/evidence-snapshot.package-graph.mjs +5 -474
  71. package/src/mcp/graph/context-core.mjs +111 -0
  72. package/src/mcp/graph/context-seeds.mjs +208 -0
  73. package/src/mcp/graph/context-state.mjs +86 -0
  74. package/src/mcp/graph/tools-core.mjs +143 -0
  75. package/src/mcp/graph/tools-query.mjs +223 -0
  76. package/src/mcp/graph-context.mjs +4 -496
  77. package/src/mcp/health/audit-format.mjs +172 -0
  78. package/src/mcp/health/audit.mjs +171 -0
  79. package/src/mcp/health/dead-code.mjs +110 -0
  80. package/src/mcp/health/duplicates.mjs +83 -0
  81. package/src/mcp/health/endpoints.mjs +42 -0
  82. package/src/mcp/health/structure.mjs +219 -0
  83. package/src/mcp/runtime-version.mjs +32 -0
  84. package/src/mcp/server/auto-refresh.mjs +66 -0
  85. package/src/mcp/server/runtime-config.mjs +43 -0
  86. package/src/mcp/server/shutdown.mjs +40 -0
  87. package/src/mcp/sync/evidence-architecture.mjs +54 -0
  88. package/src/mcp/sync/evidence-common.mjs +88 -0
  89. package/src/mcp/sync/evidence-duplicates.mjs +100 -0
  90. package/src/mcp/sync/evidence-health.mjs +56 -0
  91. package/src/mcp/sync/evidence-packages.mjs +95 -0
  92. package/src/mcp/sync/payload-common.mjs +97 -0
  93. package/src/mcp/sync/payload-v2.mjs +53 -0
  94. package/src/mcp/sync/payload-v3.mjs +79 -0
  95. package/src/mcp/sync-evidence.mjs +7 -402
  96. package/src/mcp/sync-payload.mjs +10 -244
  97. package/src/mcp/tools-actions.mjs +18 -414
  98. package/src/mcp/tools-architecture.mjs +18 -70
  99. package/src/mcp/tools-context.mjs +56 -15
  100. package/src/mcp/tools-endpoints.mjs +4 -1
  101. package/src/mcp/tools-graph.mjs +17 -331
  102. package/src/mcp/tools-health.mjs +24 -705
  103. package/src/mcp-server.mjs +35 -146
  104. package/src/precision/lsp-client/constants.js +12 -0
  105. package/src/precision/lsp-client/environment.js +20 -0
  106. package/src/precision/lsp-client/errors.js +15 -0
  107. package/src/precision/lsp-client/lifecycle.js +127 -0
  108. package/src/precision/lsp-client/message-parser.js +81 -0
  109. package/src/precision/lsp-client/protocol.js +212 -0
  110. package/src/precision/lsp-client/registry.js +58 -0
  111. package/src/precision/lsp-client/repo-uri.js +60 -0
  112. package/src/precision/lsp-client/stdio-client.js +151 -0
  113. package/src/precision/lsp-client.js +10 -682
  114. package/src/precision/lsp-overlay/build.js +238 -0
  115. package/src/precision/lsp-overlay/contract.js +61 -0
  116. package/src/precision/lsp-overlay/reference-results.js +108 -0
  117. package/src/precision/lsp-overlay/semantic-inputs.js +62 -0
  118. package/src/precision/lsp-overlay/source-session.js +134 -0
  119. package/src/precision/lsp-overlay/store.js +150 -0
  120. package/src/precision/lsp-overlay/target-index.js +147 -0
  121. package/src/precision/lsp-overlay/target-query.js +55 -0
  122. package/src/precision/lsp-overlay.js +11 -868
  123. package/src/precision/typescript-lsp-provider.js +12 -682
  124. package/src/precision/typescript-provider/client.js +69 -0
  125. package/src/precision/typescript-provider/discovery.js +124 -0
  126. package/src/precision/typescript-provider/project-host.js +249 -0
  127. package/src/precision/typescript-provider/project-safety.js +161 -0
  128. package/src/precision/typescript-provider/reference-usage.js +53 -0
  129. package/src/version.js +7 -0
  130. package/docs/releases/v0.2.13.md +0 -48
@@ -1,245 +1,14 @@
1
- // Versioned, explicit wire schema for sync_graph. Never forward graph.json wholesale: it is a local
2
- // cache file and may contain future fields or attacker-injected data that are not safe to upload.
1
+ // Versioned, explicit wire schema for sync_graph. Never forward graph.json wholesale.
3
2
  import {sanitizeEvidenceSnapshot} from './sync-evidence.mjs';
4
- import {edgeProvenance} from '../graph/edge-provenance.js';
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';
5
8
 
6
- const CONTROL_CHARS = /[\u0000-\u001f\u007f]/;
7
- const ABSOLUTE_PATH_FRAGMENT = /(?:^|[\/\s"'`(=])[a-z]:[\\/]|(?:^|[\s"'`(=])(?:\\\\[^\\/\s]+(?:[\\/]|$)|file:(?:\/\/)?[\\/]|\/(?!\/)[^\s])/i;
8
-
9
- export const MAX_SYNC_BODY_BYTES = 8 * 1024 * 1024;
10
- export const MAX_SYNC_NODES = 25_000;
11
- export const MAX_SYNC_LINKS = 100_000;
12
- export const MAX_SYNC_EXTERNAL_IMPORTS = 50_000;
13
-
14
- function metadataString(value, max = 4096) {
15
- return typeof value === 'string' && value.length > 0 && value.length <= max && !CONTROL_CHARS.test(value)
16
- ? value
17
- : undefined;
18
- }
19
-
20
- // graph.json is derived data and may be edited independently of the repository. Never trust a path
21
- // merely because it occupies an allowlisted field: sync only accepts canonical-looking repo-relative
22
- // paths, on every host OS. Graph IDs append `#symbol@line`, so validate their file portion separately
23
- // while preserving the complete ID on the wire.
24
- function repoRelativePathString(value, max = 4096) {
25
- const path = metadataString(value, max);
26
- if (!path) return undefined;
27
- if (/^(?:[a-z][a-z0-9+.-]*:|[\\/])/i.test(path)) return undefined; // URI, drive path, POSIX or UNC absolute
28
- const segments = path.split(/[\\/]/);
29
- if (segments.some((segment) => segment === '.' || segment === '..')) return undefined;
30
- return path;
31
- }
32
-
33
- function graphIdString(value) {
34
- const id = metadataString(value);
35
- if (!id) return undefined;
36
- const hash = id.indexOf('#');
37
- const file = hash < 0 ? id : id.slice(0, hash);
38
- return repoRelativePathString(file) ? id : undefined;
39
- }
40
-
41
- // Optional display metadata is still attacker-controlled graph data. Keep useful labels/import
42
- // specifiers, but never let an absolute host path hide inside one of those free-text fields.
43
- function privacySafeText(value, max = 4096) {
44
- const text = metadataString(value, max);
45
- if (!text) return undefined;
46
- return ABSOLUTE_PATH_FRAGMENT.test(text) ? undefined : text;
47
- }
48
-
49
- function repoPathV3(value, max = 4096) {
50
- const path = repoRelativePathString(value, max);
51
- return path ? path.replace(/\\/g, '/') : undefined;
52
- }
53
-
54
- function graphIdV3(value) {
55
- const id = metadataString(value);
56
- if (!id) return undefined;
57
- const hash = id.indexOf('#');
58
- const file = hash < 0 ? id : id.slice(0, hash);
59
- const safeFile = repoPathV3(file);
60
- if (!safeFile) return undefined;
61
- if (hash < 0) return safeFile;
62
- const suffix = id.slice(hash);
63
- // Builder IDs are `#symbol@line` (optionally with a short collision suffix). A symbol suffix
64
- // never needs a path separator or whitespace; rejecting both closes an otherwise opaque channel.
65
- if (suffix.length > 512 || !/^#[^\\/\s\u0000-\u001f\u007f]{1,511}$/u.test(suffix)) return undefined;
66
- return `${safeFile}${suffix}`;
67
- }
68
-
69
- function safeToken(value, max = 256) {
70
- const token = metadataString(value, max);
71
- if (!token || !/^[\p{L}\p{N}_.:@+\-#$<>()\[\],]+$/u.test(token)) return undefined;
72
- return token;
73
- }
74
-
75
- function packageName(value) {
76
- const name = metadataString(value, 256);
77
- return name && /^(?:@[a-z0-9._-]+\/)?[a-z0-9][a-z0-9._-]*$/i.test(name) ? name : undefined;
78
- }
79
-
80
- function externalSpecifier(value) {
81
- const spec = metadataString(value, 512);
82
- if (!spec || ABSOLUTE_PATH_FRAGMENT.test(spec) || /^(?:[a-z]:[\\/]|[\\/]|\.\.?[\\/])/i.test(spec)) return undefined;
83
- return /^[a-z0-9@][a-z0-9@._:/+\-]*$/i.test(spec) ? spec : undefined;
84
- }
85
-
86
- function finiteNumber(value) {
87
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
88
- }
89
-
90
- function setIf(out, key, value) {
91
- if (value !== undefined) out[key] = value;
92
- }
93
-
94
- const COMPLEXITY_NUMBERS = [
95
- 'startLine', 'endLine', 'loc', 'params', 'objectFields', 'branches', 'cyclomatic',
96
- 'loops', 'maxLoopDepth', 'returns', 'awaits', 'callCount', 'externalCalls',
97
- 'asyncBoundaries', 'allocations', 'objectLiterals', 'spreadCopies', 'sorts',
98
- 'linearOps', 'allocationsInLoops', 'copiesInLoops', 'linearOpsInLoops',
99
- 'sortsInLoops', 'recursionInLoops', 'timeRank', 'timeScore', 'memoryRank', 'memoryScore',
100
- ];
101
-
102
- function sanitizeComplexity(value) {
103
- if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
104
- const out = {};
105
- for (const key of COMPLEXITY_NUMBERS) setIf(out, key, finiteNumber(value[key]));
106
- if (typeof value.recursion === 'boolean') out.recursion = value.recursion;
107
- for (const key of ['family', 'scope', 'complexityScope', 'confidence']) {
108
- setIf(out, key, metadataString(value[key], 32));
109
- }
110
- return Object.keys(out).length ? out : undefined;
111
- }
112
-
113
- function sanitizeNode(value) {
114
- if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
115
- const id = graphIdString(value.id);
116
- if (!id) return null;
117
- const out = {id};
118
- setIf(out, 'label', metadataString(value.label, 1024));
119
- setIf(out, 'file_type', metadataString(value.file_type, 32));
120
- setIf(out, 'source_file', repoRelativePathString(value.source_file));
121
- const sourceLocation = metadataString(value.source_location, 32);
122
- const sourceEnd = metadataString(value.source_end, 32);
123
- if (sourceLocation && /^L\d+$/.test(sourceLocation)) out.source_location = sourceLocation;
124
- if (sourceEnd && /^L\d+$/.test(sourceEnd)) out.source_end = sourceEnd;
125
- const community = finiteNumber(value.community);
126
- if (community !== undefined && Number.isInteger(community) && community >= 0) out.community = community;
127
- if (typeof value.exported === 'boolean') out.exported = value.exported;
128
- if (typeof value.decorated === 'boolean') out.decorated = value.decorated;
129
- setIf(out, 'complexity', sanitizeComplexity(value.complexity));
130
- return out;
131
- }
132
-
133
- function sanitizeLink(value) {
134
- if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
135
- const source = graphIdString(value.source);
136
- const target = graphIdString(value.target);
137
- if (!source || !target) return null;
138
- const out = {source, target};
139
- setIf(out, 'relation', metadataString(value.relation, 32));
140
- setIf(out, 'confidence', metadataString(value.confidence, 32));
141
- if (value.typeOnly === true) out.typeOnly = true;
142
- if (value.compileOnly === true) out.compileOnly = true;
143
- const line = finiteNumber(value.line);
144
- if (line !== undefined && Number.isInteger(line) && line >= 0) out.line = line;
145
- setIf(out, 'specifier', metadataString(value.specifier));
146
- return out;
147
- }
148
-
149
- function sanitizeExternalImport(value) {
150
- if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
151
- const file = repoRelativePathString(value.file);
152
- if (!file) return null;
153
- const out = {file};
154
- for (const key of ['spec', 'target']) setIf(out, key, metadataString(value[key]));
155
- for (const key of ['pkg', 'kind', 'ecosystem']) setIf(out, key, metadataString(value[key], 256));
156
- const line = finiteNumber(value.line);
157
- if (line !== undefined && Number.isInteger(line) && line >= 0) out.line = line;
158
- for (const key of ['builtin', 'dynamic', 'unresolved']) {
159
- if (typeof value[key] === 'boolean') out[key] = value[key];
160
- }
161
- return out;
162
- }
163
-
164
- function sanitizeNodeV3(value) {
165
- const out = sanitizeNode(value);
166
- if (!out) return null;
167
- const id = graphIdV3(value.id);
168
- if (!id) return null;
169
- const sourceFile = value.source_file == null ? undefined : repoPathV3(value.source_file);
170
- if (value.source_file != null && !sourceFile) return null;
171
- const hash = id.indexOf('#');
172
- const idFile = hash < 0 ? id : id.slice(0, hash);
173
- if (sourceFile && idFile !== sourceFile) return null;
174
- out.id = id;
175
- const label = privacySafeText(value.label, 1024);
176
- if (label) out.label = label;
177
- else delete out.label;
178
- const fileType = safeToken(value.file_type, 32);
179
- if (fileType) out.file_type = fileType;
180
- else delete out.file_type;
181
- if (sourceFile) out.source_file = sourceFile;
182
- else delete out.source_file;
183
- for (const key of ['symbol_kind', 'symbol_space', 'member_of', 'visibility']) setIf(out, key, safeToken(value[key], 128));
184
- if (out.complexity) {
185
- for (const key of ['family', 'scope', 'complexityScope', 'confidence']) {
186
- const safe = safeToken(value.complexity?.[key], 32);
187
- if (safe) out.complexity[key] = safe;
188
- else delete out.complexity[key];
189
- }
190
- }
191
- return out;
192
- }
193
-
194
- function sanitizeLinkV3(value) {
195
- const out = sanitizeLink(value);
196
- if (!out) return null;
197
- const source = graphIdV3(value.source);
198
- const target = graphIdV3(value.target);
199
- if (!source || !target) return null;
200
- out.source = source;
201
- out.target = target;
202
- for (const key of ['relation', 'confidence']) {
203
- const safe = safeToken(value[key], 32);
204
- if (safe) out[key] = safe;
205
- else delete out[key];
206
- }
207
- const provenance = edgeProvenance(value);
208
- if (provenance !== 'UNKNOWN') out.provenance = provenance;
209
- const specifier = privacySafeText(value.specifier, 1024);
210
- if (specifier) out.specifier = specifier;
211
- else delete out.specifier;
212
- return out;
213
- }
214
-
215
- function sanitizeExternalImportV3(value) {
216
- const out = sanitizeExternalImport(value);
217
- if (!out) return null;
218
- const file = repoPathV3(value.file);
219
- if (!file) return null;
220
- out.file = file;
221
- setIf(out, 'spec', externalSpecifier(value.spec));
222
- if (!externalSpecifier(value.spec)) delete out.spec;
223
- setIf(out, 'pkg', packageName(value.pkg));
224
- if (!packageName(value.pkg)) delete out.pkg;
225
- for (const key of ['kind', 'ecosystem']) {
226
- const safe = safeToken(value[key], 64);
227
- if (safe) out[key] = safe;
228
- else delete out[key];
229
- }
230
- if (value.target != null) {
231
- const target = repoPathV3(value.target);
232
- if (target) out.target = target;
233
- else delete out.target;
234
- }
235
- if (value.typeOnly === true) out.typeOnly = true;
236
- return out;
237
- }
238
-
239
- function assertArrayLimit(raw, key, limit) {
240
- const count = Array.isArray(raw[key]) ? raw[key].length : 0;
241
- if (count > limit) throw new Error(`${key} has ${count} entries; maximum is ${limit}`);
242
- }
9
+ export {
10
+ MAX_SYNC_BODY_BYTES, MAX_SYNC_EXTERNAL_IMPORTS, MAX_SYNC_LINKS, MAX_SYNC_NODES,
11
+ } from './sync/payload-common.mjs';
243
12
 
244
13
  export function createSyncPayload(raw) {
245
14
  if (!raw || typeof raw !== 'object' || Array.isArray(raw) || raw.repoBoundaryV !== 1) {
@@ -251,8 +20,7 @@ export function createSyncPayload(raw) {
251
20
  const nodes = Array.isArray(raw.nodes) ? raw.nodes.map(sanitizeNode).filter(Boolean) : [];
252
21
  const links = Array.isArray(raw.links) ? raw.links.map(sanitizeLink).filter(Boolean) : [];
253
22
  const externalImports = Array.isArray(raw.externalImports)
254
- ? raw.externalImports.map(sanitizeExternalImport).filter(Boolean)
255
- : [];
23
+ ? raw.externalImports.map(sanitizeExternalImport).filter(Boolean) : [];
256
24
  return {
257
25
  syncPayloadV: 2,
258
26
  repoBoundaryV: 1,
@@ -266,8 +34,6 @@ export function createSyncPayload(raw) {
266
34
  }
267
35
 
268
36
  export function createSyncPayloadV3(raw, evidence) {
269
- // Reuse the v2 schema gates, but construct v3 arrays independently so the stricter path/identity
270
- // rules cannot change graph-only compatibility for existing endpoints.
271
37
  const base = createSyncPayload(raw);
272
38
  if (!Number.isInteger(raw.edgeProvenanceV) || raw.edgeProvenanceV < 1) {
273
39
  throw new Error('graph predates edge provenance metadata');