@vcad/mcp 0.9.4-main.8 → 0.9.4-main.9
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 +1 -1
- package/index.mjs +49 -108
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -6,4 +6,4 @@ vcad's MCP server as a self-contained bundle (server + BRep kernel WASM).
|
|
|
6
6
|
{ "mcpServers": { "vcad": { "command": "npx", "args": ["-y", "@vcad/mcp"] } } }
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Built from
|
|
9
|
+
Built from c3ef1dae913d41fab4da6f029c6d6b347bb08395 at 2026-07-24T16:14:27.739Z. Source: https://github.com/ecto/vcad
|
package/index.mjs
CHANGED
|
@@ -41533,6 +41533,24 @@ var init_CHANGELOG = __esm({
|
|
|
41533
41533
|
CHANGELOG_default = {
|
|
41534
41534
|
$schema: "./changelog.schema.json",
|
|
41535
41535
|
entries: [
|
|
41536
|
+
{
|
|
41537
|
+
id: "2026-07-24-router-keepout-edge-clearance",
|
|
41538
|
+
version: "0.9.4",
|
|
41539
|
+
date: "2026-07-24",
|
|
41540
|
+
category: "fix",
|
|
41541
|
+
title: "Autorouter respects keepouts and board-edge clearance",
|
|
41542
|
+
summary: "route_nets' legality oracle now indexes no-tracks keepouts and the board outline (incl. cutouts), so routes never cross keepouts or hug the edge inside edge_clearance; multi-round negotiation can no longer finish below the single-round baseline.",
|
|
41543
|
+
features: [
|
|
41544
|
+
"pcb",
|
|
41545
|
+
"autorouter",
|
|
41546
|
+
"drc"
|
|
41547
|
+
],
|
|
41548
|
+
mcpTools: [
|
|
41549
|
+
"route_nets",
|
|
41550
|
+
"run_drc",
|
|
41551
|
+
"validate_for_fab"
|
|
41552
|
+
]
|
|
41553
|
+
},
|
|
41536
41554
|
{
|
|
41537
41555
|
id: "2026-07-23-router-post-route-legalization",
|
|
41538
41556
|
version: "0.9.4",
|
|
@@ -50869,83 +50887,26 @@ var init_store = __esm({
|
|
|
50869
50887
|
});
|
|
50870
50888
|
|
|
50871
50889
|
// src/tools/inspect.ts
|
|
50872
|
-
function signedVolumeOfTriangle(p1, p2, p3) {
|
|
50873
|
-
return (p1[0] * (p2[1] * p3[2] - p3[1] * p2[2]) - p2[0] * (p1[1] * p3[2] - p3[1] * p1[2]) + p3[0] * (p1[1] * p2[2] - p2[1] * p1[2])) / 6;
|
|
50874
|
-
}
|
|
50875
|
-
function triangleArea2(p1, p2, p3) {
|
|
50876
|
-
const ax = p2[0] - p1[0];
|
|
50877
|
-
const ay = p2[1] - p1[1];
|
|
50878
|
-
const az = p2[2] - p1[2];
|
|
50879
|
-
const bx = p3[0] - p1[0];
|
|
50880
|
-
const by = p3[1] - p1[1];
|
|
50881
|
-
const bz = p3[2] - p1[2];
|
|
50882
|
-
const cx = ay * bz - az * by;
|
|
50883
|
-
const cy = az * bx - ax * bz;
|
|
50884
|
-
const cz = ax * by - ay * bx;
|
|
50885
|
-
return Math.sqrt(cx * cx + cy * cy + cz * cz) / 2;
|
|
50886
|
-
}
|
|
50887
|
-
function getVertex(mesh, index) {
|
|
50888
|
-
const i = index * 3;
|
|
50889
|
-
return [mesh.positions[i], mesh.positions[i + 1], mesh.positions[i + 2]];
|
|
50890
|
-
}
|
|
50891
50890
|
function computeMeshProperties(mesh) {
|
|
50892
|
-
const
|
|
50893
|
-
|
|
50894
|
-
|
|
50895
|
-
let cx = 0, cy = 0, cz = 0;
|
|
50896
|
-
let acx = 0, acy = 0, acz = 0;
|
|
50897
|
-
const bbox = {
|
|
50898
|
-
min: { x: Infinity, y: Infinity, z: Infinity },
|
|
50899
|
-
max: { x: -Infinity, y: -Infinity, z: -Infinity }
|
|
50900
|
-
};
|
|
50901
|
-
for (let t2 = 0; t2 < numTriangles; t2++) {
|
|
50902
|
-
const i0 = mesh.indices[t2 * 3];
|
|
50903
|
-
const i1 = mesh.indices[t2 * 3 + 1];
|
|
50904
|
-
const i2 = mesh.indices[t2 * 3 + 2];
|
|
50905
|
-
const p1 = getVertex(mesh, i0);
|
|
50906
|
-
const p2 = getVertex(mesh, i1);
|
|
50907
|
-
const p3 = getVertex(mesh, i2);
|
|
50908
|
-
const v = signedVolumeOfTriangle(p1, p2, p3);
|
|
50909
|
-
volume += v;
|
|
50910
|
-
const a = triangleArea2(p1, p2, p3);
|
|
50911
|
-
area += a;
|
|
50912
|
-
cx += v * (p1[0] + p2[0] + p3[0]) / 4;
|
|
50913
|
-
cy += v * (p1[1] + p2[1] + p3[1]) / 4;
|
|
50914
|
-
cz += v * (p1[2] + p2[2] + p3[2]) / 4;
|
|
50915
|
-
acx += a * (p1[0] + p2[0] + p3[0]) / 3;
|
|
50916
|
-
acy += a * (p1[1] + p2[1] + p3[1]) / 3;
|
|
50917
|
-
acz += a * (p1[2] + p2[2] + p3[2]) / 3;
|
|
50918
|
-
for (const p of [p1, p2, p3]) {
|
|
50919
|
-
bbox.min.x = Math.min(bbox.min.x, p[0]);
|
|
50920
|
-
bbox.min.y = Math.min(bbox.min.y, p[1]);
|
|
50921
|
-
bbox.min.z = Math.min(bbox.min.z, p[2]);
|
|
50922
|
-
bbox.max.x = Math.max(bbox.max.x, p[0]);
|
|
50923
|
-
bbox.max.y = Math.max(bbox.max.y, p[1]);
|
|
50924
|
-
bbox.max.z = Math.max(bbox.max.z, p[2]);
|
|
50925
|
-
}
|
|
50926
|
-
}
|
|
50927
|
-
const absVolume = Math.abs(volume);
|
|
50928
|
-
let centroid = null;
|
|
50929
|
-
if (absVolume > 1e-10) {
|
|
50930
|
-
centroid = { x: cx / volume, y: cy / volume, z: cz / volume };
|
|
50931
|
-
const eps = 1e-9 * Math.max(
|
|
50932
|
-
bbox.max.x - bbox.min.x,
|
|
50933
|
-
bbox.max.y - bbox.min.y,
|
|
50934
|
-
bbox.max.z - bbox.min.z,
|
|
50935
|
-
1
|
|
50936
|
-
);
|
|
50937
|
-
const inBbox = centroid.x >= bbox.min.x - eps && centroid.x <= bbox.max.x + eps && centroid.y >= bbox.min.y - eps && centroid.y <= bbox.max.y + eps && centroid.z >= bbox.min.z - eps && centroid.z <= bbox.max.z + eps;
|
|
50938
|
-
if (!inBbox) centroid = null;
|
|
50891
|
+
const wasm2 = getKernelWasmSync();
|
|
50892
|
+
if (!wasm2) {
|
|
50893
|
+
throw new Error("kernel WASM is not initialized \u2014 call Engine.init first");
|
|
50939
50894
|
}
|
|
50940
|
-
if (
|
|
50941
|
-
|
|
50895
|
+
if (typeof wasm2.computeMeshProperties !== "function") {
|
|
50896
|
+
throw new Error(
|
|
50897
|
+
"computeMeshProperties is not in this kernel build \u2014 rebuild vcad-kernel-wasm"
|
|
50898
|
+
);
|
|
50942
50899
|
}
|
|
50900
|
+
const props = wasm2.computeMeshProperties(
|
|
50901
|
+
mesh.positions instanceof Float32Array ? mesh.positions : new Float32Array(mesh.positions),
|
|
50902
|
+
mesh.indices instanceof Uint32Array ? mesh.indices : new Uint32Array(mesh.indices)
|
|
50903
|
+
);
|
|
50943
50904
|
return {
|
|
50944
|
-
volume:
|
|
50945
|
-
area,
|
|
50946
|
-
bbox,
|
|
50947
|
-
centroid,
|
|
50948
|
-
triangles:
|
|
50905
|
+
volume: props.volume,
|
|
50906
|
+
area: props.area,
|
|
50907
|
+
bbox: props.bbox,
|
|
50908
|
+
centroid: props.centerOfMass,
|
|
50909
|
+
triangles: props.triangles
|
|
50949
50910
|
};
|
|
50950
50911
|
}
|
|
50951
50912
|
function computeInspection(ir, engine) {
|
|
@@ -53566,21 +53527,6 @@ var init_continue_doc = __esm({
|
|
|
53566
53527
|
});
|
|
53567
53528
|
|
|
53568
53529
|
// src/fabricate/geometry.ts
|
|
53569
|
-
function vertex(mesh, index) {
|
|
53570
|
-
const i = index * 3;
|
|
53571
|
-
return [mesh.positions[i], mesh.positions[i + 1], mesh.positions[i + 2]];
|
|
53572
|
-
}
|
|
53573
|
-
function signedTetVolume(p1, p2, p3) {
|
|
53574
|
-
return (p1[0] * (p2[1] * p3[2] - p3[1] * p2[2]) - p2[0] * (p1[1] * p3[2] - p3[1] * p1[2]) + p3[0] * (p1[1] * p2[2] - p2[1] * p1[2])) / 6;
|
|
53575
|
-
}
|
|
53576
|
-
function triArea(p1, p2, p3) {
|
|
53577
|
-
const ax = p2[0] - p1[0], ay = p2[1] - p1[1], az = p2[2] - p1[2];
|
|
53578
|
-
const bx = p3[0] - p1[0], by = p3[1] - p1[1], bz = p3[2] - p1[2];
|
|
53579
|
-
const cx = ay * bz - az * by;
|
|
53580
|
-
const cy = az * bx - ax * bz;
|
|
53581
|
-
const cz = ax * by - ay * bx;
|
|
53582
|
-
return Math.sqrt(cx * cx + cy * cy + cz * cz) / 2;
|
|
53583
|
-
}
|
|
53584
53530
|
function measureDocument(ir, engine) {
|
|
53585
53531
|
let scene;
|
|
53586
53532
|
try {
|
|
@@ -53594,21 +53540,15 @@ function measureDocument(ir, engine) {
|
|
|
53594
53540
|
const min = [Infinity, Infinity, Infinity];
|
|
53595
53541
|
const max = [-Infinity, -Infinity, -Infinity];
|
|
53596
53542
|
for (const part of scene.parts) {
|
|
53597
|
-
const
|
|
53598
|
-
|
|
53599
|
-
|
|
53600
|
-
|
|
53601
|
-
|
|
53602
|
-
|
|
53603
|
-
|
|
53604
|
-
|
|
53605
|
-
|
|
53606
|
-
for (let k = 0; k < 3; k++) {
|
|
53607
|
-
if (p[k] < min[k]) min[k] = p[k];
|
|
53608
|
-
if (p[k] > max[k]) max[k] = p[k];
|
|
53609
|
-
}
|
|
53610
|
-
}
|
|
53611
|
-
}
|
|
53543
|
+
const props = computeMeshProperties(part.mesh);
|
|
53544
|
+
volume += props.volume;
|
|
53545
|
+
area += props.area;
|
|
53546
|
+
min[0] = Math.min(min[0], props.bbox.min.x);
|
|
53547
|
+
min[1] = Math.min(min[1], props.bbox.min.y);
|
|
53548
|
+
min[2] = Math.min(min[2], props.bbox.min.z);
|
|
53549
|
+
max[0] = Math.max(max[0], props.bbox.max.x);
|
|
53550
|
+
max[1] = Math.max(max[1], props.bbox.max.y);
|
|
53551
|
+
max[2] = Math.max(max[2], props.bbox.max.z);
|
|
53612
53552
|
}
|
|
53613
53553
|
if (!Number.isFinite(min[0])) return { ...EMPTY };
|
|
53614
53554
|
const dx = max[0] - min[0];
|
|
@@ -53617,7 +53557,7 @@ function measureDocument(ir, engine) {
|
|
|
53617
53557
|
return {
|
|
53618
53558
|
ok: true,
|
|
53619
53559
|
parts: scene.parts.length,
|
|
53620
|
-
volume_mm3:
|
|
53560
|
+
volume_mm3: volume,
|
|
53621
53561
|
surface_area_mm2: area,
|
|
53622
53562
|
footprint_mm2: dx * dy,
|
|
53623
53563
|
max_dim_mm: Math.max(dx, dy, dz),
|
|
@@ -53628,6 +53568,7 @@ var EMPTY;
|
|
|
53628
53568
|
var init_geometry2 = __esm({
|
|
53629
53569
|
"src/fabricate/geometry.ts"() {
|
|
53630
53570
|
"use strict";
|
|
53571
|
+
init_inspect();
|
|
53631
53572
|
EMPTY = {
|
|
53632
53573
|
ok: false,
|
|
53633
53574
|
parts: 0,
|
|
@@ -78807,8 +78748,8 @@ var init_server3 = __esm({
|
|
|
78807
78748
|
init_order_feed();
|
|
78808
78749
|
init_animate();
|
|
78809
78750
|
PKG_VERSION = (() => {
|
|
78810
|
-
if ("0.9.4-main.
|
|
78811
|
-
return "0.9.4-main.
|
|
78751
|
+
if ("0.9.4-main.9") {
|
|
78752
|
+
return "0.9.4-main.9";
|
|
78812
78753
|
}
|
|
78813
78754
|
try {
|
|
78814
78755
|
const req = createRequire2(import.meta.url);
|
|
@@ -78817,8 +78758,8 @@ var init_server3 = __esm({
|
|
|
78817
78758
|
return "0.0.0";
|
|
78818
78759
|
}
|
|
78819
78760
|
})();
|
|
78820
|
-
BUILD_SHA = "
|
|
78821
|
-
BUILD_TIME = "2026-07-24T16:
|
|
78761
|
+
BUILD_SHA = "c3ef1dae913d41fab4da6f029c6d6b347bb08395";
|
|
78762
|
+
BUILD_TIME = "2026-07-24T16:14:27.739Z";
|
|
78822
78763
|
SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
|
|
78823
78764
|
VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
|
|
78824
78765
|
INSTANCE_ID = randomUUID6().slice(0, 8);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vcad/mcp",
|
|
3
|
-
"version": "0.9.4-main.
|
|
3
|
+
"version": "0.9.4-main.9",
|
|
4
4
|
"description": "vcad MCP server — parametric CAD + PCB design tools for AI agents (self-contained: bundled server + kernel WASM)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://vcad.io",
|
|
21
21
|
"vcadBuild": {
|
|
22
|
-
"sha": "
|
|
23
|
-
"builtAt": "2026-07-24T16:
|
|
22
|
+
"sha": "c3ef1dae913d41fab4da6f029c6d6b347bb08395",
|
|
23
|
+
"builtAt": "2026-07-24T16:14:27.739Z"
|
|
24
24
|
}
|
|
25
25
|
}
|