@vcad/mcp 0.9.4-main.81 → 0.9.4-main.83

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
@@ -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 ede17d7f4397ed76cac2bf72e4d7576e42d754bc at 2026-09-01T14:57:36.685Z. Source: https://github.com/ecto/vcad
9
+ Built from e80c65b95cd396d4e1b0b3706df18d6376aa3a72 at 2026-09-06T15:00:24.263Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -10366,8 +10366,12 @@ async function bindings() {
10366
10366
  async function runDfm(doc, opts) {
10367
10367
  const wasm3 = await getKernelWasm();
10368
10368
  const scene = evaluateDocumentTS(doc, wasm3);
10369
- const pack = opts.rulePack ?? "";
10369
+ let pack = opts.rulePack ?? "";
10370
+ if (!pack && opts.ruleset) {
10371
+ pack = wasm3.get_default_dfm_pack(opts.ruleset);
10372
+ }
10370
10373
  const allIssues = [];
10374
+ const ruleResults = [];
10371
10375
  let packName = "";
10372
10376
  let packVersion = "1";
10373
10377
  const visibleRoots = doc.roots.filter((entry) => entry.visible !== false);
@@ -10386,13 +10390,16 @@ async function runDfm(doc, opts) {
10386
10390
  packName = packName || report.rule_pack_name;
10387
10391
  packVersion = report.rule_pack_version || packVersion;
10388
10392
  allIssues.push(...report.issues);
10393
+ if (report.rule_results)
10394
+ ruleResults.push(...report.rule_results);
10389
10395
  }
10390
10396
  return {
10391
10397
  process: opts.process,
10392
10398
  rule_pack_name: packName,
10393
10399
  rule_pack_version: packVersion,
10394
10400
  issues: allIssues,
10395
- cost_estimate: null
10401
+ cost_estimate: null,
10402
+ rule_results: ruleResults
10396
10403
  };
10397
10404
  }
10398
10405
  async function getDefaultDfmPack(process3) {
@@ -41634,6 +41641,23 @@ var init_CHANGELOG = __esm({
41634
41641
  CHANGELOG_default = {
41635
41642
  $schema: "./changelog.schema.json",
41636
41643
  entries: [
41644
+ {
41645
+ id: "2026-09-06-dfm-hobby-3axis-mill",
41646
+ version: "0.9.4",
41647
+ date: "2026-09-06",
41648
+ category: "feat",
41649
+ title: "dfm: hobby 3-axis mill ruleset, pass/fail per rule with affordances",
41650
+ summary: "A named DFM ruleset for a small bench mill \u2014 seven rules (corner radius, \xB1Z reachability, reamer/tap bores, plate stock, min wall, envelope, threads/gear teeth) judged on the exported mesh, each reported pass/fail with located examples and a suggested fix.",
41651
+ details: "lib/dfm/hobby-3axis-mill.toml (ruleset = hobby_3axis_mill, process cnc_3axis) parameterises a 2 mm minimum end mill, a 3/4/5/6 reamer set, metric tap drills, plate stock thicknesses, \xB10.05 tolerance and a 300x200x80 envelope. Unlike the per-process packs it runs in the mesh domain: BReps are tessellated, STLs are taken as-is, and loose-union exports (every additive body its own shell) are unioned first \u2014 buried faces dropped, section loops unioned in 2D with T-junction splitting, slits under 0.05 mm bridged, zero-width profile spikes collapsed. R1 fits radii to concave arcs in horizontal sections; R2 casts \xB1Z rays through an XY grid and separates 'flip the part' from true undercuts; R3 fits circles to internal loops and names the nearest reamer / tap drill ('bore \xD83.80 \u2192 ream \xD84 H7'); R7 finds helices by the section centroid orbiting the axis and gear teeth by the dominant angular harmonic. `vcad dfm <stl> --ruleset hobby-3axis-mill`, dfm_check's new `ruleset` argument, and get_default_dfm_pack all select it by name; DfmReport gains rule_results.",
41652
+ features: [
41653
+ "dfm",
41654
+ "cli",
41655
+ "mcp"
41656
+ ],
41657
+ mcpTools: [
41658
+ "dfm_check"
41659
+ ]
41660
+ },
41637
41661
  {
41638
41662
  id: "2026-09-01-solid-query-probe-suites",
41639
41663
  version: "0.9.4",
@@ -76749,6 +76773,7 @@ async function dfmCheck(input, _engine) {
76749
76773
  const documentId = resolvedId ?? "";
76750
76774
  const process3 = String(args.process ?? "fdm");
76751
76775
  const rulePack = typeof args.rule_pack_toml === "string" ? args.rule_pack_toml : void 0;
76776
+ const ruleset = typeof args.ruleset === "string" && args.ruleset ? args.ruleset : void 0;
76752
76777
  const profile = pcbProfileFor(process3);
76753
76778
  if (profile) {
76754
76779
  const pcb = getDocPcb3(doc);
@@ -76793,7 +76818,7 @@ async function dfmCheck(input, _engine) {
76793
76818
  ]
76794
76819
  };
76795
76820
  }
76796
- const report = await runDfm(doc, { process: process3, rulePack });
76821
+ const report = await runDfm(doc, { process: process3, rulePack, ruleset });
76797
76822
  if (documentId) lastReports.set(documentId, report);
76798
76823
  return {
76799
76824
  content: [
@@ -76803,6 +76828,7 @@ async function dfmCheck(input, _engine) {
76803
76828
  {
76804
76829
  ...report,
76805
76830
  issue_count: report.issues.length,
76831
+ failed_rules: (report.rule_results ?? []).filter((r) => !r.passed).map((r) => r.rule),
76806
76832
  score: dfmScore(
76807
76833
  report.issues.filter((i) => i.severity === "error").length,
76808
76834
  report.issues.filter((i) => i.severity === "warning").length
@@ -76950,7 +76976,7 @@ function applySetParam(doc, node, path, value) {
76950
76976
  }
76951
76977
  cursor[parts[parts.length - 1]] = value;
76952
76978
  }
76953
- var lastReports, mechanicalProcessEnum, pcbProcessEnum, processEnum, dfmCheckSchema, dfmExplainSchema, dfmSuggestFixSchema, dfmApplyFixSchema, toolDefs40;
76979
+ var lastReports, mechanicalProcessEnum, pcbProcessEnum, processEnum, rulesetEnum, dfmCheckSchema, dfmExplainSchema, dfmSuggestFixSchema, dfmApplyFixSchema, toolDefs40;
76954
76980
  var init_dfm2 = __esm({
76955
76981
  "src/tools/dfm.ts"() {
76956
76982
  "use strict";
@@ -76975,6 +77001,7 @@ var init_dfm2 = __esm({
76975
77001
  "pcb_generic_4layer"
76976
77002
  ];
76977
77003
  processEnum = [...mechanicalProcessEnum, ...pcbProcessEnum];
77004
+ rulesetEnum = ["hobby-3axis-mill"];
76978
77005
  dfmCheckSchema = {
76979
77006
  type: "object",
76980
77007
  properties: {
@@ -76991,6 +77018,11 @@ var init_dfm2 = __esm({
76991
77018
  enum: [...processEnum],
76992
77019
  description: "Manufacturing process (mechanical part) or PCB fab profile (board) to evaluate against. Mechanical: cnc_3axis, fdm, sla, injection, sheet_metal, casting_sand, casting_investment. PCB fab profiles: pcb_jlcpcb, pcb_pcbway, pcb_generic_2layer, pcb_generic_4layer \u2014 these run when the document is a PCB and check the board against that fab's published process capability (min annular ring, drill, trace/space by copper weight, copper-to-edge, soldermask dam/sliver, silk-over-pad, acid traps, via-in-pad). Each pack is bundled at lib/dfm/<process>.toml."
76993
77020
  },
77021
+ ruleset: {
77022
+ type: "string",
77023
+ enum: [...rulesetEnum],
77024
+ description: "Optional named ruleset layered on the process, selected by name. hobby-3axis-mill (process cnc_3axis): a bench mill with a 2 mm minimum end mill, 3/4/5/6 reamers, metric tap drills, plate stock and a 300x200x80 envelope \u2014 reports pass/fail per rule (R1 internal corner radius, R2 \xB1Z reachability, R3 hole diameters, R4 plate stock, R5 min wall, R6 envelope, R7 threads/gear teeth) with located examples and affordances. Bundled at lib/dfm/<ruleset>.toml; ignored when rule_pack_toml is given."
77025
+ },
76994
77026
  rule_pack_toml: {
76995
77027
  type: "string",
76996
77028
  description: "Optional TOML rule pack to override the bundled default. Same schema as lib/dfm/<process>.toml."
@@ -84380,8 +84412,8 @@ var init_server3 = __esm({
84380
84412
  init_order_feed();
84381
84413
  init_animate();
84382
84414
  PKG_VERSION = (() => {
84383
- if ("0.9.4-main.81") {
84384
- return "0.9.4-main.81";
84415
+ if ("0.9.4-main.83") {
84416
+ return "0.9.4-main.83";
84385
84417
  }
84386
84418
  try {
84387
84419
  const req = createRequire2(import.meta.url);
@@ -84390,8 +84422,8 @@ var init_server3 = __esm({
84390
84422
  return "0.0.0";
84391
84423
  }
84392
84424
  })();
84393
- BUILD_SHA = "ede17d7f4397ed76cac2bf72e4d7576e42d754bc";
84394
- BUILD_TIME = "2026-09-01T14:57:36.685Z";
84425
+ BUILD_SHA = "e80c65b95cd396d4e1b0b3706df18d6376aa3a72";
84426
+ BUILD_TIME = "2026-09-06T15:00:24.263Z";
84395
84427
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
84396
84428
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
84397
84429
  INSTANCE_ID = randomUUID7().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.9.4-main.81",
3
+ "version": "0.9.4-main.83",
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": "ede17d7f4397ed76cac2bf72e4d7576e42d754bc",
23
- "builtAt": "2026-09-01T14:57:36.685Z"
22
+ "sha": "e80c65b95cd396d4e1b0b3706df18d6376aa3a72",
23
+ "builtAt": "2026-09-06T15:00:24.263Z"
24
24
  }
25
25
  }
Binary file