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.
- package/README.md +83 -39
- package/SECURITY.md +2 -2
- package/docs/releases/v0.2.14.md +93 -0
- package/package.json +2 -2
- package/skill/SKILL.md +57 -38
- package/src/analysis/architecture/contract-graph.js +119 -0
- package/src/analysis/architecture/contract-schema.js +110 -0
- package/src/analysis/architecture/contract-storage.js +35 -0
- package/src/analysis/architecture/contract-verification.js +168 -0
- package/src/analysis/architecture-contract.js +16 -343
- package/src/analysis/change-classification/diff-parser.js +103 -0
- package/src/analysis/change-classification/options.js +40 -0
- package/src/analysis/change-classification/symbol-classifier.js +177 -0
- package/src/analysis/change-classification.js +120 -519
- package/src/analysis/dead-code-review/policy.js +23 -0
- package/src/analysis/dead-code-review.js +9 -19
- package/src/analysis/dep-check.js +10 -57
- package/src/analysis/dep-rules.js +10 -303
- package/src/analysis/dependency/scoped-dependencies.js +40 -0
- package/src/analysis/endpoints/common.js +62 -0
- package/src/analysis/endpoints/extract.js +107 -0
- package/src/analysis/endpoints/inventory.js +84 -0
- package/src/analysis/endpoints/mounts.js +129 -0
- package/src/analysis/endpoints-java.js +80 -3
- package/src/analysis/endpoints.js +3 -448
- package/src/analysis/git-history/analytics.js +177 -0
- package/src/analysis/git-history/collector.js +109 -0
- package/src/analysis/git-history/options.js +68 -0
- package/src/analysis/git-history.js +128 -577
- package/src/analysis/health-capabilities.js +82 -0
- package/src/analysis/http-contracts/analysis.js +169 -0
- package/src/analysis/http-contracts/client-call-detection.js +81 -0
- package/src/analysis/http-contracts/client-call-parser.js +255 -0
- package/src/analysis/http-contracts/graph-context.js +143 -0
- package/src/analysis/http-contracts/matching.js +61 -0
- package/src/analysis/http-contracts/shared.js +86 -0
- package/src/analysis/http-contracts.js +6 -822
- package/src/analysis/internal-audit/dependency-health.js +111 -0
- package/src/analysis/internal-audit/python-manifests.js +65 -0
- package/src/analysis/internal-audit/repo-files.js +55 -0
- package/src/analysis/internal-audit/supply-chain.js +132 -0
- package/src/analysis/internal-audit.collect.js +5 -106
- package/src/analysis/internal-audit.run.js +113 -200
- package/src/analysis/jvm-dependency-evidence.js +69 -0
- package/src/analysis/source-correctness/retry-patterns.js +93 -0
- package/src/analysis/source-correctness.js +225 -0
- package/src/analysis/structure/dependency-graph.js +156 -0
- package/src/analysis/structure/findings.js +142 -0
- package/src/graph/builder/go-receiver-resolution.js +112 -0
- package/src/graph/builder/js/queries.js +48 -0
- package/src/graph/builder/lang-go.js +89 -4
- package/src/graph/builder/lang-js.js +4 -44
- package/src/graph/builder/pass2-resolution.js +68 -0
- package/src/graph/freshness-probe.js +2 -1
- package/src/graph/incremental-refresh.js +3 -2
- package/src/graph/internal-builder.build.js +22 -183
- package/src/graph/internal-builder.pass2.js +161 -0
- package/src/graph/internal-builder.resolvers.js +2 -105
- package/src/graph/resolvers/rust.js +117 -0
- package/src/mcp/actions/advisories.mjs +18 -0
- package/src/mcp/actions/graph-lifecycle.mjs +148 -0
- package/src/mcp/actions/graph-sync.mjs +195 -0
- package/src/mcp/actions/hosted-architecture.mjs +57 -0
- package/src/mcp/architecture-bootstrap.mjs +168 -0
- package/src/mcp/architecture-starter.mjs +234 -0
- package/src/mcp/catalog.mjs +20 -6
- package/src/mcp/evidence/bun-lock-graph.mjs +209 -0
- package/src/mcp/evidence/package-graph-common.mjs +115 -0
- package/src/mcp/evidence/package-lock-graph.mjs +92 -0
- package/src/mcp/evidence-snapshot.package-graph.mjs +5 -474
- package/src/mcp/graph/context-core.mjs +111 -0
- package/src/mcp/graph/context-seeds.mjs +208 -0
- package/src/mcp/graph/context-state.mjs +86 -0
- package/src/mcp/graph/tools-core.mjs +143 -0
- package/src/mcp/graph/tools-query.mjs +223 -0
- package/src/mcp/graph-context.mjs +4 -496
- package/src/mcp/health/audit-format.mjs +172 -0
- package/src/mcp/health/audit.mjs +171 -0
- package/src/mcp/health/dead-code.mjs +110 -0
- package/src/mcp/health/duplicates.mjs +83 -0
- package/src/mcp/health/endpoints.mjs +42 -0
- package/src/mcp/health/structure.mjs +219 -0
- package/src/mcp/runtime-version.mjs +32 -0
- package/src/mcp/server/auto-refresh.mjs +66 -0
- package/src/mcp/server/runtime-config.mjs +43 -0
- package/src/mcp/server/shutdown.mjs +40 -0
- package/src/mcp/sync/evidence-architecture.mjs +54 -0
- package/src/mcp/sync/evidence-common.mjs +88 -0
- package/src/mcp/sync/evidence-duplicates.mjs +100 -0
- package/src/mcp/sync/evidence-health.mjs +56 -0
- package/src/mcp/sync/evidence-packages.mjs +95 -0
- package/src/mcp/sync/payload-common.mjs +97 -0
- package/src/mcp/sync/payload-v2.mjs +53 -0
- package/src/mcp/sync/payload-v3.mjs +79 -0
- package/src/mcp/sync-evidence.mjs +7 -402
- package/src/mcp/sync-payload.mjs +10 -244
- package/src/mcp/tools-actions.mjs +18 -414
- package/src/mcp/tools-architecture.mjs +18 -70
- package/src/mcp/tools-context.mjs +56 -15
- package/src/mcp/tools-endpoints.mjs +4 -1
- package/src/mcp/tools-graph.mjs +17 -331
- package/src/mcp/tools-health.mjs +24 -705
- package/src/mcp-server.mjs +35 -146
- package/src/precision/lsp-client/constants.js +12 -0
- package/src/precision/lsp-client/environment.js +20 -0
- package/src/precision/lsp-client/errors.js +15 -0
- package/src/precision/lsp-client/lifecycle.js +127 -0
- package/src/precision/lsp-client/message-parser.js +81 -0
- package/src/precision/lsp-client/protocol.js +212 -0
- package/src/precision/lsp-client/registry.js +58 -0
- package/src/precision/lsp-client/repo-uri.js +60 -0
- package/src/precision/lsp-client/stdio-client.js +151 -0
- package/src/precision/lsp-client.js +10 -682
- package/src/precision/lsp-overlay/build.js +238 -0
- package/src/precision/lsp-overlay/contract.js +61 -0
- package/src/precision/lsp-overlay/reference-results.js +108 -0
- package/src/precision/lsp-overlay/semantic-inputs.js +62 -0
- package/src/precision/lsp-overlay/source-session.js +134 -0
- package/src/precision/lsp-overlay/store.js +150 -0
- package/src/precision/lsp-overlay/target-index.js +147 -0
- package/src/precision/lsp-overlay/target-query.js +55 -0
- package/src/precision/lsp-overlay.js +11 -868
- package/src/precision/typescript-lsp-provider.js +12 -682
- package/src/precision/typescript-provider/client.js +69 -0
- package/src/precision/typescript-provider/discovery.js +124 -0
- package/src/precision/typescript-provider/project-host.js +249 -0
- package/src/precision/typescript-provider/project-safety.js +161 -0
- package/src/precision/typescript-provider/reference-usage.js +53 -0
- package/src/version.js +7 -0
- package/docs/releases/v0.2.13.md +0 -48
package/README.md
CHANGED
|
@@ -34,8 +34,8 @@ Weavatrix answers questions a text index cannot:
|
|
|
34
34
|
depends on them — with test coverage attached, so the **untested part of the blast radius** stands
|
|
35
35
|
out before you ship.
|
|
36
36
|
- *"Who calls this function?"* → `inspect_symbol` returns exact bounded TS/JS occurrences plus
|
|
37
|
-
source context; `context_bundle` adds
|
|
38
|
-
smaller source workset. `get_dependents` walks the symbol-level reverse graph transitively. Opt into
|
|
37
|
+
source context; `context_bundle` adds production-first graph relations, exact re-export sites,
|
|
38
|
+
diverse call-site excerpts, and a smaller source workset. `get_dependents` walks the symbol-level reverse graph transitively. Opt into
|
|
39
39
|
`include_container_importers:true` only when a broader module-import radius is intended.
|
|
40
40
|
- *"Did my refactor actually decouple anything?"* → `graph_diff base_ref=HEAD~1` builds an immutable
|
|
41
41
|
baseline graph without checking it out, then reports the structural delta: new module
|
|
@@ -116,6 +116,43 @@ find_duplicates
|
|
|
116
116
|
Every dead-code, orphan, dependency and duplicate item remains review evidence. Confirm framework
|
|
117
117
|
conventions and source use before editing; Weavatrix does not auto-delete or merge findings.
|
|
118
118
|
|
|
119
|
+
`run_audit` also returns an explicit capability matrix. `STRUCTURE CHECKED` and a supported package
|
|
120
|
+
ecosystem do not imply `RUNTIME_CORRECTNESS` or `CONCURRENCY` is complete. Maven/Gradle manifests are
|
|
121
|
+
reported `NOT_SUPPORTED`/`PARTIAL` for import-to-artifact verification rather than as a false clean
|
|
122
|
+
`0 declared / 0 external`; bounded Go/Java correctness checks disclose that they are neither compiler
|
|
123
|
+
proof nor a race detector.
|
|
124
|
+
|
|
125
|
+
### Trace an event, queue, worker, cron or CLI flow
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
query_graph
|
|
129
|
+
seed_symbols=["handleAttackEvents"]
|
|
130
|
+
relation_filter=["calls", "references"]
|
|
131
|
+
flow_direction="both"
|
|
132
|
+
-> exact listener plus bounded producers and consumers
|
|
133
|
+
context_bundle label="handleAttackEvents"
|
|
134
|
+
-> production callers first and diverse excerpts around decisive call sites
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Exact symbol seeds avoid fuzzy routing noise and work for non-HTTP entry points without adding a
|
|
138
|
+
special-purpose tool for every framework. A narrow `search_code` registration check is still useful
|
|
139
|
+
when the handler name is not known; it is a discovery aid, not the graph.
|
|
140
|
+
|
|
141
|
+
### Establish an architecture contract without silently changing policy
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
get_architecture_contract action=preview baseline_mode=none
|
|
145
|
+
-> adaptive Maven/Gradle/monorepo territories
|
|
146
|
+
-> observed dependency directions labelled OBSERVED_NOT_ENFORCED
|
|
147
|
+
-> exact proposed file, verification, hash and short-lived token
|
|
148
|
+
get_architecture_contract action=approve confirm_token=<reviewed-token>
|
|
149
|
+
-> creates only a missing .weavatrix/architecture.json
|
|
150
|
+
prepare_change -> edit -> verify_architecture
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Use `baseline_mode=accept-current` only when the owner explicitly accepts current deterministic debt.
|
|
154
|
+
Approval rechecks the graph and never overwrites an existing local or Hosted policy.
|
|
155
|
+
|
|
119
156
|
## Benchmarks
|
|
120
157
|
|
|
121
158
|
Two different gates ship in the repository:
|
|
@@ -126,7 +163,7 @@ Two different gates ship in the repository:
|
|
|
126
163
|
0.2.1 relation baseline. It fails on unexplained signal loss; `MISSING`, `STALE` and `UNBASELINED`
|
|
127
164
|
remain incomplete, not green.
|
|
128
165
|
|
|
129
|
-
|
|
166
|
+
Representative local regression run (Windows x64, Node 24.15.0, July 18, 2026):
|
|
130
167
|
|
|
131
168
|
| Gate | Result | Selected evidence |
|
|
132
169
|
|---|---:|---|
|
|
@@ -218,7 +255,7 @@ No graph yet? Ask the agent to call `rebuild_graph`; it builds the missing graph
|
|
|
218
255
|
With the default `offline` profile (or an explicit capability set containing `retarget`),
|
|
219
256
|
`open_repo` can change the active repository
|
|
220
257
|
and builds a missing graph automatically. A normal
|
|
221
|
-
`open_repo` also upgrades graphs that predate current typed-edge/provenance metadata; `build:false`
|
|
258
|
+
`open_repo` also upgrades graphs that predate current typed-edge/provenance/physical-LOC metadata; `build:false`
|
|
222
259
|
probes without building and refuses a legacy graph. Retargeting is offline but intentionally changes
|
|
223
260
|
the filesystem boundary for subsequent tools; select `pinned` when that boundary must not move.
|
|
224
261
|
|
|
@@ -240,8 +277,8 @@ Every current edge carries versioned provenance. The parser emits `EXTRACTED`, `
|
|
|
240
277
|
confirmed by its bundled `typescript-language-server` + TypeScript runtime to `EXACT_LSP`.
|
|
241
278
|
`CONFLICT` means evidence disagrees. `graph_stats` reports the provenance breakdown and the semantic
|
|
242
279
|
provider's `COMPLETE`, `PARTIAL`, `UNAVAILABLE`, or `OFF` state; `OFF` means precision was explicitly
|
|
243
|
-
disabled and only static evidence is active. Java and Rust language-server providers are not bundled
|
|
244
|
-
|
|
280
|
+
disabled and only static evidence is active. Java and Rust language-server providers are not bundled:
|
|
281
|
+
their edges never become `EXACT_LSP`, even when a mixed repository reports a complete
|
|
245
282
|
TypeScript/JavaScript overlay.
|
|
246
283
|
|
|
247
284
|
The bounded JS/TS provider is enabled by default for new graphs. Set `WEAVATRIX_PRECISION=off`
|
|
@@ -252,19 +289,21 @@ choice as **TypeScript/JavaScript semantic precision**.
|
|
|
252
289
|
**search / source** — `search_code` (ripgrep-backed, pure-Node fallback, with repository-relative
|
|
253
290
|
path globs on Windows/macOS/Linux), `read_source` (a
|
|
254
291
|
symbol's actual code in one hop), `context_bundle` (definition plus grouped inbound/outbound
|
|
255
|
-
containers, exact re-export sites, call-site/target provenance and bounded excerpts around decisive
|
|
292
|
+
containers ranked production-first, exact re-export sites, call-site/target provenance and diverse bounded excerpts around decisive
|
|
256
293
|
edges), `inspect_symbol` (one exact
|
|
257
294
|
bounded TS/JS reference query, logical containers, impact and source excerpts), `list_endpoints` (HTTP route inventory:
|
|
258
295
|
Express/Fastify/Nest/Flask/FastAPI/Go mux/Rust axum and actix-web, including nested Express
|
|
259
|
-
`router.use(...)` mount composition, declaration/reachability counts
|
|
296
|
+
`router.use(...)` mount composition, declaration/reachability counts, mount provenance, and Spring
|
|
297
|
+
conditional/default-active state),
|
|
260
298
|
`trace_endpoint` (one exact composed route → handler → bounded production call graph with call-site excerpts)
|
|
261
299
|
|
|
262
300
|
**health** — `find_dead_code` (bounded review queue for statically unreferenced and test-only files,
|
|
263
301
|
functions, methods, and symbols, with evidence tiers, completed/remaining verification and explicit
|
|
264
302
|
public/framework/dynamic caveats),
|
|
265
|
-
`run_audit` (unused files/exports/dependencies with per-finding manifest/indexed-source/script/config verification;
|
|
303
|
+
`run_audit` (an explicit capability matrix plus unused files/exports/dependencies with per-finding manifest/indexed-source/script/config verification;
|
|
266
304
|
`category:dependencies` isolates missing/unused/duplicate declarations, unresolved imports and lockfile drift,
|
|
267
|
-
missing npm/Go/Python deps,
|
|
305
|
+
missing npm/Go/Python deps, honest Maven/Gradle `NOT_SUPPORTED`/`PARTIAL` import verification, bounded
|
|
306
|
+
Go/Java correctness candidates, runtime
|
|
268
307
|
cycles, type-only/compile-only coupling, orphans, boundary rules, offline OSV vulnerabilities + typosquat +
|
|
269
308
|
lockfile drift; accepts an immutable `base_ref`, `changed_files`, and `debt: new|existing|all` for
|
|
270
309
|
review-scoped results; production paths are the default and `include_classified:true` opts into
|
|
@@ -318,8 +357,10 @@ not CFG, value-propagation, or taint analysis.
|
|
|
318
357
|
**crossrepo** *(included in `offline`; absent from `pinned`; reads only registered local graphs)* —
|
|
319
358
|
`trace_api_contract`; reconciles the selected backend/client graphs and joins routes to client callsites
|
|
320
359
|
|
|
321
|
-
`query_graph` accepts optional `seed_files` when an architectural
|
|
322
|
-
|
|
360
|
+
`query_graph` accepts optional `seed_files` and exact `seed_symbols` when an architectural or
|
|
361
|
+
event-driven question must start from known entry points. `relation_filter` limits edge kinds and
|
|
362
|
+
`flow_direction:forward|backward|both` turns the same graph into a bounded producer/consumer view.
|
|
363
|
+
Resolved explicit seeds are exclusive by default; set `augment_seeds:true` only when
|
|
323
364
|
question-derived seeds are also wanted. A code-shaped identifier such as `startMitigate` is treated
|
|
324
365
|
as a stronger bounded seed than surrounding words such as controller/service/flow; all exact
|
|
325
366
|
same-name declarations are retained instead of adding unrelated concept seeds. Broad
|
|
@@ -329,7 +370,7 @@ and fixture matches. Production-first classification also applies during travers
|
|
|
329
370
|
tests/generated/docs/benchmarks do not leak back from a production seed; name a class in the
|
|
330
371
|
question or set `include_classified:true` to include it. Unreferenced unmatched constant/field leaves
|
|
331
372
|
are hidden unless `include_low_signal:true`. Broad ranking remains orientation evidence; use
|
|
332
|
-
`seed_files`, an exact endpoint, or `inspect_symbol` when the intended entry point is already known.
|
|
373
|
+
`seed_files`, `seed_symbols`, an exact endpoint, or `inspect_symbol` when the intended entry point is already known.
|
|
333
374
|
Instruction words such as “REST”, “path”, and “inspect” do not become fuzzy code seeds.
|
|
334
375
|
|
|
335
376
|
**advisories** *(network, explicit opt-in)* — `refresh_advisories`
|
|
@@ -347,25 +388,29 @@ disclosed instead of silently guessed; and the server **hot-reloads its watched
|
|
|
347
388
|
modules and catalog** when those files change — other MCP helpers and analysis engines require a
|
|
348
389
|
reconnect. Every MCP response also carries local, transient `_meta["weavatrix/metrics"]` with elapsed
|
|
349
390
|
time, output bytes/token estimate, graph freshness/revision/update and graph-cache status. These
|
|
350
|
-
metrics are not persisted or transmitted by Weavatrix.
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
`
|
|
361
|
-
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
391
|
+
metrics are not persisted or transmitted by Weavatrix. If a source checkout's package version moves
|
|
392
|
+
while an old daemon remains alive, `initialize`, `tools/list`, and tool calls fail loudly with
|
|
393
|
+
`STALE_RUNTIME` until the client reconnects; the opt-out is reserved for deliberate development.
|
|
394
|
+
|
|
395
|
+
### 0.2.14 typed flows, honest Health, and architecture bootstrap
|
|
396
|
+
|
|
397
|
+
- Go call resolution now follows receiver types through parameters, locals, constructor returns,
|
|
398
|
+
imported types and struct fields. It links calls such as `bgpSpeaker.RemoveMitigator(update)` to
|
|
399
|
+
`(*Speaker).RemoveMitigator` without guessing across ambiguous same-name receivers.
|
|
400
|
+
- `query_graph` adds exact `seed_symbols`, `relation_filter`, and directed traversal for generic
|
|
401
|
+
event/queue/worker/cron/CLI flows. `context_bundle` ranks production callers before tests and uses
|
|
402
|
+
diverse edge-centered excerpts. `FlowSpec` no longer accidentally requests test traversal.
|
|
403
|
+
- Health exposes per-capability completeness. Maven/Gradle support is honest instead of returning a
|
|
404
|
+
clean zero, and bounded Go/Java correctness findings never claim compiler, runtime, race, or
|
|
405
|
+
concurrency proof. Spring endpoints expose conditional/default-inactive controllers.
|
|
406
|
+
- Architecture bootstrap adapts to Maven/Gradle/monorepo source roots and uses a reviewable
|
|
407
|
+
preview/approve handshake. A stale daemon now refuses analysis when its runtime version differs
|
|
408
|
+
from the package on disk.
|
|
409
|
+
- The MCP implementation and static site are split into owner-focused modules/assets. A release test
|
|
410
|
+
enforces a physical 300-line maximum for JavaScript/TypeScript under `src`, `bin`, `scripts`, and
|
|
411
|
+
`test`, plus maintained HTML/CSS/JavaScript under `site`.
|
|
412
|
+
|
|
413
|
+
Full patch notes: [docs/releases/v0.2.14.md](docs/releases/v0.2.14.md).
|
|
369
414
|
|
|
370
415
|
### 0.2.9 correctness, signal, and consent patch
|
|
371
416
|
|
|
@@ -752,10 +797,10 @@ The benchmark checks representative graph correctness, complete edge provenance,
|
|
|
752
797
|
HTTP tracing, output bytes, latency, freshness, reconnect and active-target stability. Its budgets, semantics and intentionally
|
|
753
798
|
limited claims are documented in [docs/benchmarking.md](docs/benchmarking.md).
|
|
754
799
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
800
|
+
Maintained JavaScript/TypeScript files under `src`, `bin`, `scripts`, and `test`, plus HTML/CSS/JavaScript
|
|
801
|
+
under `site`, have a hard physical 300-line ceiling enforced by the release suite. Larger concerns are
|
|
802
|
+
split into owner-focused modules behind slim stable facades (`foo.js` re-exports `foo.parse.js`,
|
|
803
|
+
`foo.report.js`, …). The MCP layer lives
|
|
759
804
|
in `src/mcp/` (graph context, tool entry modules, focused helpers, and the catalog/hot-reload
|
|
760
805
|
loader) behind the thin stdio entry `src/mcp-server.mjs`.
|
|
761
806
|
|
|
@@ -763,9 +808,8 @@ loader) behind the thin stdio entry `src/mcp-server.mjs`.
|
|
|
763
808
|
|
|
764
809
|
- **Public 0.2.2 regression foundation** now has the permanent six-language golden corpus,
|
|
765
810
|
cross-repository wrapper/liveness fixture, framework/convention fixture, full MCP lifecycle gate
|
|
766
|
-
and a portable real-repository runner.
|
|
767
|
-
recorded; edge provenance is gated end-to-end
|
|
768
|
-
explicit local gap preventing the strict six-repository release command from passing here.
|
|
811
|
+
and a portable real-repository runner. Six source-free 0.2.1 real-repository baselines are
|
|
812
|
+
recorded; edge provenance is gated end-to-end and the strict six-repository release command passes.
|
|
769
813
|
- **Wrapper-aware API contracts** shipped in 0.2.2: persistent/ad-hoc configuration,
|
|
770
814
|
conservative discovery, cross-repository handler liveness and explicit unknown states. The next
|
|
771
815
|
hosted increment joins privacy-safe contract identities across separately synced services.
|
package/SECURITY.md
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
| Version | Supported |
|
|
6
6
|
|---|---|
|
|
7
|
-
| `0.2.
|
|
8
|
-
| `0.2.
|
|
7
|
+
| `0.2.14.x` | Yes |
|
|
8
|
+
| `0.2.13` and older | Upgrade to the latest release |
|
|
9
9
|
|
|
10
10
|
Security fixes are provided for the latest published version of Weavatrix. Upgrade before reporting
|
|
11
11
|
an issue that may already be resolved.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Weavatrix 0.2.14
|
|
2
|
+
|
|
3
|
+
0.2.14 is a trust and maintainability release found by dogfooding the MCP on a Go BGP service and a
|
|
4
|
+
Java event-driven application. It keeps the 38-tool surface and the local-first/Hosted wire boundary,
|
|
5
|
+
while closing false dead-code, false clean-health, noisy flow, weak architecture-bootstrap, and stale
|
|
6
|
+
daemon failure modes.
|
|
7
|
+
|
|
8
|
+
## Go receiver-aware call flow
|
|
9
|
+
|
|
10
|
+
- Go call resolution now carries receiver types from function parameters, explicit and inferred
|
|
11
|
+
locals, constructor return types (including the first value of `value, err := pkg.New()`), imported
|
|
12
|
+
package types, and struct fields.
|
|
13
|
+
- Calls such as `bgpSpeaker.RemoveMitigator(update)` resolve to
|
|
14
|
+
`(*Speaker).RemoveMitigator` instead of leaving the method falsely test-only.
|
|
15
|
+
- Unknown or ambiguous same-name receivers still fail closed rather than inventing a call edge.
|
|
16
|
+
|
|
17
|
+
## Focused generic flows
|
|
18
|
+
|
|
19
|
+
- `query_graph` accepts exact `seed_symbols`, a `relation_filter`, and
|
|
20
|
+
`flow_direction: forward|backward|both`. The same bounded graph can now trace Kafka listeners,
|
|
21
|
+
queues, workers, cron jobs, CLI entry points, and other event/data flows without one tool per
|
|
22
|
+
framework.
|
|
23
|
+
- Exact seeds remain exclusive unless `augment_seeds:true` is requested. CamelCase identifiers such
|
|
24
|
+
as `FlowSpec` no longer opt tests into production traversal merely because they contain `spec`.
|
|
25
|
+
- `context_bundle` ranks production callers before classified test callers and uses diverse,
|
|
26
|
+
non-overlapping excerpts around decisive call sites.
|
|
27
|
+
|
|
28
|
+
## Honest Health and endpoint state
|
|
29
|
+
|
|
30
|
+
- `run_audit` returns an explicit capability matrix for structure, dependencies, runtime correctness,
|
|
31
|
+
concurrency, advisories, malware scanning, and measured coverage. Each row has independent status
|
|
32
|
+
and completeness.
|
|
33
|
+
- Maven and Gradle manifests are detected and inventoried, but unsupported import-to-artifact
|
|
34
|
+
verification returns `NOT_SUPPORTED`/`PARTIAL` instead of a misleading complete zero.
|
|
35
|
+
- Conservative source checks can flag selected Go fixed-index slice/discriminator hazards and Java
|
|
36
|
+
interruption/retry candidates, including conditional `while` and `do/while` loops with failure plus
|
|
37
|
+
wait behavior but no visible attempt/deadline/cancellation policy. The result explicitly does not
|
|
38
|
+
claim compiler, runtime, CFG, race, or full concurrency proof.
|
|
39
|
+
- Ordinary Go grouped imports (`import (...)`) no longer trigger the JavaScript dynamic-import caveat;
|
|
40
|
+
real Go reflection evidence remains visible independently.
|
|
41
|
+
- Spring endpoint inventory includes conditional activation evidence and whether a controller is
|
|
42
|
+
inactive by default.
|
|
43
|
+
|
|
44
|
+
## Safe target-architecture bootstrap
|
|
45
|
+
|
|
46
|
+
- The starter discovers adaptive Maven/Gradle source roots and nested monorepo product territories
|
|
47
|
+
instead of grouping an entire Java application under its first directory. Oversized Java package
|
|
48
|
+
branches split recursively at real child packages, while a large flat package remains an honest
|
|
49
|
+
size hotspot instead of being divided into invented components.
|
|
50
|
+
- Observed dependency directions are proposed separately as `OBSERVED_NOT_ENFORCED`; inventory is not
|
|
51
|
+
silently promoted to intended architecture.
|
|
52
|
+
- Only universal starter guards (`runtimeCycles=0`, `maxFileLoc=300`) are active. Generic function,
|
|
53
|
+
complexity, cohesion, and boundary thresholds are returned as `CANDIDATE_NOT_ENFORCED` so a first
|
|
54
|
+
preview does not manufacture hundreds of policy violations.
|
|
55
|
+
- `maxFileLoc` now reads physical file LOC stored on file nodes, not the last declaration's end line;
|
|
56
|
+
older graphs rebuild before this budget can report a pass.
|
|
57
|
+
- `get_architecture_contract action=preview` returns the materialized candidate, verification, exact
|
|
58
|
+
file content/hash, and a short-lived token without writing. `action=approve` rechecks repository and
|
|
59
|
+
graph identity, then creates only a missing `.weavatrix/architecture.json` with the exact reviewed
|
|
60
|
+
content. Existing policy is never overwritten.
|
|
61
|
+
- `baseline_mode=accept-current` is an explicit owner action for ratcheting accepted current debt; the
|
|
62
|
+
default records no baseline findings.
|
|
63
|
+
|
|
64
|
+
## Runtime and codebase integrity
|
|
65
|
+
|
|
66
|
+
- The MCP compares its running version with the package version on disk. A mismatch blocks
|
|
67
|
+
`initialize`, `tools/list`, and tool calls with `STALE_RUNTIME` until the client reconnects. The
|
|
68
|
+
environment override is reserved for deliberate source development.
|
|
69
|
+
- Large MCP, graph, analysis, precision, and test modules were split into owner-focused folders with
|
|
70
|
+
stable hot-reload facades. The watcher and cache-busting chain include the new graph, Health,
|
|
71
|
+
action, and architecture owner modules, so supported tool edits still go live without reconnecting.
|
|
72
|
+
- The public page keeps the same design and continuous canvas graph animation while CSS and animation
|
|
73
|
+
code move into focused assets. A release test enforces a physical 300-line ceiling for
|
|
74
|
+
JavaScript/TypeScript under `src`, `bin`, `scripts`, and `test`, plus site HTML/CSS/JavaScript.
|
|
75
|
+
- The 38-tool catalog and profile counts remain unchanged: 31 pinned, 34 offline, 35 OSV, and 38
|
|
76
|
+
hosted/full.
|
|
77
|
+
|
|
78
|
+
## Compatibility and security
|
|
79
|
+
|
|
80
|
+
- Hosted payload v2/v3, `preview_sync` confirmation, and architecture-contract transport are
|
|
81
|
+
unchanged. This release does not modify the separate Hosted frontend/backend application.
|
|
82
|
+
- Local architecture approval writes only inside the active repository boundary, uses an exclusive
|
|
83
|
+
create, expires and consumes tokens, rejects repository/graph drift, and refuses an existing target.
|
|
84
|
+
- Source bodies, snippets, absolute paths, credentials, environment values, and Git remotes remain
|
|
85
|
+
excluded from Hosted sync payloads.
|
|
86
|
+
|
|
87
|
+
## Verification
|
|
88
|
+
|
|
89
|
+
The release is gated by the full Node suite (538 tests: 535 passed and three platform skips), the
|
|
90
|
+
six-language fixture benchmark, a 6/6 real-repository semantic-regression gate, zero npm audit
|
|
91
|
+
vulnerabilities, packed npm and MCPB stdio checks, plus direct Go and Java dogfooding. Cold timings
|
|
92
|
+
vary with machine load and repository snapshots; the public README keeps a dated representative
|
|
93
|
+
run instead of presenting one release machine's timing as a universal result.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weavatrix",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local repository intelligence MCP for AI coding agents: reusable architecture graph for fast application understanding, Health, dead code, clones, history, blast radius and architecture safeguards.",
|
|
6
6
|
"author": "Sergii Ziborov <sergii.ziborov@gmail.com>",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"skill",
|
|
27
27
|
"scripts/run-agent-task-benchmark.mjs",
|
|
28
28
|
"docs/agent-task-benchmark.md",
|
|
29
|
-
"docs/releases/v0.2.
|
|
29
|
+
"docs/releases/v0.2.14.md",
|
|
30
30
|
"README.md",
|
|
31
31
|
"SECURITY.md",
|
|
32
32
|
"LICENSE"
|
package/skill/SKILL.md
CHANGED
|
@@ -17,10 +17,11 @@ Tools are named `mcp__weavatrix__…`. If none are available, ask the user to re
|
|
|
17
17
|
`codex mcp add weavatrix -- npx -y weavatrix <repoRoot>`), then retry.
|
|
18
18
|
|
|
19
19
|
First compare the selected profile with the `graph_stats` runtime line. Expected catalogs are 31
|
|
20
|
-
tools for `pinned`, 34 for `offline`, 35 for `osv`, and 38 for `hosted` / `full`.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
tools for `pinned`, 34 for `offline`, 35 for `osv`, and 38 for `hosted` / `full`. Weavatrix refuses
|
|
21
|
+
`initialize`, `tools/list`, and tool calls when the running package version differs from the
|
|
22
|
+
`package.json` version on disk, with a loud `STALE_RUNTIME` error; restart/reconnect rather than using
|
|
23
|
+
an old daemon. `WEAVATRIX_ALLOW_STALE_RUNTIME=1` is only for deliberate source development. A custom
|
|
24
|
+
capability list needs `crossrepo` for `trace_api_contract`; legacy `online` adds only
|
|
24
25
|
`advisories,hosted`. Missing HTTP tools are intentional only when the selected profile excludes them.
|
|
25
26
|
|
|
26
27
|
Profiles use the same npm package and binary:
|
|
@@ -53,8 +54,10 @@ projection; expand only when the answer requires it.
|
|
|
53
54
|
- **Find a connectivity path between two concepts**: `shortest_path`. It traverses the graph as
|
|
54
55
|
undirected reachability, so it is not proof of call/dependency direction; confirm direction with
|
|
55
56
|
`get_neighbors` and `read_source`.
|
|
56
|
-
- **Explore an unknown entry point or architectural question**: `query_graph`; pin `seed_files`
|
|
57
|
-
known
|
|
57
|
+
- **Explore an unknown entry point or architectural question**: `query_graph`; pin `seed_files` or
|
|
58
|
+
exact `seed_symbols` when known. Use `relation_filter` plus `flow_direction` for a bounded event,
|
|
59
|
+
worker, queue, cron, CLI, or data-flow view; keep a broad natural-language result as orientation
|
|
60
|
+
evidence.
|
|
58
61
|
- **Inspect one exact symbol deeply**: `context_bundle` for the bounded edit workset;
|
|
59
62
|
`inspect_symbol` for the raw point query and on-demand JS/TS reference evidence.
|
|
60
63
|
- **Confirm graph evidence in source**: `read_source`; use `search_code` only for a narrow regex/glob
|
|
@@ -86,11 +89,14 @@ projection; expand only when the answer requires it.
|
|
|
86
89
|
|
|
87
90
|
### Health, debt and testing scenarios
|
|
88
91
|
|
|
89
|
-
- **Run a whole-repository Health review**: `run_audit debt=all
|
|
92
|
+
- **Run a whole-repository Health review**: `run_audit debt=all`, then read its capability matrix.
|
|
93
|
+
`STRUCTURE CHECKED` and `DEPENDENCIES CHECKED` do not imply runtime or concurrency correctness.
|
|
90
94
|
- **Gate only newly introduced branch debt**: `run_audit base_ref=<merge-base> debt=new`; old debt in
|
|
91
95
|
a changed file remains existing.
|
|
92
96
|
- **Review dependency declarations/imports**: `run_audit category=dependencies`; it includes missing,
|
|
93
97
|
unused, duplicate, unresolved-import and lockfile-drift evidence without relabelling identities.
|
|
98
|
+
Maven/Gradle manifests are inventoried but unsupported import-to-artifact verification is reported
|
|
99
|
+
`NOT_SUPPORTED`/`PARTIAL`, never a false clean `0 declared / 0 external`.
|
|
94
100
|
- **Refresh vulnerability evidence when explicitly authorized**: `refresh_advisories`, then
|
|
95
101
|
`run_audit category=vulnerability`. `NOT_CHECKED` is unknown, never clean.
|
|
96
102
|
- **Review dead files, functions, methods and symbols**: `find_dead_code`; every result remains a
|
|
@@ -104,9 +110,15 @@ projection; expand only when the answer requires it.
|
|
|
104
110
|
|
|
105
111
|
### Intended architecture and Hosted governance
|
|
106
112
|
|
|
107
|
-
- **Read or establish intended architecture**: `get_architecture_contract`. A returned starter
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
- **Read or establish intended architecture**: `get_architecture_contract`. A returned starter adapts
|
|
114
|
+
to Maven/Gradle source roots and monorepos and proposes product-code territories plus observed
|
|
115
|
+
dependency directions labelled `OBSERVED_NOT_ENFORCED`; oversized Java branches split only at real
|
|
116
|
+
child packages. Only runtime-cycle and 300-line file guards are active by default; generic
|
|
117
|
+
complexity/cohesion thresholds are `CANDIDATE_NOT_ENFORCED`. None becomes policy automatically.
|
|
118
|
+
- **Bootstrap local policy safely**: `get_architecture_contract action=preview` with an optional
|
|
119
|
+
reviewed `candidate_contract` and `baseline_mode=none|accept-current`; inspect the exact content,
|
|
120
|
+
verification and patch, then call `action=approve confirm_token=<exact-token>`. Approval creates
|
|
121
|
+
only a missing `.weavatrix/architecture.json`, rechecks graph identity, and never overwrites policy.
|
|
110
122
|
- **Select rules before editing**: `prepare_change`; **enforce the ratchet after editing**:
|
|
111
123
|
`verify_architecture`.
|
|
112
124
|
- **Understand or request an exception**: `explain_architecture_violation` ->
|
|
@@ -117,11 +129,13 @@ projection; expand only when the answer requires it.
|
|
|
117
129
|
- **Review exactly what Hosted sync would send**: `preview_sync`; only an approved
|
|
118
130
|
`sync_graph dry_run=false confirm_token=...` may send that exact bounded payload.
|
|
119
131
|
|
|
120
|
-
Across every scenario, treat `PARTIAL`, `UNAVAILABLE`, `OFF`, `
|
|
121
|
-
evidence as incomplete rather than success. Java and Rust exact language-server
|
|
122
|
-
bundled, so their edges never become `EXACT_LSP` even when a mixed repository has
|
|
123
|
-
TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
|
|
124
|
-
`INFERRED`;
|
|
132
|
+
Across every scenario, treat `PARTIAL`, `UNAVAILABLE`, `OFF`, `NOT_SUPPORTED`, `NOT_CHECKED`,
|
|
133
|
+
`ERROR`, or capped evidence as incomplete rather than success. Java and Rust exact language-server
|
|
134
|
+
providers are not bundled, so their edges never become `EXACT_LSP` even when a mixed repository has
|
|
135
|
+
a complete TypeScript/JavaScript overlay. Java and Go receiver-type call edges are parser-resolved
|
|
136
|
+
and explicitly `INFERRED`; Go resolution uses parameter, local, constructor-return, imported and
|
|
137
|
+
struct-field types. These edges improve cross-file flow without claiming compiler-exact overload,
|
|
138
|
+
interface dispatch, reflection, or runtime behavior.
|
|
125
139
|
|
|
126
140
|
## Ground rules
|
|
127
141
|
|
|
@@ -171,10 +185,15 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
|
|
|
171
185
|
and the score is not profiler data or an interprocedural Big-O proof. The default queue uses
|
|
172
186
|
`min_score=85` plus a narrow strong-local fallback; use `min_score=0` only for full diagnostics.
|
|
173
187
|
Inspect its line evidence and measure runtime before scheduling a performance rewrite.
|
|
174
|
-
- **Audit completeness**: read
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
188
|
+
- **Audit completeness**: read the top-level Health capability matrix first: structure, dependencies,
|
|
189
|
+
runtime correctness, concurrency, advisories, malware and measured coverage each have independent
|
|
190
|
+
status/completeness. The bounded Go/Java correctness patterns can flag a fixed-index slice hazard,
|
|
191
|
+
discriminator mismatch, lost Java interrupt or unbounded retry candidate, but they are not a
|
|
192
|
+
compiler, race detector, runtime trace, CFG, or proof of race freedom. Then read
|
|
193
|
+
`dependencyReport.status`, ecosystem support, unused/missing counts, each npm finding's
|
|
194
|
+
`verification` (manifest, indexed source, scripts/config, unresolved dynamic usage), and
|
|
195
|
+
`checks.osv.status` / `checks.malware.status`. A dependency result from a partial or unsupported
|
|
196
|
+
ecosystem is not a repository-wide clean zero. For OSV, `OK` is
|
|
178
197
|
complete for the recorded dependency fingerprint; `PARTIAL` is incomplete or stale,
|
|
179
198
|
`NOT_CHECKED` has no repository-specific result, and `ERROR` means the local check failed. Treat
|
|
180
199
|
the same non-`OK` states as incomplete for malware scanning. Refresh OSV only when the user has
|
|
@@ -248,12 +267,15 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
|
|
|
248
267
|
safety semantics, not boilerplate. Use `.weavatrix-deps.json` entrypoints/nonRuntimeRoots only for
|
|
249
268
|
verified conventions.
|
|
250
269
|
- **API inventory**: `list_endpoints` (including mount provenance, Next.js App Router, Rust axum and
|
|
251
|
-
actix-web).
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
270
|
+
actix-web). Spring endpoint rows also expose conditional activation and whether the controller is
|
|
271
|
+
inactive by default. When one exact route is known, use `trace_endpoint` for its composed mount
|
|
272
|
+
chain, handler and bounded production call graph instead of broad natural-language traversal.
|
|
273
|
+
- **CLI, worker, queue, cron or event flow**: identify the exact listener/handler/registration symbol,
|
|
274
|
+
then call `query_graph seed_symbols=[...] relation_filter=["calls","references"]
|
|
275
|
+
flow_direction="both"`; use `context_bundle` for production-first inbound/outbound containers and
|
|
276
|
+
diverse call-site excerpts, then `get_dependents` / `read_source` for decisive evidence. If the
|
|
277
|
+
symbol is unknown, use a narrow `search_code` registration check once and pin what it finds. Do not
|
|
278
|
+
force a non-HTTP flow through endpoint tools or begin with an unconstrained natural-language seed.
|
|
257
279
|
- **Cross-repository API impact**: ensure both repositories are in `list_known_repos`, then call
|
|
258
280
|
`trace_api_contract backend=<uuid-or-label> clients=[<uuid-or-label>]`; narrow with `method`, `path`,
|
|
259
281
|
or backend `changed_files`. `path` may be a segment-aligned fragment (`/query` can select
|
|
@@ -273,19 +295,16 @@ TypeScript/JavaScript overlay. Java receiver-type call edges are parser-resolved
|
|
|
273
295
|
`UNBASELINED` and `STALE` are explicit incomplete states, not green results.
|
|
274
296
|
A green Java/Rust fixture proves only its declared representative signals, not compiler-exact
|
|
275
297
|
coverage of arbitrary repositories.
|
|
276
|
-
- **Target architecture before editing**:
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
Without a contract, `prepare_change` still returns provisional no-regression budgets, but they are
|
|
287
|
-
guidance rather than enforceable policy. Pull an owner-approved hosted contract only when the user
|
|
288
|
-
selected `hosted` and explicitly asks for it. No Weavatrix tool silently writes either policy.
|
|
298
|
+
- **Target architecture before editing**: if no contract exists, call
|
|
299
|
+
`get_architecture_contract action=preview baseline_mode=none` and inspect the adaptive product
|
|
300
|
+
territories, observed-but-not-enforced directions and verification. Pass a reviewed
|
|
301
|
+
`candidate_contract` when the desired target differs. Only after explicit owner approval call
|
|
302
|
+
`get_architecture_contract action=approve confirm_token=<exact-token>`. Use
|
|
303
|
+
`baseline_mode=accept-current` only when the owner intentionally accepts current deterministic
|
|
304
|
+
debt into the ratchet. Then run `prepare_change` with intended files → edit/rebuild →
|
|
305
|
+
`verify_architecture`. An approved exception is still applied by adding the exact returned proposal
|
|
306
|
+
to `exceptions` and verifying again. Existing contracts are never overwritten; Hosted contracts
|
|
307
|
+
are pulled only after explicit opt-in. No tool silently changes an active policy.
|
|
289
308
|
- **Behavioral architecture**: `git_history` ranks churn × connectivity hotspots and hidden
|
|
290
309
|
co-change coupling from bounded local numstat history. Always set `top_n`; it is enforced across
|
|
291
310
|
every returned structured collection and JSON reports per-collection truncation. Use it as review
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {architectureHash} from './contract-schema.js'
|
|
2
|
+
|
|
3
|
+
export const isSymbolNode = (id) => String(id).includes('#')
|
|
4
|
+
const endpointId = (value) => value && typeof value === 'object' ? String(value.id) : String(value ?? '')
|
|
5
|
+
|
|
6
|
+
export function fileOfNode(id, byId) {
|
|
7
|
+
const node = byId.get(String(id))
|
|
8
|
+
if (node?.source_file) return String(node.source_file).replace(/\\/g, '/')
|
|
9
|
+
return String(id).split('#')[0].replace(/\\/g, '/')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function componentForFile(file, components) {
|
|
13
|
+
const normalized = String(file || '').replace(/\\/g, '/')
|
|
14
|
+
let best = null
|
|
15
|
+
for (const component of components) for (const prefix of component.paths) {
|
|
16
|
+
if (normalized !== prefix && !normalized.startsWith(`${prefix}/`)) continue
|
|
17
|
+
if (!best || prefix.length > best.prefix.length) best = {id: component.id, prefix}
|
|
18
|
+
}
|
|
19
|
+
return best?.id || '(unmapped)'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function relationKind(link) {
|
|
23
|
+
if (link.typeOnly === true) return 'type-only'
|
|
24
|
+
if (link.compileOnly === true) return 'compile-only'
|
|
25
|
+
return 'runtime'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function runtimeFileGraph(graph) {
|
|
29
|
+
const byId = new Map((graph.nodes || []).map((node) => [String(node.id), node]))
|
|
30
|
+
const files = new Set((graph.nodes || []).filter((node) => !isSymbolNode(node.id)).map((node) => String(node.id)))
|
|
31
|
+
const adjacency = new Map([...files].map((file) => [file, new Set()]))
|
|
32
|
+
for (const link of graph.links || []) {
|
|
33
|
+
if (relationKind(link) !== 'runtime' || !['imports', 're_exports'].includes(link.relation) || link.barrelProxy === true) continue
|
|
34
|
+
const source = fileOfNode(endpointId(link.source), byId)
|
|
35
|
+
const target = fileOfNode(endpointId(link.target), byId)
|
|
36
|
+
if (source && target && source !== target && files.has(source) && files.has(target)) adjacency.get(source)?.add(target)
|
|
37
|
+
}
|
|
38
|
+
return adjacency
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function stronglyConnected(adjacency) {
|
|
42
|
+
let index = 0
|
|
43
|
+
const indexes = new Map(), low = new Map(), stack = [], onStack = new Set(), out = []
|
|
44
|
+
const visit = (node) => {
|
|
45
|
+
indexes.set(node, index); low.set(node, index); index++; stack.push(node); onStack.add(node)
|
|
46
|
+
for (const target of adjacency.get(node) || []) {
|
|
47
|
+
if (!indexes.has(target)) { visit(target); low.set(node, Math.min(low.get(node), low.get(target))) }
|
|
48
|
+
else if (onStack.has(target)) low.set(node, Math.min(low.get(node), indexes.get(target)))
|
|
49
|
+
}
|
|
50
|
+
if (low.get(node) !== indexes.get(node)) return
|
|
51
|
+
const component = []
|
|
52
|
+
while (stack.length) {
|
|
53
|
+
const value = stack.pop()
|
|
54
|
+
onStack.delete(value)
|
|
55
|
+
component.push(value)
|
|
56
|
+
if (value === node) break
|
|
57
|
+
}
|
|
58
|
+
if (component.length > 1 || adjacency.get(node)?.has(node)) out.push(component.sort())
|
|
59
|
+
}
|
|
60
|
+
for (const node of [...adjacency.keys()].sort()) if (!indexes.has(node)) visit(node)
|
|
61
|
+
return out.sort((a, b) => b.length - a.length || a[0].localeCompare(b[0]))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function architectureViolation(ruleId, kind, evidence, current, target) {
|
|
65
|
+
const normalizedEvidence = String(evidence).replace(/:\d+(?=\b|$)/g, '')
|
|
66
|
+
const fingerprint = architectureHash({ruleId, kind, evidence: normalizedEvidence}).slice(0, 32)
|
|
67
|
+
return {fingerprint, ruleId, kind, evidence, ...(current != null ? {current} : {}), ...(target != null ? {target} : {})}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const matchComponentSelector = (selector, value) => selector.includes('*') || selector.includes(value)
|
|
71
|
+
|
|
72
|
+
export function collectComponentEdges(graph, contract) {
|
|
73
|
+
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : []
|
|
74
|
+
const links = Array.isArray(graph?.links) ? graph.links : []
|
|
75
|
+
const byId = new Map(nodes.map((node) => [String(node.id), node]))
|
|
76
|
+
const componentEdges = new Map()
|
|
77
|
+
for (const link of links) {
|
|
78
|
+
if (!['imports', 're_exports', 'calls', 'references'].includes(link.relation) || link.barrelProxy === true) continue
|
|
79
|
+
const fromFile = fileOfNode(endpointId(link.source), byId)
|
|
80
|
+
const toFile = fileOfNode(endpointId(link.target), byId)
|
|
81
|
+
if (!fromFile || !toFile || fromFile === toFile) continue
|
|
82
|
+
const from = componentForFile(fromFile, contract.components)
|
|
83
|
+
const to = componentForFile(toFile, contract.components)
|
|
84
|
+
if (from === to) continue
|
|
85
|
+
const kind = relationKind(link)
|
|
86
|
+
const key = `${from}\0${to}\0${kind}`
|
|
87
|
+
const record = componentEdges.get(key) || {from, to, kind, count: 0, samples: []}
|
|
88
|
+
record.count++
|
|
89
|
+
if (record.samples.length < 5) record.samples.push(`${fromFile} -> ${toFile}`)
|
|
90
|
+
componentEdges.set(key, record)
|
|
91
|
+
}
|
|
92
|
+
return {nodes, links, byId, componentEdges}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function collectComponentFitness(nodes, links, byId, contract) {
|
|
96
|
+
const stats = new Map(contract.components.map((component) => [component.id, {
|
|
97
|
+
files: new Set(), internalPairs: new Set(), boundaryPairs: new Set(),
|
|
98
|
+
}]))
|
|
99
|
+
for (const node of nodes.filter((item) => !isSymbolNode(item.id))) {
|
|
100
|
+
const file = String(node.source_file || node.id).replace(/\\/g, '/')
|
|
101
|
+
stats.get(componentForFile(file, contract.components))?.files.add(file)
|
|
102
|
+
}
|
|
103
|
+
const runtimePairs = new Set()
|
|
104
|
+
for (const link of links) {
|
|
105
|
+
if (relationKind(link) !== 'runtime' || !['imports', 're_exports', 'calls', 'references'].includes(link.relation) || link.barrelProxy === true) continue
|
|
106
|
+
const source = fileOfNode(endpointId(link.source), byId), target = fileOfNode(endpointId(link.target), byId)
|
|
107
|
+
if (!source || !target || source === target) continue
|
|
108
|
+
const pair = `${source}\0${target}`
|
|
109
|
+
if (runtimePairs.has(pair)) continue
|
|
110
|
+
runtimePairs.add(pair)
|
|
111
|
+
const from = componentForFile(source, contract.components), to = componentForFile(target, contract.components)
|
|
112
|
+
if (from === to) stats.get(from)?.internalPairs.add(pair)
|
|
113
|
+
else {
|
|
114
|
+
stats.get(from)?.boundaryPairs.add(pair)
|
|
115
|
+
stats.get(to)?.boundaryPairs.add(pair)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return stats
|
|
119
|
+
}
|