@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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/index.mjs +49 -108
  3. 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 f09f3d656a04f8a18840c42116208ada180ce487 at 2026-07-24T16:11:19.940Z. Source: https://github.com/ecto/vcad
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 numTriangles = mesh.indices.length / 3;
50893
- let volume = 0;
50894
- let area = 0;
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 (centroid === null) {
50941
- centroid = area > 0 ? { x: acx / area, y: acy / area, z: acz / area } : { x: 0, y: 0, z: 0 };
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: absVolume,
50945
- area,
50946
- bbox,
50947
- centroid,
50948
- triangles: numTriangles
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 mesh = part.mesh;
53598
- const numTris = mesh.indices.length / 3;
53599
- for (let t2 = 0; t2 < numTris; t2++) {
53600
- const p1 = vertex(mesh, mesh.indices[t2 * 3]);
53601
- const p2 = vertex(mesh, mesh.indices[t2 * 3 + 1]);
53602
- const p3 = vertex(mesh, mesh.indices[t2 * 3 + 2]);
53603
- volume += signedTetVolume(p1, p2, p3);
53604
- area += triArea(p1, p2, p3);
53605
- for (const p of [p1, p2, p3]) {
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: Math.abs(volume),
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.8") {
78811
- return "0.9.4-main.8";
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 = "f09f3d656a04f8a18840c42116208ada180ce487";
78821
- BUILD_TIME = "2026-07-24T16:11:19.940Z";
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.8",
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": "f09f3d656a04f8a18840c42116208ada180ce487",
23
- "builtAt": "2026-07-24T16:11:19.940Z"
22
+ "sha": "c3ef1dae913d41fab4da6f029c6d6b347bb08395",
23
+ "builtAt": "2026-07-24T16:14:27.739Z"
24
24
  }
25
25
  }