@vcad/mcp 0.10.0-main.127 → 0.10.0-main.129

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 +132 -184
  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 29cbe4343d120465c4b5eda7f7ccfc72d65a2171 at 2026-10-21T14:37:18.317Z. Source: https://github.com/ecto/vcad
9
+ Built from c0f41c513a664c5cad95f6b53a04977718e67e65 at 2026-10-21T15:14:39.035Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -10798,6 +10798,75 @@ var init_diff = __esm({
10798
10798
  }
10799
10799
  });
10800
10800
 
10801
+ // ../engine/dist/delta.js
10802
+ function stateFromEnvelope(json) {
10803
+ const env = typeof json === "string" ? JSON.parse(json) : json;
10804
+ if (!env.ok || !env.result)
10805
+ throw new EngineRefusal(env.error);
10806
+ return { document: env.result.document, parts: env.result.parts };
10807
+ }
10808
+ function parseDeltaEnvelope(json) {
10809
+ const env = typeof json === "string" ? JSON.parse(json) : json;
10810
+ if (!env.ok || !env.result)
10811
+ throw new EngineRefusal(env.error);
10812
+ return env.result;
10813
+ }
10814
+ function applyDocumentDelta(doc, delta) {
10815
+ const out = { ...doc };
10816
+ for (const key3 of delta.removedFields)
10817
+ delete out[key3];
10818
+ for (const [key3, value] of Object.entries(delta.fields))
10819
+ out[key3] = value;
10820
+ for (const [key3, patch] of Object.entries(delta.maps)) {
10821
+ const prev = out[key3];
10822
+ const map = prev && typeof prev === "object" && !Array.isArray(prev) ? { ...prev } : {};
10823
+ for (const k of patch.remove)
10824
+ delete map[k];
10825
+ for (const [k, v] of Object.entries(patch.set))
10826
+ map[k] = v;
10827
+ out[key3] = map;
10828
+ }
10829
+ return out;
10830
+ }
10831
+ function applyPartsDelta(parts, delta) {
10832
+ const order = delta.order ?? parts.map((p) => p.id);
10833
+ const byId = new Map(parts.map((p) => [p.id, p]));
10834
+ for (const p of [...delta.added, ...delta.updated])
10835
+ byId.set(p.id, p);
10836
+ for (const id of delta.removed)
10837
+ byId.delete(id);
10838
+ return order.flatMap((id) => {
10839
+ const p = byId.get(id);
10840
+ return p ? [p] : [];
10841
+ });
10842
+ }
10843
+ function applyEngineDelta(state, delta) {
10844
+ return {
10845
+ state: {
10846
+ document: applyDocumentDelta(state.document, delta.document),
10847
+ parts: applyPartsDelta(state.parts, delta.parts)
10848
+ },
10849
+ changes: {
10850
+ rebuild: [...delta.parts.added, ...delta.parts.updated].map((p) => p.id),
10851
+ removed: [...delta.parts.removed]
10852
+ }
10853
+ };
10854
+ }
10855
+ var EngineRefusal;
10856
+ var init_delta = __esm({
10857
+ "../engine/dist/delta.js"() {
10858
+ "use strict";
10859
+ EngineRefusal = class extends Error {
10860
+ error;
10861
+ constructor(error2) {
10862
+ super(error2.message);
10863
+ this.error = error2;
10864
+ this.name = "EngineRefusal";
10865
+ }
10866
+ };
10867
+ }
10868
+ });
10869
+
10801
10870
  // ../engine/dist/sequence.js
