@vcad/mcp 0.10.0-main.112 → 0.10.0-main.113

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 +174 -7
  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 cdbfe885b0a0ed7b3492e33d7b2f4a1da4f3bd6c at 2026-10-20T22:45:38.715Z. Source: https://github.com/ecto/vcad
9
+ Built from 6fe98c8bcad683e78ce3185512bd51fbfc36aa73 at 2026-10-20T22:54:39.478Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -42019,6 +42019,21 @@ var init_CHANGELOG = __esm({
42019
42019
  "get_footprint"
42020
42020
  ]
42021
42021
  },
42022
+ {
42023
+ id: "2026-10-20-update-params-apply",
42024
+ version: "0.10.0",
42025
+ date: "2026-10-20",
42026
+ category: "fix",
42027
+ title: "AI updates to part dimensions actually apply",
42028
+ summary: "An update like resizing a cube via size {x,y,z} reported success but changed nothing; nested params now map onto the part's real fields, and unknown params are refused.",
42029
+ features: [
42030
+ "engine",
42031
+ "ai"
42032
+ ],
42033
+ mcpTools: [
42034
+ "update"
42035
+ ]
42036
+ },
42022
42037
  {
42023
42038
  id: "2026-10-20-schematic-power-flags",
42024
42039
  version: "0.10.0",
@@ -42152,6 +42167,19 @@ var init_CHANGELOG = __esm({
42152
42167
  "find_alternatives"
42153
42168
  ]
42154
42169
  },
42170
+ {
42171
+ id: "2026-10-20-import-keeps-materials",
42172
+ version: "0.10.0",
42173
+ date: "2026-10-20",
42174
+ category: "fix",
42175
+ title: "Imported parts keep their material and visibility",
42176
+ summary: "Opening a document through the engine reset every part's material to default and showed hidden parts; both now survive import and every later edit.",
42177
+ features: [
42178
+ "engine",
42179
+ "import",
42180
+ "materials"
42181
+ ]
42182
+ },
42155
42183
  {
42156
42184
  id: "2026-10-20-hierarchical-schematic-sheets",
42157
42185
  version: "0.10.0",
@@ -55719,8 +55747,123 @@ function dispatchRegistryTool(toolName, args, engine) {
55719
55747
  }
55720
55748
  return result;
55721
55749
  }
55722
- function runMutation(toolName, rawArgs, doc, documentId) {
55750
+ function toStableId(doc, v) {
55751
+ if (typeof v !== "string" && typeof v !== "number") return v;
55752
+ return rootForPartId(doc, v)?.partId ?? String(v);
55753
+ }
55754
+ function owningRootIndex(doc, nodeId) {
55755
+ const exact = doc.roots.findIndex((r) => String(r.root) === nodeId);
55756
+ if (exact >= 0) return exact;
55757
+ return doc.roots.findIndex((r) => {
55758
+ const stack = [r.root];
55759
+ const seen = /* @__PURE__ */ new Set();
55760
+ while (stack.length) {
55761
+ const id = String(stack.pop());
55762
+ if (id === nodeId) return true;
55763
+ if (seen.has(id)) continue;
55764
+ seen.add(id);
55765
+ const op = doc.nodes[id]?.op;
55766
+ if (!op) continue;
55767
+ for (const k of ["child", "left", "right"]) if (op[k] !== void 0) stack.push(op[k]);
55768
+ if (Array.isArray(op.children)) stack.push(...op.children);
55769
+ }
55770
+ return false;
55771
+ });
55772
+ }
55773
+ function nodeRefToStableId(doc, v) {
55774
+ if (typeof v === "number" || typeof v === "string" && /^\d+$/.test(v)) {
55775
+ const idx = owningRootIndex(doc, String(v));
55776
+ if (idx >= 0) return partIdForRoot(doc, idx);
55777
+ }
55778
+ return toStableId(doc, v);
55779
+ }
55780
+ function engineArgs(toolName, args, doc) {
55781
+ const out = toolName === "create" ? applyParamDefaults({ ...args }) : { ...args };
55782
+ if ("part_id" in out) out.part_id = toStableId(doc, out.part_id);
55783
+ if (Array.isArray(out.part_ids)) out.part_ids = out.part_ids.map((v) => toStableId(doc, v));
55784
+ if (out.parent_part_id !== void 0) out.parent_part_id = nodeRefToStableId(doc, out.parent_part_id);
55785
+ if (toolName === "update" && out.node_id !== void 0) {
55786
+ out.node_id = nodeRefToStableId(doc, out.node_id);
55787
+ }
55788
+ if (toolName === "create" && out.params && typeof out.params === "object") {
55789
+ const params = { ...out.params };
55790
+ for (const key3 of ["left", "right", "child"]) {
55791
+ if (key3 in params) params[key3] = nodeRefToStableId(doc, params[key3]);
55792
+ }
55793
+ out.params = params;
55794
+ }
55795
+ return out;
55796
+ }
55797
+ function engineErrorMessage(toolName, args, err9) {
55798
+ switch (err9.kind) {
55799
+ case "unknown_id":
55800
+ return `${toolName}: no part with id "${err9.id ?? "?"}"`;
55801
+ case "invalid":
55802
+ return enrichPlannerError(toolName, args, `${toolName}: ${err9.message ?? "invalid arguments"}`);
55803
+ default:
55804
+ return `${toolName}: ${err9.message ?? err9.kind}`;
55805
+ }
55806
+ }
55807
+ function runMutationViaEngine(toolName, toolArgs, doc, documentId) {
55808
+ if (!ENGINE_LOWERED_TOOLS.has(toolName)) return null;
55809
+ if (process.env.VCAD_MCP_ENGINE_APPLY === "0") return null;
55810
+ const wasm3 = getKernelWasmSync();
55811
+ const factory = wasm3?.WasmDocumentEngine;
55812
+ if (!factory || typeof factory.withReplica !== "function") return null;
55813
+ const engine = factory.withReplica(0);
55814
+ try {
55815
+ if (typeof engine.apply_tool !== "function") return null;
55816
+ const deprecation = typeof toolArgs.part_id === "string" ? partIdDeprecation(toolArgs.part_id, rootForPartId(doc, toolArgs.part_id)) : void 0;
55817
+ const args = engineArgs(toolName, toolArgs, doc);
55818
+ engine.import_ir(JSON.stringify(doc));
55819
+ const envelope = JSON.parse(engine.apply_tool(toolName, JSON.stringify(args)));
55820
+ if (!envelope.ok || !envelope.result) {
55821
+ const err9 = envelope.error ?? { kind: "invalid", message: "engine returned no result" };
55822
+ if (err9.kind === "unsupported") return null;
55823
+ throw new Error(engineErrorMessage(toolName, args, err9));
55824
+ }
55825
+ const next = envelope.result.document;
55826
+ const parts = envelope.result.parts ?? [];
55827
+ for (const p of parts) {
55828
+ if (!p.name) continue;
55829
+ const rootIdx = next.roots.findIndex((_, i) => next.partIds?.[String(next.roots[i].root)] === p.id);
55830
+ const rootNode = rootIdx >= 0 ? next.nodes[String(next.roots[rootIdx].root)] : void 0;
55831
+ if (rootNode && !rootNode.name) rootNode.name = p.name;
55832
+ }
55833
+ for (const k of Object.keys(doc)) delete doc[k];
55834
+ Object.assign(doc, next);
55835
+ const warnings = [...envelope.result.warnings ?? [], ...deprecation ? [deprecation] : []];
55836
+ const payload = { document_id: documentId };
55837
+ if (toolName === "delete") {
55838
+ payload.removed = args.part_id;
55839
+ } else if (toolName === "set_material") {
55840
+ payload.part_id = args.part_id ?? args.part_ids;
55841
+ payload.material = toolArgs.material;
55842
+ } else {
55843
+ const partId = envelope.result.createdFeatureId ?? (typeof args.part_id === "string" ? args.part_id : void 0);
55844
+ if (partId) {
55845
+ payload.part_id = partId;
55846
+ const part = parts.find((p) => p.id === partId);
55847
+ const root = rootForPartId(doc, partId);
55848
+ const nodeId = part?.primitiveNodeId ?? root?.entry.root;
55849
+ if (nodeId !== void 0) payload.node_id = nodeId;
55850
+ }
55851
+ }
55852
+ if (envelope.result.consumedPartIds?.length) {
55853
+ payload.consumed_part_ids = envelope.result.consumedPartIds;
55854
+ }
55855
+ if (warnings.length) payload.warnings = warnings;
55856
+ return { content: [{ type: "text", text: JSON.stringify(payload) }] };
55857
+ } finally {
55858
+ engine.free?.();
55859
+ }
55860
+ }
55861
+ function runMutation(toolName, rawArgs, doc, documentId, opts = {}) {
55723
55862
  const toolArgs = normalizeNodeRefs(toolName, rawArgs, doc);
55863
+ if (opts.engine !== false) {
55864
+ const viaEngine = runMutationViaEngine(toolName, toolArgs, doc, documentId);
55865
+ if (viaEngine) return viaEngine;
55866
+ }
55724
55867
  if (toolName === "delete") {
55725
55868
  const partId = String(toolArgs.part_id ?? "");
55726
55869
  if (!partId) throw new Error("delete: missing `part_id`");
@@ -55905,13 +56048,14 @@ function childrenOf(op) {
55905
56048
  return [];
55906
56049
  }
55907
56050
  }
55908
- var BROWSER_ONLY_TOOLS, DEFERRED_TOOLS, READ_ONLY_REGISTRY_TOOLS, MCP_DESCRIPTIONS, CREATE_PARAM_DEFAULTS, CREATE_PARAM_HINTS, NODE_REF_PARAM_KEYS;
56051
+ var BROWSER_ONLY_TOOLS, DEFERRED_TOOLS, READ_ONLY_REGISTRY_TOOLS, MCP_DESCRIPTIONS, CREATE_PARAM_DEFAULTS, CREATE_PARAM_HINTS, NODE_REF_PARAM_KEYS, ENGINE_LOWERED_TOOLS;
55909
56052
  var init_registry_dispatch = __esm({
55910
56053
  "src/tools/registry-dispatch.ts"() {
55911
56054
  "use strict";
55912
56055
  init_dist3();
55913
56056
  init_session2();
55914
56057
  init_part_ids2();
56058
+ init_dist();
55915
56059
  init_pose();
55916
56060
  init_integrity();
55917
56061
  init_measure();
@@ -55967,6 +56111,26 @@ var init_registry_dispatch = __esm({
55967
56111
  edge_blend: '{child: nodeId, edges: {type: "All"} | {type: "Near", point: {x,y,z}} | {type: "Direction", axis: {x,y,z}, tol_deg}, profile: {type: "Constant", size, shape} | {type: "Keyed", keys: [{t, size, shape}]}} \u2014 shape 0 = chamfer, 1 = fillet; size in mm'
55968
56112
  };
55969
56113
  NODE_REF_PARAM_KEYS = ["child", "left", "right", "sketch"];
56114
+ ENGINE_LOWERED_TOOLS = /* @__PURE__ */ new Set([
56115
+ "create",
56116
+ "update",
56117
+ "delete",
56118
+ "set_material",
56119
+ "linear_pattern",
56120
+ "circular_pattern",
56121
+ "mirror",
56122
+ "translate",
56123
+ "rotate",
56124
+ "scale",
56125
+ "union",
56126
+ "difference",
56127
+ "intersection",
56128
+ "fillet",
56129
+ "chamfer",
56130
+ "shell",
56131
+ "tube",
56132
+ "polyline_tube"
56133
+ ]);
55970
56134
  }
55971
56135
  });
55972
56136
 
@@ -58041,7 +58205,10 @@ function applyOps(doc, ops, documentId) {
58041
58205
  name,
58042
58206
  resolveSymbolicRefs(args, createdIds, i, doc),
58043
58207
  doc,
58044
- documentId
58208
+ documentId,
58209
+ // Legacy planner: "@N" and raw numeric child refs address the
58210
+ // planner's node numbering (see runMutation).
58211
+ { engine: false }
58045
58212
  );
58046
58213
  } catch (err9) {
58047
58214
  throw new BatchOpError(i, name, err9);
@@ -87229,8 +87396,8 @@ var init_server3 = __esm({
87229
87396
  init_order_feed();
87230
87397
  init_animate();
87231
87398
  PKG_VERSION = (() => {
87232
- if ("0.10.0-main.112") {
87233
- return "0.10.0-main.112";
87399
+ if ("0.10.0-main.113") {
87400
+ return "0.10.0-main.113";
87234
87401
  }
87235
87402
  try {
87236
87403
  const req = createRequire2(import.meta.url);
@@ -87239,8 +87406,8 @@ var init_server3 = __esm({
87239
87406
  return "0.0.0";
87240
87407
  }
87241
87408
  })();
87242
- BUILD_SHA = "cdbfe885b0a0ed7b3492e33d7b2f4a1da4f3bd6c";
87243
- BUILD_TIME = "2026-10-20T22:45:38.715Z";
87409
+ BUILD_SHA = "6fe98c8bcad683e78ce3185512bd51fbfc36aa73";
87410
+ BUILD_TIME = "2026-10-20T22:54:39.478Z";
87244
87411
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
87245
87412
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
87246
87413
  INSTANCE_ID = randomUUID7().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.10.0-main.112",
3
+ "version": "0.10.0-main.113",
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": "cdbfe885b0a0ed7b3492e33d7b2f4a1da4f3bd6c",
23
- "builtAt": "2026-10-20T22:45:38.715Z"
22
+ "sha": "6fe98c8bcad683e78ce3185512bd51fbfc36aa73",
23
+ "builtAt": "2026-10-20T22:54:39.478Z"
24
24
  }
25
25
  }