weavatrix 0.2.2 → 0.2.3
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
CHANGED
|
@@ -173,6 +173,18 @@ disclosed instead of silently guessed; and the server **hot-reloads its watched
|
|
|
173
173
|
modules and catalog** when those files change — other MCP helpers and analysis engines require a
|
|
174
174
|
reconnect.
|
|
175
175
|
|
|
176
|
+
### 0.2.3 real-wrapper patch
|
|
177
|
+
|
|
178
|
+
- Auto-discovery recognizes wrappers that pass a fixed HTTP client method and argument array to a
|
|
179
|
+
shared transport helper, such as `api(axios.get, [url, options])`.
|
|
180
|
+
- Ambiguous handler names can resolve to the unique matching symbol in a module directly imported
|
|
181
|
+
by the route file, allowing proven external frontend calls to suppress only that exact backend
|
|
182
|
+
dead-code candidate.
|
|
183
|
+
- Missing, ambiguous, low-confidence and capped evidence remains review-only; the patch does not
|
|
184
|
+
turn absence of a client match into a dead-code verdict.
|
|
185
|
+
|
|
186
|
+
Full patch notes: [docs/releases/v0.2.3.md](docs/releases/v0.2.3.md).
|
|
187
|
+
|
|
176
188
|
### 0.2.2 regression and cross-repository evidence
|
|
177
189
|
|
|
178
190
|
- Permanent TS/JS/Python/Go/Java/Rust regression fixtures now gate graph correctness, output size,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weavatrix",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Weavatrix — code graph & blast-radius MCP server for AI coding agents: change impact, transitive dependents, health audit, duplicate detection, and coverage mapping over any local repository.",
|
|
6
6
|
"author": "Sergii Ziborov <sergii.ziborov@gmail.com>",
|
|
@@ -181,6 +181,15 @@ function delegatedWrapper(mask, definition, clientNames) {
|
|
|
181
181
|
const urlArgument = definition.parameters.indexOf(found[2]);
|
|
182
182
|
if (urlArgument >= 0) matches.push({ method: found[1].toUpperCase(), urlArgument });
|
|
183
183
|
}
|
|
184
|
+
// Common typed clients keep response/error handling in one helper and pass the concrete
|
|
185
|
+
// axios/http method plus its argument array: api(axios.get, [url, options]). The HTTP method and
|
|
186
|
+
// first transport argument are still statically fixed, so this is as deterministic as a direct
|
|
187
|
+
// axios.get(url) delegation without evaluating the helper.
|
|
188
|
+
const methodReference = new RegExp(`\\b[A-Za-z_$][\\w$]*\\s*\\(\\s*(?:${clients})\\s*(?:\\?\\.|\\.)\\s*(get|post|put|patch|delete|head|options)\\s*,\\s*\\[\\s*([A-Za-z_$][\\w$]*)\\s*(?=[,\\]])`, "gi");
|
|
189
|
+
while ((found = methodReference.exec(body)) && matches.length < 3) {
|
|
190
|
+
const urlArgument = definition.parameters.indexOf(found[2]);
|
|
191
|
+
if (urlArgument >= 0) matches.push({ method: found[1].toUpperCase(), urlArgument });
|
|
192
|
+
}
|
|
184
193
|
const unique = [...new Map(matches.map((item) => [`${item.method}\0${item.urlArgument}`, item])).values()];
|
|
185
194
|
return unique.length === 1 ? unique[0] : null;
|
|
186
195
|
}
|
|
@@ -639,10 +639,22 @@ function bareGraphLabel(value) {
|
|
|
639
639
|
function handlerNodeEvidence(endpoint, graph) {
|
|
640
640
|
const handler = /^[A-Za-z_$][\w$]{0,127}$/.test(String(endpoint?.handler || "")) ? String(endpoint.handler) : null;
|
|
641
641
|
if (!handler) return { handler: null, handlerNodeId: null, handlerResolution: "inline-or-unresolved" };
|
|
642
|
-
const
|
|
642
|
+
const nodes = graph?.nodes || [];
|
|
643
|
+
const matches = nodes.filter((node) =>
|
|
643
644
|
normalizeFile(node?.source_file) && bareGraphLabel(node?.label) === handler && String(node?.id || "") !== normalizeFile(node?.source_file));
|
|
644
|
-
const
|
|
645
|
-
const
|
|
645
|
+
const endpointFile = normalizeFile(endpoint.file);
|
|
646
|
+
const sameFile = matches.filter((node) => normalizeFile(node?.source_file) === endpointFile);
|
|
647
|
+
const byId = new Map(nodes.map((node) => [endpointId(node?.id), node]));
|
|
648
|
+
const linkFile = (value) => {
|
|
649
|
+
const id = endpointId(value);
|
|
650
|
+
return normalizeFile(byId.get(id)?.source_file || String(id || "").split("#")[0]);
|
|
651
|
+
};
|
|
652
|
+
const directlyImportedFiles = new Set((graph?.links || [])
|
|
653
|
+
.filter((link) => ["imports", "re_exports"].includes(link?.relation) && linkFile(link?.source) === endpointFile)
|
|
654
|
+
.map((link) => linkFile(link?.target))
|
|
655
|
+
.filter(Boolean));
|
|
656
|
+
const imported = matches.filter((node) => directlyImportedFiles.has(normalizeFile(node?.source_file)));
|
|
657
|
+
const resolved = sameFile.length === 1 ? sameFile[0] : imported.length === 1 ? imported[0] : matches.length === 1 ? matches[0] : null;
|
|
646
658
|
return {
|
|
647
659
|
handler,
|
|
648
660
|
handlerNodeId: resolved ? String(resolved.id) : null,
|