10802
10871
  function requireWasm2() {
10803
10872
  const mod = getKernelWasmSync();
@@ -11955,6 +12024,7 @@ __export(dist_exports, {
11955
12024
  DEFAULT_SHOP_PROFILE: () => DEFAULT_SHOP_PROFILE,
11956
12025
  DependencyGraph: () => DependencyGraph,
11957
12026
  Engine: () => Engine,
12027
+ EngineRefusal: () => EngineRefusal,
11958
12028
  ExpressionEvalError: () => EvalError,
11959
12029
  ExpressionParseError: () => ParseError,
11960
12030
  MdEnv: () => MdEnv,
@@ -11963,7 +12033,10 @@ __export(dist_exports, {
11963
12033
  SolidCache: () => SolidCache,
11964
12034
  airgapFluxDensity: () => airgapFluxDensity,
11965
12035
  airgapSolve: () => airgapSolve,
12036
+ applyDocumentDelta: () => applyDocumentDelta,
12037
+ applyEngineDelta: () => applyEngineDelta,
11966
12038
  applyForwardKinematics: () => applyForwardKinematics,
12039
+ applyPartsDelta: () => applyPartsDelta,
11967
12040
  buildMoleculeReceipt: () => buildReceipt2,
11968
12041
  buildPartDocument: () => buildPartDocument,
11969
12042
  buildReceipt: () => buildReceipt,
@@ -12033,6 +12106,7 @@ __export(dist_exports, {
12033
12106
  parseAltiumPcbDoc: () => parseAltiumPcbDoc2,
12034
12107
  parseAltiumPcbLib: () => parseAltiumPcbLib2,
12035
12108
  parseBindingKey: () => parseBindingKey,
12109
+ parseDeltaEnvelope: () => parseDeltaEnvelope,
12036
12110
  parseEagleBrd: () => parseEagleBrd2,
12037
12111
  parseExpression: () => parse,
12038
12112
  parseKicadPcb: () => parseKicadPcb2,
@@ -12066,6 +12140,7 @@ __export(dist_exports, {
12066
12140
  semanticDiff: () => semanticDiff,
12067
12141
  solveDesignConstraints: () => solveDesignConstraints2,
12068
12142
  solveForwardKinematics: () => solveForwardKinematics2,
12143
+ stateFromEnvelope: () => stateFromEnvelope,
12069
12144
  threeWayMerge: () => threeWayMerge,
12070
12145
  toWorld: () => toWorld,
12071
12146
  transformMesh: () => transformMesh,
@@ -12092,6 +12167,7 @@ var init_dist = __esm({
12092
12167
  init_gpu();
12093
12168
  init_diff();
12094
12169
  init_solid_cache();
12170
+ init_delta();
12095
12171
  init_mesh_cache();
12096
12172
  init_dependency_graph();
12097
12173
  init_evaluate();
@@ -12228,6 +12304,7 @@ var init_dist = __esm({
12228
12304
  importUrdfBuffer: wasmModule7.importUrdfBuffer,
12229
12305
  importUrdfBufferWithOptions: wasmModule7.importUrdfBufferWithOptions,
12230
12306
  urdfCommentedFloatingJoint: wasmModule7.urdfCommentedFloatingJoint,
12307
+ buildSheetMetalDocument: wasmModule7.buildSheetMetalDocument,
12231
12308
  inlineMeshImports: wasmModule7.inlineMeshImports,
12232
12309
  exportProjectedViewToDxf: wasmModule7.exportProjectedViewToDxf,
12233
12310
  offsetSectionMesh: wasmModule7.offsetSectionMesh,
@@ -12891,6 +12968,17 @@ var init_dist = __esm({
12891
12968
  * a commented-out floating joint means the author expected the simulator
12892
12969
  * to supply the free base.
12893
12970
  */
12971
+ /**
12972
+ * Build a sheet-metal document (base flange + ordered flanges, hems, jogs,
12973
+ * bend relief) from a `sheet_metal_create` request, in the kernel
12974
+ * (`vcad_eval::sheet_build`). Throws on malformed input.
12975
+ */
12976
+ buildSheetMetalDocument(args) {
12977
+ if (typeof this.kernel.buildSheetMetalDocument !== "function") {
12978
+ throw new Error("sheet-metal document builder not available - rebuild the kernel WASM");
12979
+ }
12980
+ return JSON.parse(this.kernel.buildSheetMetalDocument(JSON.stringify(args)));
12981
+ }
12894
12982
  /**
12895
12983
  * Inline STL meshes into `doc` in place: each `MeshImport` node keyed in
12896
12984
  * `meshes` (node id -> STL bytes) becomes an `ImportedMesh` (metres -> mm,
@@ -41395,6 +41483,19 @@ var init_CHANGELOG = __esm({
41395
41483
  "render"
41396
41484
  ]
41397
41485
  },
41486
+ {
41487
+ id: "2026-10-21-photoreal-focus-dist",
41488
+ version: "0.10.0",
41489
+ date: "2026-10-21",
41490
+ category: "feat",
41491
+ title: "Depth of field controls for photoreal renders",
41492
+ summary: "--focus-dist sets the thin-lens plane of focus in vcad-render; vcad render --photoreal gains --aperture, --focus-dist and --focus-part.",
41493
+ features: [
41494
+ "photoreal",
41495
+ "render",
41496
+ "cli"
41497
+ ]
41498
+ },
41398
41499
  {
41399
41500
  id: "2026-10-21-mac-sim-teardown-race",
41400
41501
  version: "0.10.0",
@@ -41419,6 +41520,32 @@ var init_CHANGELOG = __esm({
41419
41520
  "file-io"
41420
41521
  ]
41421
41522
  },
41523
+ {
41524
+ id: "2026-10-21-mac-labs-toggle",
41525
+ version: "0.10.0",
41526
+ date: "2026-10-21",
41527
+ category: "feat",
41528
+ title: "Labs toggle for in-development Mac workspaces",
41529
+ summary: "Electronics, Manufacture (CNC Studio) and simulation in the Mac app now sit behind Settings \u25B8 Labs, off by default, so the default app is Design plus Agent.",
41530
+ features: [
41531
+ "desktop",
41532
+ "settings"
41533
+ ]
41534
+ },
41535
+ {
41536
+ id: "2026-10-21-mac-exports-photoreal",
41537
+ version: "0.10.0",
41538
+ date: "2026-10-21",
41539
+ category: "feat",
41540
+ title: "Mac app exports STEP and GLB, renders photoreal",
41541
+ summary: "File \u25B8 Export now writes STL, STEP and GLB with the CLI's writers, and File \u25B8 Render Photoreal\u2026 path-traces the current view with progress and cancel, no external binary.",
41542
+ features: [
41543
+ "desktop",
41544
+ "mac",
41545
+ "export",
41546
+ "photoreal"
41547
+ ]
41548
+ },
41422
41549
  {
41423
41550
  id: "2026-10-21-mac-app-updates",
41424
41551
  version: "0.10.0",
@@ -79719,154 +79846,6 @@ var init_dfm2 = __esm({
79719
79846
  });
79720
79847
 
79721
79848
  // src/tools/sheet-metal.ts
79722
- function buildSheetMetalDoc(base, flanges, hems, jogs, bendRelief) {
79723
- const doc = createDocument();
79724
- const nodes = {};
79725
- const shopProfile = base.shop_profile !== void 0 ? { shop_profile: base.shop_profile } : {};
79726
- const engravings = base.engravings !== void 0 && base.engravings.length > 0 ? { engravings: base.engravings } : {};
79727
- const baseNode = base.outline !== void 0 ? {
79728
- id: 0,
79729
- name: "Base flange (polygon)",
79730
- op: {
79731
- type: "SheetMetalBaseFlangePolygon",
79732
- outline: base.outline,
79733
- holes: base.holes,
79734
- thickness: base.thickness,
79735
- material: base.material,
79736
- ...shopProfile,
79737
- ...engravings
79738
- }
79739
- } : {
79740
- id: 0,
79741
- name: "Base flange",
79742
- op: {
79743
- type: "SheetMetalBaseFlangeRect",
79744
- width: base.width ?? 0,
79745
- depth: base.depth ?? 0,
79746
- thickness: base.thickness,
79747
- material: base.material,
79748
- ...shopProfile,
79749
- ...engravings
79750
- }
79751
- };
79752
- nodes["0"] = baseNode;
79753
- let parent = 0;
79754
- let nextId3 = 1;
79755
- flanges.forEach((f) => {
79756
- const id = nextId3++;
79757
- nodes[String(id)] = {
79758
- id,
79759
- name: `Edge flange ${id}`,
79760
- op: {
79761
- type: "SheetMetalEdgeFlange",
79762
- parent,
79763
- panel_id: f.panel_id ?? 0,
79764
- edge_index: f.edge_index,
79765
- length: f.length,
79766
- angle: f.angle ?? Math.PI / 2,
79767
- // Omit radius when unspecified — the kernel defaults to thickness,
79768
- // or the shop's fixed radius under a shop profile.
79769
- ...f.radius !== void 0 ? { radius: f.radius } : {},
79770
- direction: f.direction ?? "Up",
79771
- ...f.manual_k !== void 0 ? { manual_k: f.manual_k } : {}
79772
- }
79773
- };
79774
- parent = id;
79775
- });
79776
- hems.forEach((h) => {
79777
- const id = nextId3++;
79778
- nodes[String(id)] = {
79779
- id,
79780
- name: `Hem ${id}`,
79781
- op: {
79782
- type: "SheetMetalHem",
79783
- parent,
79784
- panel_id: h.panel_id ?? 0,
79785
- edge_index: h.edge_index,
79786
- kind: h.kind ?? "Closed",
79787
- length: h.length,
79788
- gap: h.gap ?? 0,
79789
- direction: h.direction ?? "Up"
79790
- }
79791
- };
79792
- parent = id;
79793
- });
79794
- jogs.forEach((j) => {
79795
- const id = nextId3++;
79796
- nodes[String(id)] = {
79797
- id,
79798
- name: `Jog ${id}`,
79799
- op: {
79800
- type: "SheetMetalJog",
79801
- parent,
79802
- panel_id: j.panel_id ?? 0,
79803
- edge_index: j.edge_index,
79804
- offset: j.offset,
79805
- length: j.length,
79806
- ...j.radius !== void 0 ? { radius: j.radius } : {},
79807
- direction: j.direction ?? "Up"
79808
- }
79809
- };
79810
- parent = id;
79811
- });
79812
- if (bendRelief) {
79813
- const id = nextId3++;
79814
- nodes[String(id)] = {
79815
- id,
79816
- name: "Bend relief",
79817
- op: {
79818
- type: "SheetMetalBendRelief",
79819
- parent,
79820
- ...bendRelief.width_mm !== void 0 ? { width: bendRelief.width_mm } : {},
79821
- ...bendRelief.depth_mm !== void 0 ? { depth: bendRelief.depth_mm } : {}
79822
- }
79823
- };
79824
- parent = id;
79825
- }
79826
- doc.nodes = nodes;
79827
- doc.roots = [{ root: parent, material: "default" }];
79828
- return doc;
79829
- }
79830
- function normaliseEngravings(raw) {
79831
- return raw.map((e, i) => {
79832
- const o = e ?? {};
79833
- if (o.type === "Text" || o.type === void 0 && typeof o.text === "string") {
79834
- if (typeof o.text !== "string" || o.text.length === 0) {
79835
- throw new Error(`engravings[${i}]: Text needs a non-empty \`text\``);
79836
- }
79837
- const height = Number(o.height);
79838
- if (!(height > 0)) {
79839
- throw new Error(`engravings[${i}]: Text needs \`height\` > 0 (cap height, mm)`);
79840
- }
79841
- return {
79842
- type: "Text",
79843
- text: o.text,
79844
- x: Number(o.x ?? 0),
79845
- y: Number(o.y ?? 0),
79846
- height,
79847
- angle: Number(o.angle ?? 0)
79848
- };
79849
- }
79850
- if (o.type === "Polyline" || Array.isArray(o.points)) {
79851
- const points = Array.isArray(o.points) ? o.points.map((p) => {
79852
- if (Array.isArray(p) && p.length >= 2)
79853
- return { x: Number(p[0]), y: Number(p[1]) };
79854
- if (p && typeof p === "object" && "x" in p && "y" in p) {
79855
- const q2 = p;
79856
- return { x: Number(q2.x), y: Number(q2.y) };
79857
- }
79858
- return null;
79859
- }).filter((p) => p !== null) : [];
79860
- if (points.length < 2) {
79861
- throw new Error(`engravings[${i}]: Polyline needs >= 2 points`);
79862
- }
79863
- return { type: "Polyline", points };
79864
- }
79865
- throw new Error(
79866
- `engravings[${i}]: expected {type: "Text", text, x, y, height} or {type: "Polyline", points}`
79867
- );
79868
- });
79869
- }
79870
79849
  function renderedOf(engine, doc) {
79871
79850
  const scene = engine.evaluate(doc);
79872
79851
  for (const part of scene.parts) {
@@ -79886,37 +79865,7 @@ function textResult13(payload) {
79886
79865
  };
79887
79866
  }
79888
79867
  function sheetMetalCreate(input, engine) {
79889
- const a = input ?? {};
79890
- const normalisePoint = (p) => {
79891
- if (Array.isArray(p) && p.length >= 2)
79892
- return { x: Number(p[0]), y: Number(p[1]) };
79893
- if (p && typeof p === "object" && "x" in p && "y" in p) {
79894
- const o = p;
79895
- return { x: Number(o.x), y: Number(o.y) };
79896
- }
79897
- return null;
79898
- };
79899
- const normaliseLoop = (loop) => {
79900
- if (!Array.isArray(loop)) return [];
79901
- return loop.map(normalisePoint).filter((p) => p !== null);
79902
- };
79903
- const outline = Array.isArray(a.outline) ? normaliseLoop(a.outline) : void 0;
79904
- const holes = Array.isArray(a.holes) ? a.holes.map(normaliseLoop) : void 0;
79905
- const base = {
79906
- width: Number(a.width),
79907
- depth: Number(a.depth),
79908
- thickness: Number(a.thickness),
79909
- material: typeof a.material === "string" ? a.material : "al-soft",
79910
- outline,
79911
- holes,
79912
- ...typeof a.shop_profile === "string" && a.shop_profile.length > 0 ? { shop_profile: a.shop_profile } : {},
79913
- ...Array.isArray(a.engravings) ? { engravings: normaliseEngravings(a.engravings) } : {}
79914
- };
79915
- const flanges = Array.isArray(a.flanges) ? a.flanges : [];
79916
- const hems = Array.isArray(a.hems) ? a.hems : [];
79917
- const jogs = Array.isArray(a.jogs) ? a.jogs : [];
79918
- const bendRelief = a.bend_relief === true ? {} : a.bend_relief && typeof a.bend_relief === "object" ? a.bend_relief : void 0;
79919
- const doc = buildSheetMetalDoc(base, flanges, hems, jogs, bendRelief);
79868
+ const doc = engine.buildSheetMetalDocument(input ?? {});
79920
79869
  const rendered = renderedOf(engine, doc);
79921
79870
  const documentId = registerSession(doc);
79922
79871
  const errors = rendered.violations.filter(
@@ -80184,7 +80133,6 @@ var sheetMetalCreateSchema, sheetMetalUnfoldSchema, sheetMetalMaterialsSchema, s
80184
80133
  var init_sheet_metal2 = __esm({
80185
80134
  "src/tools/sheet-metal.ts"() {
80186
80135
  "use strict";
80187
- init_dist2();
80188
80136
  init_session2();
80189
80137
  init_tool_def();
80190
80138
  sheetMetalCreateSchema = {
@@ -86902,8 +86850,8 @@ var init_server3 = __esm({
86902
86850
  init_order_feed();
86903
86851
  init_animate();
86904
86852
  PKG_VERSION = (() => {
86905
- if ("0.10.0-main.127") {
86906
- return "0.10.0-main.127";
86853
+ if ("0.10.0-main.129") {
86854
+ return "0.10.0-main.129";
86907
86855
  }
86908
86856
  try {
86909
86857
  const req = createRequire2(import.meta.url);
@@ -86912,8 +86860,8 @@ var init_server3 = __esm({
86912
86860
  return "0.0.0";
86913
86861
  }
86914
86862
  })();
86915
- BUILD_SHA = "29cbe4343d120465c4b5eda7f7ccfc72d65a2171";
86916
- BUILD_TIME = "2026-10-21T14:37:18.317Z";
86863
+ BUILD_SHA = "c0f41c513a664c5cad95f6b53a04977718e67e65";
86864
+ BUILD_TIME = "2026-10-21T15:14:39.035Z";
86917
86865
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
86918
86866
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
86919
86867
  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.127",
3
+ "version": "0.10.0-main.129",
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": "29cbe4343d120465c4b5eda7f7ccfc72d65a2171",
23
- "builtAt": "2026-10-21T14:37:18.317Z"
22
+ "sha": "c0f41c513a664c5cad95f6b53a04977718e67e65",
23
+ "builtAt": "2026-10-21T15:14:39.035Z"
24
24
  }
25
25
  }