@vcad/mcp 0.9.4-main.6 → 0.9.4-main.8

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 5d4ed6fea90eb5e449458ec1cf2fcda1ba7aef52 at 2026-07-23T16:40:33.899Z. Source: https://github.com/ecto/vcad
9
+ Built from f09f3d656a04f8a18840c42116208ada180ce487 at 2026-07-24T16:11:19.940Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -538,6 +538,7 @@ __export(vcad_kernel_wasm_exports, {
538
538
  camGenerateRoughing3d: () => camGenerateRoughing3d,
539
539
  camGetDefaultTools: () => camGetDefaultTools,
540
540
  camToolpathStats: () => camToolpathStats,
541
+ checkDesignConstraints: () => checkDesignConstraints,
541
542
  checkPrintability: () => checkPrintability,
542
543
  checkSheetMetal: () => checkSheetMetal,
543
544
  circuitAcResponse: () => circuitAcResponse,
@@ -688,6 +689,7 @@ __export(vcad_kernel_wasm_exports, {
688
689
  sliceMesh: () => sliceMesh,
689
690
  sliceMeshWithProgress: () => sliceMeshWithProgress,
690
691
  sliceSolid: () => sliceSolid,
692
+ solveDesignConstraints: () => solveDesignConstraints,
691
693
  solveForwardKinematics: () => solveForwardKinematics,
692
694
  solveSketchSegments: () => solveSketchSegments,
693
695
  textBounds: () => textBounds,
@@ -1139,6 +1141,27 @@ function camToolpathStats(toolpath_json) {
1139
1141
  }
1140
1142
  return takeFromExternrefTable0(ret[0]);
1141
1143
  }
1144
+ function checkDesignConstraints(doc_json) {
1145
+ let deferred3_0;
1146
+ let deferred3_1;
1147
+ try {
1148
+ const ptr0 = passStringToWasm0(doc_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1149
+ const len0 = WASM_VECTOR_LEN;
1150
+ const ret = wasm.checkDesignConstraints(ptr0, len0);
1151
+ var ptr2 = ret[0];
1152
+ var len2 = ret[1];
1153
+ if (ret[3]) {
1154
+ ptr2 = 0;
1155
+ len2 = 0;
1156
+ throw takeFromExternrefTable0(ret[2]);
1157
+ }
1158
+ deferred3_0 = ptr2;
1159
+ deferred3_1 = len2;
1160
+ return getStringFromWasm0(ptr2, len2);
1161
+ } finally {
1162
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
1163
+ }
1164
+ }
1142
1165
  function checkPrintability(solid, printer_profile) {
1143
1166
  _assertClass(solid, Solid);
1144
1167
  const ptr0 = passStringToWasm0(printer_profile, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@@ -2986,6 +3009,29 @@ function sliceSolid(solid, settings, segments) {
2986
3009
  }
2987
3010
  return SliceResult.__wrap(ret[0]);
2988
3011
  }
3012
+ function solveDesignConstraints(doc_json, options_json) {
3013
+ let deferred4_0;
3014
+ let deferred4_1;
3015
+ try {
3016
+ const ptr0 = passStringToWasm0(doc_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3017
+ const len0 = WASM_VECTOR_LEN;
3018
+ const ptr1 = passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3019
+ const len1 = WASM_VECTOR_LEN;
3020
+ const ret = wasm.solveDesignConstraints(ptr0, len0, ptr1, len1);
3021
+ var ptr3 = ret[0];
3022
+ var len3 = ret[1];
3023
+ if (ret[3]) {
3024
+ ptr3 = 0;
3025
+ len3 = 0;
3026
+ throw takeFromExternrefTable0(ret[2]);
3027
+ }
3028
+ deferred4_0 = ptr3;
3029
+ deferred4_1 = len3;
3030
+ return getStringFromWasm0(ptr3, len3);
3031
+ } finally {
3032
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
3033
+ }
3034
+ }
2989
3035
  function solveForwardKinematics(doc_json) {
2990
3036
  const ptr0 = passStringToWasm0(doc_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2991
3037
  const len0 = WASM_VECTOR_LEN;
@@ -10031,120 +10077,22 @@ var init_diff = __esm({
10031
10077
  });
10032
10078
 
10033
10079
  // ../engine/dist/sequence.js
10034
- function sampleTrackValue(track, t2) {
10035
- const keys = track.keys;
10036
- if (keys.length === 0)
10037
- return 0;
10038
- const first = keys[0];
10039
- if (t2 <= first.t)
10040
- return first.value;
10041
- const last = keys[keys.length - 1];
10042
- if (t2 >= last.t)
10043
- return last.value;
10044
- const idx = keys.findIndex((k) => k.t > t2);
10045
- const a = keys[idx - 1];
10046
- const b = keys[idx];
10047
- const span = b.t - a.t;
10048
- let u = span <= 0 ? 1 : (t2 - a.t) / span;
10049
- switch (b.ease ?? "linear") {
10050
- case "step":
10051
- u = u >= 1 ? 1 : 0;
10052
- break;
10053
- case "ease-in-out":
10054
- u = u * u * (3 - 2 * u);
10055
- break;
10056
- default:
10057
- break;
10058
- }
10059
- return a.value + (b.value - a.value) * u;
10060
- }
10061
- function cameraPoseAt(shots, t2, prevPose) {
10062
- let active;
10063
- for (const shot of shots) {
10064
- if (t2 >= shot.startS && t2 < shot.endS)
10065
- active = shot;
10066
- }
10067
- if (!active)
10068
- return prevPose;
10069
- const span = active.endS - active.startS;
10070
- const u = span <= 0 ? 1 : (t2 - active.startS) / span;
10071
- const kind = active.kind;
10072
- switch (kind.type) {
10073
- case "Turntable":
10074
- return {
10075
- azimuthDeg: kind.degrees * u,
10076
- elevationDeg: kind.elevationDeg,
10077
- dolly: 1
10078
- };
10079
- case "Orbit":
10080
- return {
10081
- azimuthDeg: kind.from[0] + (kind.to[0] - kind.from[0]) * u,
10082
- elevationDeg: kind.from[1] + (kind.to[1] - kind.from[1]) * u,
10083
- dolly: 1
10084
- };
10085
- case "Focus":
10086
- return {
10087
- azimuthDeg: prevPose.azimuthDeg,
10088
- elevationDeg: prevPose.elevationDeg,
10089
- dolly: 1 + (kind.dolly - 1) * u,
10090
- target: kind.target
10091
- };
10092
- case "Static":
10093
- return { ...DEFAULT_POSE };
10080
+ function requireWasm() {
10081
+ const mod = getKernelWasmSync();
10082
+ if (!mod || typeof mod.sample_timeline_sequence !== "function" || typeof mod.sample_timeline_track !== "function") {
10083
+ throw new Error("kernel WASM not initialized (or too old for timeline sampling) \u2014 await getKernelWasm() before sampling sequences");
10094
10084
  }
10085
+ return mod;
10086
+ }
10087
+ function sampleTrackValue(track, t2) {
10088
+ return requireWasm().sample_timeline_track(JSON.stringify(track), t2);
10095
10089
  }
10096
10090
  function sampleSequence(doc, timelineOverride) {
10097
10091
  const timeline = timelineOverride ?? doc.timeline;
10098
10092
  if (!timeline)
10099
10093
  return [];
10100
- const fps = timeline.fps && timeline.fps > 0 ? timeline.fps : 24;
10101
- const frameCount = Math.max(2, Math.round(timeline.durationS * fps) + 1);
10102
- const tracks = timeline.tracks ?? [];
10103
- const shots = timeline.camera ?? [];
10104
- const hasParamTracks2 = tracks.some((tr) => tr.target.type === "Parameter");
10105
- const frames = [];
10106
- let prevParams;
10107
- let prevPose = { ...DEFAULT_POSE };
10108
- for (let index = 0; index < frameCount; index++) {
10109
- const t2 = index / fps;
10110
- const params = {};
10111
- const joints = {};
10112
- const visibility = {};
10113
- let explode = 0;
10114
- for (const track of tracks) {
10115
- const value = sampleTrackValue(track, t2);
10116
- const target = track.target;
10117
- switch (target.type) {
10118
- case "Parameter":
10119
- params[target.name] = value;
10120
- break;
10121
- case "Joint":
10122
- joints[target.jointId] = value;
10123
- break;
10124
- case "Visibility":
10125
- visibility[target.instanceId] = value > 0.5;
10126
- break;
10127
- case "Explode":
10128
- explode = value;
10129
- break;
10130
- }
10131
- }
10132
- const camera = cameraPoseAt(shots, t2, prevPose);
10133
- prevPose = camera;
10134
- const geometryDirty = prevParams === void 0 ? hasParamTracks2 : Object.keys(params).some((name) => params[name] !== prevParams[name]);
10135
- prevParams = params;
10136
- frames.push({
10137
- index,
10138
- t: t2,
10139
- params,
10140
- joints,
10141
- visibility,
10142
- explode,
10143
- camera,
10144
- geometryDirty
10145
- });
10146
- }
10147
- return frames;
10094
+ const json = requireWasm().sample_timeline_sequence(JSON.stringify(timeline));
10095
+ return JSON.parse(json);
10148
10096
  }
10149
10097
  function poseDocument(doc, frame) {
10150
10098
  const posed = structuredClone(doc);
@@ -10166,11 +10114,10 @@ function poseDocument(doc, frame) {
10166
10114
  }
10167
10115
  return posed;
10168
10116
  }
10169
- var DEFAULT_POSE;
10170
10117
  var init_sequence = __esm({
10171
10118
  "../engine/dist/sequence.js"() {
10172
10119
  "use strict";
10173
- DEFAULT_POSE = { azimuthDeg: 0, elevationDeg: 30, dolly: 1 };
10120
+ init_wasm_singleton();
10174
10121
  }
10175
10122
  });
10176
10123
 
@@ -10211,7 +10158,7 @@ async function isEcadAvailable2() {
10211
10158
  const wasm2 = await loadEcadWasm();
10212
10159
  return wasm2 !== null;
10213
10160
  }
10214
- async function solveDesignConstraints(doc, options) {
10161
+ async function solveDesignConstraints2(doc, options) {
10215
10162
  return verifyWithKernel("design constraints", (wasm2) => {
10216
10163
  if (typeof wasm2.solveDesignConstraints !== "function") {
10217
10164
  throw new Error("kernel WASM predates solveDesignConstraints");
@@ -10219,7 +10166,7 @@ async function solveDesignConstraints(doc, options) {
10219
10166
  return JSON.parse(wasm2.solveDesignConstraints(JSON.stringify(doc), JSON.stringify(options ?? {})));
10220
10167
  });
10221
10168
  }
10222
- async function checkDesignConstraints(doc) {
10169
+ async function checkDesignConstraints2(doc) {
10223
10170
  return verifyWithKernel("design constraints (check)", (wasm2) => {
10224
10171
  if (typeof wasm2.checkDesignConstraints !== "function") {
10225
10172
  throw new Error("kernel WASM predates checkDesignConstraints");
@@ -11885,7 +11832,7 @@ __export(dist_exports, {
11885
11832
  buildPartDocument: () => buildPartDocument,
11886
11833
  buildReceipt: () => buildReceipt,
11887
11834
  builtinSymbols: () => builtinSymbols,
11888
- checkDesignConstraints: () => checkDesignConstraints,
11835
+ checkDesignConstraints: () => checkDesignConstraints2,
11889
11836
  checkEnclosureFit: () => checkEnclosureFit,
11890
11837
  checkErc: () => checkErc,
11891
11838
  circuitAcResponse: () => circuitAcResponse2,
@@ -11976,7 +11923,7 @@ __export(dist_exports, {
11976
11923
  searchParts: () => searchParts,
11977
11924
  semanticDiff: () => semanticDiff,
11978
11925
  semanticDiffFallback: () => semanticDiffFallback,
11979
- solveDesignConstraints: () => solveDesignConstraints,
11926
+ solveDesignConstraints: () => solveDesignConstraints2,
11980
11927
  solveForwardKinematics: () => solveForwardKinematics2,
11981
11928
  threeWayMerge: () => threeWayMerge,
11982
11929
  toWorld: () => toWorld,
@@ -41634,6 +41581,20 @@ var init_CHANGELOG = __esm({
41634
41581
  "route_nets"
41635
41582
  ]
41636
41583
  },
41584
+ {
41585
+ id: "2026-07-23-render-view-triangle-guard",
41586
+ version: "0.9.4",
41587
+ date: "2026-07-23",
41588
+ category: "fix",
41589
+ title: "render_view refuses over-dense documents instead of crashing",
41590
+ summary: "Documents tessellating past 120k triangles (e.g. large sphere patterns) now get an actionable error from render_view instead of OOM-killing the server with a >100 MB per-triangle SVG.",
41591
+ features: [
41592
+ "render"
41593
+ ],
41594
+ mcpTools: [
41595
+ "render_view"
41596
+ ]
41597
+ },
41637
41598
  {
41638
41599
  id: "2026-07-23-plane-stitch-maze-rescue",
41639
41600
  version: "0.9.4",
@@ -48462,6 +48423,7 @@ function undoLastSnapshot(documentId) {
48462
48423
  function clearHistory(documentId) {
48463
48424
  sessionHistory.delete(documentId);
48464
48425
  lastChangedParts.delete(documentId);
48426
+ lastTriangleCount.delete(documentId);
48465
48427
  }
48466
48428
  function recordLastChanged(documentId, partIds) {
48467
48429
  if (!documentId) return;
@@ -48470,7 +48432,14 @@ function recordLastChanged(documentId, partIds) {
48470
48432
  function getLastChanged(documentId) {
48471
48433
  return lastChangedParts.get(documentId) ?? null;
48472
48434
  }
48473
- var fallbackDocuments, scopeProvider, documents, nextId, MAX_HISTORY, sessionHistory, lastChangedParts;
48435
+ function recordTriangles(documentId, triangles) {
48436
+ if (!documentId) return;
48437
+ lastTriangleCount.set(documentId, triangles);
48438
+ }
48439
+ function getLastTriangles(documentId) {
48440
+ return lastTriangleCount.get(documentId) ?? null;
48441
+ }
48442
+ var fallbackDocuments, scopeProvider, documents, nextId, MAX_HISTORY, sessionHistory, lastChangedParts, lastTriangleCount;
48474
48443
  var init_session_core = __esm({
48475
48444
  "src/tools/session-core.ts"() {
48476
48445
  "use strict";
@@ -48490,6 +48459,7 @@ var init_session_core = __esm({
48490
48459
  MAX_HISTORY = 50;
48491
48460
  sessionHistory = /* @__PURE__ */ new Map();
48492
48461
  lastChangedParts = /* @__PURE__ */ new Map();
48462
+ lastTriangleCount = /* @__PURE__ */ new Map();
48493
48463
  }
48494
48464
  });
48495
48465
 
@@ -49682,7 +49652,10 @@ var init_loon = __esm({
49682
49652
  if (doc) {
49683
49653
  if (targetId) documents.set(targetId, doc);
49684
49654
  const integrity = computeIntegrity(doc, ctx.engine);
49685
- if (integrity) appendIntegrity(result, integrity);
49655
+ if (integrity) {
49656
+ appendIntegrity(result, integrity);
49657
+ if (targetId) recordTriangles(targetId, integrity.triangles);
49658
+ }
49686
49659
  }
49687
49660
  } catch {
49688
49661
  }
@@ -51570,7 +51543,10 @@ function dispatchRegistryTool(toolName, args, engine) {
51570
51543
  ]);
51571
51544
  if (engine) {
51572
51545
  const integrity = computeIntegrity(doc, engine);
51573
- if (integrity) appendIntegrity(result, integrity);
51546
+ if (integrity) {
51547
+ appendIntegrity(result, integrity);
51548
+ recordTriangles(documentId, integrity.triangles);
51549
+ }
51574
51550
  }
51575
51551
  }
51576
51552
  return result;
@@ -53224,7 +53200,10 @@ function applyEdits(args, engine) {
53224
53200
  ]);
53225
53201
  if (engine) {
53226
53202
  const integrity = computeIntegrity(working, engine);
53227
- if (integrity) appendIntegrity(result, integrity);
53203
+ if (integrity) {
53204
+ appendIntegrity(result, integrity);
53205
+ recordTriangles(documentId, integrity.triangles);
53206
+ }
53228
53207
  }
53229
53208
  }
53230
53209
  return result;
@@ -57223,7 +57202,7 @@ async function setParameters(input, engine) {
57223
57202
  }
57224
57203
  let constraintSolve;
57225
57204
  if ((doc.constraints ?? []).length > 0) {
57226
- const outcome = await solveDesignConstraints(doc);
57205
+ const outcome = await solveDesignConstraints2(doc);
57227
57206
  if (outcome.status === "ok") {
57228
57207
  doc.nodes = outcome.value.document.nodes;
57229
57208
  doc.constraints = outcome.value.document.constraints;
@@ -57240,7 +57219,10 @@ async function setParameters(input, engine) {
57240
57219
  });
57241
57220
  result.structuredContent = { changed };
57242
57221
  const integrity = computeIntegrity(doc, engine);
57243
- if (integrity) appendIntegrity(result, integrity);
57222
+ if (integrity) {
57223
+ appendIntegrity(result, integrity);
57224
+ recordTriangles(documentId, integrity.triangles);
57225
+ }
57244
57226
  return result;
57245
57227
  }
57246
57228
  function parameterGradient(input, engine) {
@@ -57363,7 +57345,7 @@ function describe(c) {
57363
57345
  async function constraintReceiptClaims(doc) {
57364
57346
  const constraints = doc.constraints ?? [];
57365
57347
  if (constraints.length === 0) return [];
57366
- const outcome = await checkDesignConstraints(doc);
57348
+ const outcome = await checkDesignConstraints2(doc);
57367
57349
  const byId = /* @__PURE__ */ new Map();
57368
57350
  if (outcome.status === "ok") {
57369
57351
  for (const r of outcome.value.residuals) byId.set(r.id, r);
@@ -57440,7 +57422,7 @@ function worst(statuses) {
57440
57422
  }
57441
57423
  async function verifyConstraintClaims(doc, receipt) {
57442
57424
  const checks = [];
57443
- const outcome = await checkDesignConstraints(doc);
57425
+ const outcome = await checkDesignConstraints2(doc);
57444
57426
  const byId = /* @__PURE__ */ new Map();
57445
57427
  if (outcome.status === "ok") {
57446
57428
  for (const r of outcome.value.residuals) byId.set(r.id, r);
@@ -67961,7 +67943,7 @@ async function placementDrcIfMoved(doc, report) {
67961
67943
  return pcb ? await summarizePlacementDrc(pcb) : void 0;
67962
67944
  }
67963
67945
  async function solveAndReport(doc, documentId) {
67964
- const outcome = await solveDesignConstraints(doc);
67946
+ const outcome = await solveDesignConstraints2(doc);
67965
67947
  if (outcome.status !== "ok") {
67966
67948
  return err6(`constraint solve unavailable: ${outcome.reason}`);
67967
67949
  }
@@ -68087,7 +68069,7 @@ async function listConstraints(args) {
68087
68069
  hint: "add_constraint persists solver-enforced geometric relationships"
68088
68070
  });
68089
68071
  }
68090
- const outcome = await checkDesignConstraints(ctx.doc);
68072
+ const outcome = await checkDesignConstraints2(ctx.doc);
68091
68073
  const report = outcome.status === "ok" ? outcome.value : void 0;
68092
68074
  const residuals = new Map(report?.residuals.map((r) => [r.id, r.residual]) ?? []);
68093
68075
  const measured = new Map(report?.drivenValues.map((d) => [d.id, d.value]) ?? []);
@@ -68614,6 +68596,13 @@ function complexityGuard(doc) {
68614
68596
  return null;
68615
68597
  }
68616
68598
  async function rasterize(svg, widthPx, background = "white") {
68599
+ const svgBytes = Buffer.byteLength(svg, "utf8");
68600
+ if (svgBytes > MAX_RASTER_SVG_BYTES) {
68601
+ return {
68602
+ png: null,
68603
+ reason: `rasterization refused: SVG is ${svgBytes} bytes (cap ${MAX_RASTER_SVG_BYTES}) \u2014 the document is too dense to raster safely`
68604
+ };
68605
+ }
68617
68606
  let ResvgCtor;
68618
68607
  try {
68619
68608
  ({ Resvg: ResvgCtor } = await import("@resvg/resvg-js"));
@@ -68648,6 +68637,22 @@ async function renderView(args) {
68648
68637
  2048,
68649
68638
  Math.max(64, Number.isFinite(widthRaw) ? Math.round(widthRaw) : DEFAULT_WIDTH_PX)
68650
68639
  );
68640
+ const knownTriangles = documentId ? getLastTriangles(documentId) : null;
68641
+ if (knownTriangles !== null && knownTriangles > MAX_RENDER_TRIANGLES) {
68642
+ return {
68643
+ content: [
68644
+ {
68645
+ type: "text",
68646
+ text: JSON.stringify({
68647
+ error: `render refused: document tessellates to ${knownTriangles} triangles (render limit ${MAX_RENDER_TRIANGLES})`,
68648
+ document_id: documentId,
68649
+ hint: "The renderer emits per-triangle SVG, so documents this dense exhaust memory. Reduce pattern counts / sphere counts, render a subset via `focus`, or inspect numerically via inspect_cad / measure. For full geometry use export_cad."
68650
+ })
68651
+ }
68652
+ ],
68653
+ isError: true
68654
+ };
68655
+ }
68651
68656
  const tooComplex = complexityGuard(doc);
68652
68657
  if (tooComplex) {
68653
68658
  return {
@@ -68901,8 +68906,25 @@ async function renderView(args) {
68901
68906
  ]
68902
68907
  }, [asset]);
68903
68908
  }
68904
- const note = raster.reason === "module-missing" ? "Install @resvg/resvg-js for PNG output; returning raw SVG." : `PNG ${raster.reason}; returning raw SVG.`;
68905
68909
  const svgBytes = Buffer.byteLength(svg, "utf8");
68910
+ if (raster.reason !== "module-missing" && svgBytes > MAX_INLINE_SVG_BYTES) {
68911
+ return {
68912
+ content: [
68913
+ {
68914
+ type: "text",
68915
+ text: JSON.stringify({
68916
+ error: `render failed: ${raster.reason}`,
68917
+ document_id: documentId,
68918
+ view: viewLabel,
68919
+ svg_bytes: svgBytes,
68920
+ hint: "The document is too dense for the per-triangle SVG renderer. Reduce pattern counts, render a subset via `focus`, or inspect numerically via inspect_cad / measure. For full geometry use export_cad."
68921
+ })
68922
+ }
68923
+ ],
68924
+ isError: true
68925
+ };
68926
+ }
68927
+ const note = raster.reason === "module-missing" ? "Install @resvg/resvg-js for PNG output; returning raw SVG." : `PNG ${raster.reason}; returning raw SVG.`;
68906
68928
  return {
68907
68929
  content: [
68908
68930
  {
@@ -69307,7 +69329,7 @@ async function renderStackup(args) {
69307
69329
  });
69308
69330
  return withRenderAssets({ content }, assets);
69309
69331
  }
69310
- var renderViewSchema, SVG_SCALE, DEFAULT_WIDTH_PX, MAX_NODES, MAX_PATTERN_INSTANCES, MAX_INLINE_SVG_BYTES, renderPcbSchema, PCB_MARGIN_MM, RATSNEST_COLOR, renderRatsnestSchema, COPPER_LAYERS2, renderStackupSchema, toolDefs23;
69332
+ var renderViewSchema, SVG_SCALE, DEFAULT_WIDTH_PX, MAX_NODES, MAX_PATTERN_INSTANCES, MAX_RENDER_TRIANGLES, MAX_RASTER_SVG_BYTES, MAX_INLINE_SVG_BYTES, renderPcbSchema, PCB_MARGIN_MM, RATSNEST_COLOR, renderRatsnestSchema, COPPER_LAYERS2, renderStackupSchema, toolDefs23;
69311
69333
  var init_render2 = __esm({
69312
69334
  "src/tools/render.ts"() {
69313
69335
  "use strict";
@@ -69386,6 +69408,8 @@ var init_render2 = __esm({
69386
69408
  DEFAULT_WIDTH_PX = 800;
69387
69409
  MAX_NODES = 1e4;
69388
69410
  MAX_PATTERN_INSTANCES = 5e4;
69411
+ MAX_RENDER_TRIANGLES = 12e4;
69412
+ MAX_RASTER_SVG_BYTES = 64 * 1024 * 1024;
69389
69413
  MAX_INLINE_SVG_BYTES = 256 * 1024;
69390
69414
  renderPcbSchema = {
69391
69415
  type: "object",
@@ -77060,6 +77084,7 @@ ${issues.map((i) => i.track >= 0 ? `track[${i.track}]: ${i.problem}` : i.problem
77060
77084
  );
77061
77085
  }
77062
77086
  doc.timeline = timeline;
77087
+ await getKernelWasm();
77063
77088
  const frames = sampleSequence(doc);
77064
77089
  return ok({
77065
77090
  duration_s: timeline.durationS,
@@ -77330,6 +77355,7 @@ async function renderSequence(args, ctx) {
77330
77355
  ${issues.map((i) => i.problem).join("\n")}`
77331
77356
  );
77332
77357
  }
77358
+ await getKernelWasm();
77333
77359
  const frames = sampleSequence(doc, timeline);
77334
77360
  if (frames.length > MAX_FRAMES) {
77335
77361
  return err2(
@@ -77514,6 +77540,7 @@ async function exportVideo(args, ctx) {
77514
77540
  return err2(`timeline invalid:
77515
77541
  ${issues.map((i) => i.problem).join("\n")}`);
77516
77542
  }
77543
+ await getKernelWasm();
77517
77544
  const frames = sampleSequence(doc, timeline);
77518
77545
  if (frames.length > MAX_FRAMES) {
77519
77546
  return err2(
@@ -78780,8 +78807,8 @@ var init_server3 = __esm({
78780
78807
  init_order_feed();
78781
78808
  init_animate();
78782
78809
  PKG_VERSION = (() => {
78783
- if ("0.9.4-main.6") {
78784
- return "0.9.4-main.6";
78810
+ if ("0.9.4-main.8") {
78811
+ return "0.9.4-main.8";
78785
78812
  }
78786
78813
  try {
78787
78814
  const req = createRequire2(import.meta.url);
@@ -78790,8 +78817,8 @@ var init_server3 = __esm({
78790
78817
  return "0.0.0";
78791
78818
  }
78792
78819
  })();
78793
- BUILD_SHA = "5d4ed6fea90eb5e449458ec1cf2fcda1ba7aef52";
78794
- BUILD_TIME = "2026-07-23T16:40:33.899Z";
78820
+ BUILD_SHA = "f09f3d656a04f8a18840c42116208ada180ce487";
78821
+ BUILD_TIME = "2026-07-24T16:11:19.940Z";
78795
78822
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
78796
78823
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
78797
78824
  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.6",
3
+ "version": "0.9.4-main.8",
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": "5d4ed6fea90eb5e449458ec1cf2fcda1ba7aef52",
23
- "builtAt": "2026-07-23T16:40:33.899Z"
22
+ "sha": "f09f3d656a04f8a18840c42116208ada180ce487",
23
+ "builtAt": "2026-07-24T16:11:19.940Z"
24
24
  }
25
25
  }
Binary file