@vcad/mcp 0.11.0-main.148 → 0.11.0-main.150

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 +79 -6
  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 2e90f325d26818101fa84582fe411078142a182b at 2026-11-11T01:59:27.461Z. Source: https://github.com/ecto/vcad
9
+ Built from 24c8e431bb7af4f9ff0e014914bf7b00e92b5a17 at 2026-11-11T02:09:12.078Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -10330,6 +10330,13 @@ function evaluateOp(op, nodes, Solid2, cache2, depth = 0) {
10330
10330
  }
10331
10331
  case "Shell": {
10332
10332
  const child = evaluateNode(op.child, nodes, Solid2, cache2, depth + 1);
10333
+ if (op.open_faces && op.open_faces.length > 0) {
10334
+ const shellOpen = child.shellOpen;
10335
+ if (typeof shellOpen !== "function") {
10336
+ throw new Error("shell: this kernel build cannot open faces (rebuild kernel-wasm)");
10337
+ }
10338
+ return shellOpen.call(child, op.thickness, JSON.stringify(op.open_faces));
10339
+ }
10333
10340
  return child.shell(op.thickness);
10334
10341
  }
10335
10342
  case "Fillet": {
@@ -44759,6 +44766,23 @@ var init_CHANGELOG = __esm({
44759
44766
  "viewport"
44760
44767
  ]
44761
44768
  },
44769
+ {
44770
+ id: "2026-11-08-shell-open-faces",
44771
+ version: "0.11.0",
44772
+ date: "2026-11-08",
44773
+ category: "feat",
44774
+ title: "Shell with open faces",
44775
+ summary: "Shell can now remove picked faces to leave an opening, the open-top box every enclosure starts as. Works on boxes, rounded/filleted boxes and cylinders; fails closed if the wall consumes the solid.",
44776
+ features: [
44777
+ "shell",
44778
+ "kernel",
44779
+ "native",
44780
+ "enclosure"
44781
+ ],
44782
+ mcpTools: [
44783
+ "create"
44784
+ ]
44785
+ },
44762
44786
  {
44763
44787
  id: "2026-11-08-native-ux-niceties",
44764
44788
  version: "0.11.0",
@@ -44788,6 +44812,22 @@ var init_CHANGELOG = __esm({
44788
44812
  "modeling"
44789
44813
  ]
44790
44814
  },
44815
+ {
44816
+ id: "2026-11-07-router-island-terminals",
44817
+ version: "0.11.0",
44818
+ date: "2026-11-07",
44819
+ category: "fix",
44820
+ title: "Router starts from any copper joined to a pad",
44821
+ summary: "fab-prep routes island-to-island: a connection can start on fan-out stubs, vias or earlier traces already joined to its pad, so a walled-in fine-pitch pad with hand-placed fan-out now routes.",
44822
+ features: [
44823
+ "pcb",
44824
+ "fab-prep",
44825
+ "autoroute"
44826
+ ],
44827
+ mcpTools: [
44828
+ "fab_prep"
44829
+ ]
44830
+ },
44791
44831
  {
44792
44832
  id: "2026-11-07-native-liquid-glass-shell",
44793
44833
  version: "0.11.0",
@@ -44930,6 +44970,24 @@ var init_CHANGELOG = __esm({
44930
44970
  "native"
44931
44971
  ]
44932
44972
  },
44973
+ {
44974
+ id: "2026-11-07-fab-prep-fail-closed-incomplete",
44975
+ version: "0.11.0",
44976
+ date: "2026-11-07",
44977
+ category: "fix",
44978
+ title: "fab-prep fails closed on open nets; pinned, through-only routing",
44979
+ summary: "fab-prep no longer ships boards with unconnected nets (opt in with --allow-incomplete), pins traces to pad layers, emits through vias by default, and autoroute reports true open nets.",
44980
+ features: [
44981
+ "pcb",
44982
+ "fab-prep",
44983
+ "autoroute",
44984
+ "drc",
44985
+ "native-app"
44986
+ ],
44987
+ mcpTools: [
44988
+ "fab_prep"
44989
+ ]
44990
+ },
44933
44991
  {
44934
44992
  id: "2026-11-07-drawing-feature-edges",
44935
44993
  version: "undefined",
@@ -70970,9 +71028,11 @@ async function fabPrep(args) {
70970
71028
  prune_dangling: args.prune_dangling === void 0 ? true : Boolean(args.prune_dangling),
70971
71029
  max_rounds: Math.max(0, Math.round(Number(args.max_rounds ?? 8))),
70972
71030
  accept_rules: Array.isArray(args.accept_rules) ? args.accept_rules : [],
71031
+ allow_incomplete: args.allow_incomplete === true,
70973
71032
  verdict: {
70974
71033
  budget: Math.max(1, Math.round(Number(args.budget ?? 5e6))),
70975
- max_cluster: Math.max(1, Math.round(Number(args.max_cluster ?? 6)))
71034
+ max_cluster: Math.max(1, Math.round(Number(args.max_cluster ?? 6))),
71035
+ allow_blind_vias: args.allow_blind_vias === true
70976
71036
  }
70977
71037
  };
70978
71038
  const out = await runFabPrep(pcb, options);
@@ -71023,11 +71083,16 @@ async function fabPrep(args) {
71023
71083
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
71024
71084
  }
71025
71085
  function fabPrepHeadline(report) {
71086
+ const open2 = report.connectivity.open_nets?.length ?? 0;
71026
71087
  if (!report.converged) {
71088
+ if (report.delta.route_attributable_fixable === 0 && open2 > 0) {
71089
+ return `NOT FAB-READY \u2014 board not fully routed, ${open2} net(s) open (${report.blocker ?? "connectivity incomplete"})`;
71090
+ }
71027
71091
  return `NOT FAB-READY \u2014 ${report.delta.route_attributable_fixable} route-attributable violation(s) remain (${report.blocker ?? "loop did not converge"})`;
71028
71092
  }
71093
+ const incomplete = report.shipped_incomplete ? ` \u2014 NOT FULLY ROUTED: ${open2} net(s) open (shipped under allow_incomplete)` : "";
71029
71094
  const waived = report.delta.route_attributable_accepted > 0 ? `, ${report.delta.route_attributable_accepted} waived under ${report.accepted_rules.join("+")}` : "";
71030
- return `zero route-attributable violations${waived} \u2014 ${report.delta.final_total} on the finished board, ${report.delta.baseline_total} on the same board stripped of all routing`;
71095
+ return `zero route-attributable violations${waived} \u2014 ${report.delta.final_total} on the finished board, ${report.delta.baseline_total} on the same board stripped of all routing${incomplete}`;
71031
71096
  }
71032
71097
  async function validateForFab(args) {
71033
71098
  const ctx = resolveDocInput(args);
@@ -76958,6 +77023,14 @@ var init_ecad2 = __esm({
76958
77023
  items: { type: "string" },
76959
77024
  description: 'DRC rule names whose route-attributable violations are ACCEPTED rather than fixed (e.g. ["MinTraceWidth"]). Real fab packages ship with real, named exceptions; the difference between that and a footgun is whether the exception is written down. Waived violations are still counted, still listed, and the waiver is named in the receipt \u2014 it stops blocking the verdict, it does not hide anything. An unrecognised rule name refuses the run rather than silently accepting nothing.'
76960
77025
  },
77026
+ allow_incomplete: {
77027
+ type: "boolean",
77028
+ description: "Let a geometrically clean board that still has OPEN nets (unconnected, islanded, or an SMD pad unstitched from its plane) converge (default FALSE \u2014 such a run fails closed). The opt-in is logged in the receipt and FAB_NOTES says NOT FULLY ROUTED."
77029
+ },
77030
+ allow_blind_vias: {
77031
+ type: "boolean",
77032
+ description: "Let the router emit blind/buried (layer-pair) vias (default FALSE \u2014 through vias only, as standard 2/4-layer processes require). A board that already carries blind/buried/micro vias keeps that process."
77033
+ },
76961
77034
  dry_run: {
76962
77035
  type: "boolean",
76963
77036
  description: "Compute the receipt without writing the fixed board back to the session."
@@ -90592,8 +90665,8 @@ var init_server3 = __esm({
90592
90665
  init_order_feed();
90593
90666
  init_animate();
90594
90667
  PKG_VERSION = (() => {
90595
- if ("0.11.0-main.148") {
90596
- return "0.11.0-main.148";
90668
+ if ("0.11.0-main.150") {
90669
+ return "0.11.0-main.150";
90597
90670
  }
90598
90671
  try {
90599
90672
  const req = createRequire2(import.meta.url);
@@ -90602,8 +90675,8 @@ var init_server3 = __esm({
90602
90675
  return "0.0.0";
90603
90676
  }
90604
90677
  })();
90605
- BUILD_SHA = "2e90f325d26818101fa84582fe411078142a182b";
90606
- BUILD_TIME = "2026-11-11T01:59:27.461Z";
90678
+ BUILD_SHA = "24c8e431bb7af4f9ff0e014914bf7b00e92b5a17";
90679
+ BUILD_TIME = "2026-11-11T02:09:12.078Z";
90607
90680
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
90608
90681
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
90609
90682
  INSTANCE_ID = randomUUID7().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.11.0-main.148",
3
+ "version": "0.11.0-main.150",
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": "2e90f325d26818101fa84582fe411078142a182b",
23
- "builtAt": "2026-11-11T01:59:27.461Z"
22
+ "sha": "24c8e431bb7af4f9ff0e014914bf7b00e92b5a17",
23
+ "builtAt": "2026-11-11T02:09:12.078Z"
24
24
  }
25
25
  }