@vcad/mcp 0.11.0-main.138 → 0.11.0-main.140

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 2df8f6d220243cc013bc875337b0aceb4b6b25b3 at 2026-10-28T01:27:09.038Z. Source: https://github.com/ecto/vcad
9
+ Built from 4a5ca79b1144c3ab693e34c74fc8a20ff18d6242 at 2026-11-07T14:45:02.882Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -46,6 +46,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
46
46
  var vcad_kernel_wasm_exports = {};
47
47
  __export(vcad_kernel_wasm_exports, {
48
48
  CircuitSim: () => CircuitSim,
49
+ IncrementalEvaluator: () => IncrementalEvaluator,
49
50
  MdSim: () => MdSim,
50
51
  PhysicsSim: () => PhysicsSim,
51
52
  RayTracer: () => RayTracer,
@@ -71,6 +72,7 @@ __export(vcad_kernel_wasm_exports, {
71
72
  buildCalibrationReportJson: () => buildCalibrationReportJson,
72
73
  buildGlbBytes: () => buildGlbBytes,
73
74
  buildPart: () => buildPart,
75
+ buildSheetMetalDocument: () => buildSheetMetalDocument,
74
76
  buildStlBytes: () => buildStlBytes,
75
77
  build_chat_system_prompt: () => build_chat_system_prompt,
76
78
  calibrationDefaultTolerance: () => calibrationDefaultTolerance,
@@ -166,6 +168,7 @@ __export(vcad_kernel_wasm_exports, {
166
168
  estimatePrintCost: () => estimatePrintCost,
167
169
  estimate_cost_for_process: () => estimate_cost_for_process,
168
170
  eulerXyzDegToQuat: () => eulerXyzDegToQuat,
171
+ evalLoonDocument: () => evalLoonDocument,
169
172
  evalVcadSource: () => evalVcadSource,
170
173
  evalVcadSourceParametric: () => evalVcadSourceParametric,
171
174
  evalVcadSourceWithModules: () => evalVcadSourceWithModules,
@@ -197,11 +200,13 @@ __export(vcad_kernel_wasm_exports, {
197
200
  get_tool_schemas: () => get_tool_schemas,
198
201
  importStepBuffer: () => importStepBuffer,
199
202
  importStepBufferWithReport: () => importStepBufferWithReport,
203
+ importStepMeshDocument: () => importStepMeshDocument,
200
204
  importUrdfBuffer: () => importUrdfBuffer,
201
205
  importUrdfBufferWithOptions: () => importUrdfBufferWithOptions,
202
206
  init: () => init,
203
207
  initGpu: () => initGpu,
204
208
  initSync: () => initSync,
209
+ inlineMeshImports: () => inlineMeshImports,
205
210
  inspectDocumentFaces: () => inspectDocumentFaces,
206
211
  isCamAvailable: () => isCamAvailable,
207
212
  isEcadAvailable: () => isEcadAvailable,
@@ -277,6 +282,7 @@ __export(vcad_kernel_wasm_exports, {
277
282
  solveDesignConstraints: () => solveDesignConstraints,
278
283
  solveForwardKinematics: () => solveForwardKinematics,
279
284
  solveSketchSegments: () => solveSketchSegments,
285
+ stepImportDocument: () => stepImportDocument,
280
286
  stepSourceRegistered: () => stepSourceRegistered,
281
287
  textBounds: () => textBounds,
282
288
  thermalSolve: () => thermalSolve,
@@ -535,6 +541,27 @@ function buildPart(path, params_json) {
535
541
  wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
536
542
  }
537
543
  }
544
+ function buildSheetMetalDocument(args_json) {
545
+ let deferred3_0;
546
+ let deferred3_1;
547
+ try {
548
+ const ptr0 = passStringToWasm0(args_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
549
+ const len0 = WASM_VECTOR_LEN;
550
+ const ret = wasm.buildSheetMetalDocument(ptr0, len0);
551
+ var ptr2 = ret[0];
552
+ var len2 = ret[1];
553
+ if (ret[3]) {
554
+ ptr2 = 0;
555
+ len2 = 0;
556
+ throw takeFromExternrefTable0(ret[2]);
557
+ }
558
+ deferred3_0 = ptr2;
559
+ deferred3_1 = len2;
560
+ return getStringFromWasm0(ptr2, len2);
561
+ } finally {
562
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
563
+ }
564
+ }
538
565
  function buildStlBytes(spec_json, f32_data, u32_data) {
539
566
  const ptr0 = passStringToWasm0(spec_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
540
567
  const len0 = WASM_VECTOR_LEN;
@@ -1805,6 +1832,33 @@ function eulerXyzDegToQuat(x_deg, y_deg, z_deg) {
1805
1832
  wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
1806
1833
  return v1;
1807
1834
  }
1835
+ function evalLoonDocument(source, modules_json, base_dir, path) {
1836
+ let deferred6_0;
1837
+ let deferred6_1;
1838
+ try {
1839
+ const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1840
+ const len0 = WASM_VECTOR_LEN;
1841
+ const ptr1 = passStringToWasm0(modules_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1842
+ const len1 = WASM_VECTOR_LEN;
1843
+ var ptr2 = isLikeNone(base_dir) ? 0 : passStringToWasm0(base_dir, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1844
+ var len2 = WASM_VECTOR_LEN;
1845
+ var ptr3 = isLikeNone(path) ? 0 : passStringToWasm0(path, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1846
+ var len3 = WASM_VECTOR_LEN;
1847
+ const ret = wasm.evalLoonDocument(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
1848
+ var ptr5 = ret[0];
1849
+ var len5 = ret[1];
1850
+ if (ret[3]) {
1851
+ ptr5 = 0;
1852
+ len5 = 0;
1853
+ throw takeFromExternrefTable0(ret[2]);
1854
+ }
1855
+ deferred6_0 = ptr5;
1856
+ deferred6_1 = len5;
1857
+ return getStringFromWasm0(ptr5, len5);
1858
+ } finally {
1859
+ wasm.__wbindgen_free(deferred6_0, deferred6_1, 1);
1860
+ }
1861
+ }
1808
1862
  function evalVcadSource(source) {
1809
1863
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1810
1864
  const len0 = WASM_VECTOR_LEN;
@@ -2191,6 +2245,21 @@ function importStepBufferWithReport(data) {
2191
2245
  }
2192
2246
  return takeFromExternrefTable0(ret[0]);
2193
2247
  }
2248
+ function importStepMeshDocument(data, part_name, material, source) {
2249
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
2250
+ const len0 = WASM_VECTOR_LEN;
2251
+ const ptr1 = passStringToWasm0(part_name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2252
+ const len1 = WASM_VECTOR_LEN;
2253
+ const ptr2 = passStringToWasm0(material, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2254
+ const len2 = WASM_VECTOR_LEN;
2255
+ const ptr3 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2256
+ const len3 = WASM_VECTOR_LEN;
2257
+ const ret = wasm.importStepMeshDocument(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
2258
+ if (ret[2]) {
2259
+ throw takeFromExternrefTable0(ret[1]);
2260
+ }
2261
+ return takeFromExternrefTable0(ret[0]);
2262
+ }
2194
2263
  function importUrdfBuffer(data) {
2195
2264
  let deferred3_0;
2196
2265
  let deferred3_1;
@@ -2242,6 +2311,29 @@ function initGpu() {
2242
2311
  const ret = wasm.initGpu();
2243
2312
  return ret;
2244
2313
  }
2314
+ function inlineMeshImports(doc_json, keys, blobs) {
2315
+ let deferred4_0;
2316
+ let deferred4_1;
2317
+ try {
2318
+ const ptr0 = passStringToWasm0(doc_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2319
+ const len0 = WASM_VECTOR_LEN;
2320
+ const ptr1 = passArrayJsValueToWasm0(keys, wasm.__wbindgen_malloc);
2321
+ const len1 = WASM_VECTOR_LEN;
2322
+ const ret = wasm.inlineMeshImports(ptr0, len0, ptr1, len1, blobs);
2323
+ var ptr3 = ret[0];
2324
+ var len3 = ret[1];
2325
+ if (ret[3]) {
2326
+ ptr3 = 0;
2327
+ len3 = 0;
2328
+ throw takeFromExternrefTable0(ret[2]);
2329
+ }
2330
+ deferred4_0 = ptr3;
2331
+ deferred4_1 = len3;
2332
+ return getStringFromWasm0(ptr3, len3);
2333
+ } finally {
2334
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
2335
+ }
2336
+ }
2245
2337
  function inspectDocumentFaces(doc_json) {
2246
2338
  let deferred3_0;
2247
2339
  let deferred3_1;
@@ -3285,6 +3377,33 @@ function solveSketchSegments(segments_json, constraints_json) {
3285
3377
  wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
3286
3378
  }
3287
3379
  }
3380
+ function stepImportDocument(path, solid_indices, part_name, material) {
3381
+ let deferred6_0;
3382
+ let deferred6_1;
3383
+ try {
3384
+ const ptr0 = passStringToWasm0(path, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3385
+ const len0 = WASM_VECTOR_LEN;
3386
+ const ptr1 = passArray32ToWasm0(solid_indices, wasm.__wbindgen_malloc);
3387
+ const len1 = WASM_VECTOR_LEN;
3388
+ const ptr2 = passStringToWasm0(part_name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3389
+ const len2 = WASM_VECTOR_LEN;
3390
+ const ptr3 = passStringToWasm0(material, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3391
+ const len3 = WASM_VECTOR_LEN;
3392
+ const ret = wasm.stepImportDocument(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
3393
+ var ptr5 = ret[0];
3394
+ var len5 = ret[1];
3395
+ if (ret[3]) {
3396
+ ptr5 = 0;
3397
+ len5 = 0;
3398
+ throw takeFromExternrefTable0(ret[2]);
3399
+ }
3400
+ deferred6_0 = ptr5;
3401
+ deferred6_1 = len5;
3402
+ return getStringFromWasm0(ptr5, len5);
3403
+ } finally {
3404
+ wasm.__wbindgen_free(deferred6_0, deferred6_1, 1);
3405
+ }
3406
+ }
3288
3407
  function stepSourceRegistered(path) {
3289
3408
  const ptr0 = passStringToWasm0(path, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3290
3409
  const len0 = WASM_VECTOR_LEN;
@@ -4540,7 +4659,7 @@ function __wbg_get_imports() {
4540
4659
  const a = state0.a;
4541
4660
  state0.a = 0;
4542
4661
  try {
4543
- return wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined_______true_(a, state0.b, arg02, arg12);
4662
+ return wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined_______true_(a, state0.b, arg02, arg12);
4544
4663
  } finally {
4545
4664
  state0.a = a;
4546
4665
  }
@@ -4578,7 +4697,7 @@ function __wbg_get_imports() {
4578
4697
  const a = state0.a;
4579
4698
  state0.a = 0;
4580
4699
  try {
4581
- return wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined_______true_(a, state0.b, arg02, arg12);
4700
+ return wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined_______true_(a, state0.b, arg02, arg12);
4582
4701
  } finally {
4583
4702
  state0.a = a;
4584
4703
  }
@@ -4611,7 +4730,7 @@ function __wbg_get_imports() {
4611
4730
  return ret;
4612
4731
  }, arguments);
4613
4732
  },
4614
- __wbg_now_579c6a705b05378b: function() {
4733
+ __wbg_now_7ea0b064671ccb66: function() {
4615
4734
  const ret = performance.now();
4616
4735
  return ret;
4617
4736
  },
@@ -5368,23 +5487,23 @@ function __wbg_get_imports() {
5368
5487
  }, arguments);
5369
5488
  },
5370
5489
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
5371
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true_);
5490
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true_);
5372
5491
  return ret;
5373
5492
  },
5374
5493
  __wbindgen_generic_0000000000000002: function(arg0, arg1) {
5375
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true_);
5494
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true_);
5376
5495
  return ret;
5377
5496
  },
5378
5497
  __wbindgen_generic_0000000000000003: function(arg0, arg1) {
5379
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_);
5498
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_);
5380
5499
  return ret;
5381
5500
  },
5382
5501
  __wbindgen_generic_0000000000000004: function(arg0, arg1) {
5383
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true__447);
5502
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true__460);
5384
5503
  return ret;
5385
5504
  },
5386
5505
  __wbindgen_generic_0000000000000005: function(arg0, arg1) {
5387
- const ret = makeMutClosure(arg0, arg1, wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true__448);
5506
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true__461);
5388
5507
  return ret;
5389
5508
  },
5390
5509
  __wbindgen_generic_0000000000000006: function(arg0) {
@@ -5458,35 +5577,35 @@ function __wbg_get_imports() {
5458
5577
  "./vcad_kernel_wasm_bg.js": import0
5459
5578
  };
5460
5579
  }
5461
- function wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_(arg0, arg1, arg2) {
5462
- wasm.wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_(arg0, arg1, arg2);
5580
+ function wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_(arg0, arg1, arg2) {
5581
+ wasm.wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuDeviceLostInfo__GpuDeviceLostInfo______true_(arg0, arg1, arg2);
5463
5582
  }
5464
- function wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true_(arg0, arg1, arg2) {
5465
- const ret = wasm.wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___JsValue__core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true_(arg0, arg1, arg2);
5583
+ function wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true_(arg0, arg1, arg2) {
5584
+ const ret = wasm.wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true_(arg0, arg1, arg2);
5466
5585
  if (ret[1]) {
5467
5586
  throw takeFromExternrefTable0(ret[0]);
5468
5587
  }
5469
5588
  }
5470
- function wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true_(arg0, arg1, arg2) {
5471
- const ret = wasm.wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true_(arg0, arg1, arg2);
5589
+ function wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true_(arg0, arg1, arg2) {
5590
+ const ret = wasm.wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true_(arg0, arg1, arg2);
5472
5591
  if (ret[1]) {
5473
5592
  throw takeFromExternrefTable0(ret[0]);
5474
5593
  }
5475
5594
  }
5476
- function wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true__447(arg0, arg1, arg2) {
5477
- const ret = wasm.wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true__447(arg0, arg1, arg2);
5595
+ function wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true__460(arg0, arg1, arg2) {
5596
+ const ret = wasm.wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true__460(arg0, arg1, arg2);
5478
5597
  if (ret[1]) {
5479
5598
  throw takeFromExternrefTable0(ret[0]);
5480
5599
  }
5481
5600
  }
5482
- function wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true__448(arg0, arg1, arg2) {
5483
- const ret = wasm.wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___wasm_bindgen_d8ba3021eaa32f54___sys__JsNullable_wgpu_f894171a91484cea___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_37ee0ce0c4cd57d5___result__Result_____wasm_bindgen_d8ba3021eaa32f54___JsError___true__448(arg0, arg1, arg2);
5601
+ function wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true__461(arg0, arg1, arg2) {
5602
+ const ret = wasm.wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___wasm_bindgen_847cf9dc19a95d2a___sys__JsNullable_wgpu_a24c7b14400eaeda___backend__webgpu__webgpu_sys__gen_GpuError__GpuError___core_f0fd674eaa06beef___result__Result_____wasm_bindgen_847cf9dc19a95d2a___JsError___true__461(arg0, arg1, arg2);
5484
5603
  if (ret[1]) {
5485
5604
  throw takeFromExternrefTable0(ret[0]);
5486
5605
  }
5487
5606
  }
5488
- function wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined_______true_(arg0, arg1, arg2, arg3) {
5489
- wasm.wasm_bindgen_d8ba3021eaa32f54___convert__closures_____invoke___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined___js_sys_7c82484d4a1d6091___Function_fn_wasm_bindgen_d8ba3021eaa32f54___JsValue_____wasm_bindgen_d8ba3021eaa32f54___sys__Undefined_______true_(arg0, arg1, arg2, arg3);
5607
+ function wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined_______true_(arg0, arg1, arg2, arg3) {
5608
+ wasm.wasm_bindgen_847cf9dc19a95d2a___convert__closures_____invoke___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined___js_sys_fd485cc146ff22c1___Function_fn_wasm_bindgen_847cf9dc19a95d2a___JsValue_____wasm_bindgen_847cf9dc19a95d2a___sys__Undefined_______true_(arg0, arg1, arg2, arg3);
5490
5609
  }
5491
5610
  function addToExternrefTable0(obj) {
5492
5611
  const idx = wasm.__externref_table_alloc();
@@ -5865,7 +5984,7 @@ function __vcad_reset_wasm() {
5865
5984
  wasm = void 0;
5866
5985
  wasmModule = void 0;
5867
5986
  }
5868
- var CircuitSim, MdSim, PhysicsSim, RayTracer, SliceResult, SlicerSettings, Solid, WasmAnnotationLayer, WasmCamSettings, WasmDocumentEngine, WasmKeybindings, WasmSketchSession, __wbindgen_enum_GpuAutoLayoutMode, __wbindgen_enum_GpuBufferBindingType, __wbindgen_enum_GpuPowerPreference, __wbindgen_enum_GpuSamplerBindingType, __wbindgen_enum_GpuStorageTextureAccess, __wbindgen_enum_GpuTextureAspect, __wbindgen_enum_GpuTextureDimension, __wbindgen_enum_GpuTextureFormat, __wbindgen_enum_GpuTextureSampleType, __wbindgen_enum_GpuTextureViewDimension, CircuitSimFinalization, MdSimFinalization, PhysicsSimFinalization, RayTracerFinalization, SliceResultFinalization, SlicerSettingsFinalization, SolidFinalization, WasmAnnotationLayerFinalization, WasmCamSettingsFinalization, WasmDocumentEngineFinalization, WasmKeybindingsFinalization, WasmSketchSessionFinalization, CLOSURE_DTORS, cachedDataViewMemory0, cachedFloat32ArrayMemory0, cachedFloat64ArrayMemory0, cachedInt16ArrayMemory0, cachedInt32ArrayMemory0, cachedInt8ArrayMemory0, cachedUint16ArrayMemory0, cachedUint32ArrayMemory0, cachedUint8ArrayMemory0, cachedTextDecoder, MAX_SAFARI_DECODE_BYTES, numBytesDecoded, cachedTextEncoder, WASM_VECTOR_LEN, wasmModule, wasmInstance, wasm;
5987
+ var CircuitSim, IncrementalEvaluator, MdSim, PhysicsSim, RayTracer, SliceResult, SlicerSettings, Solid, WasmAnnotationLayer, WasmCamSettings, WasmDocumentEngine, WasmKeybindings, WasmSketchSession, __wbindgen_enum_GpuAutoLayoutMode, __wbindgen_enum_GpuBufferBindingType, __wbindgen_enum_GpuPowerPreference, __wbindgen_enum_GpuSamplerBindingType, __wbindgen_enum_GpuStorageTextureAccess, __wbindgen_enum_GpuTextureAspect, __wbindgen_enum_GpuTextureDimension, __wbindgen_enum_GpuTextureFormat, __wbindgen_enum_GpuTextureSampleType, __wbindgen_enum_GpuTextureViewDimension, CircuitSimFinalization, IncrementalEvaluatorFinalization, MdSimFinalization, PhysicsSimFinalization, RayTracerFinalization, SliceResultFinalization, SlicerSettingsFinalization, SolidFinalization, WasmAnnotationLayerFinalization, WasmCamSettingsFinalization, WasmDocumentEngineFinalization, WasmKeybindingsFinalization, WasmSketchSessionFinalization, CLOSURE_DTORS, cachedDataViewMemory0, cachedFloat32ArrayMemory0, cachedFloat64ArrayMemory0, cachedInt16ArrayMemory0, cachedInt32ArrayMemory0, cachedInt8ArrayMemory0, cachedUint16ArrayMemory0, cachedUint32ArrayMemory0, cachedUint8ArrayMemory0, cachedTextDecoder, MAX_SAFARI_DECODE_BYTES, numBytesDecoded, cachedTextEncoder, WASM_VECTOR_LEN, wasmModule, wasmInstance, wasm;
5869
5988
  var init_vcad_kernel_wasm = __esm({
5870
5989
  "../kernel-wasm/vcad_kernel_wasm.js"() {
5871
5990
  CircuitSim = class {
@@ -5941,6 +6060,59 @@ var init_vcad_kernel_wasm = __esm({
5941
6060
  }
5942
6061
  };
5943
6062
  if (Symbol.dispose) CircuitSim.prototype[Symbol.dispose] = CircuitSim.prototype.free;
6063
+ IncrementalEvaluator = class {
6064
+ __destroy_into_raw() {
6065
+ const ptr = this.__wbg_ptr;
6066
+ this.__wbg_ptr = 0;
6067
+ IncrementalEvaluatorFinalization.unregister(this);
6068
+ return ptr;
6069
+ }
6070
+ free() {
6071
+ const ptr = this.__destroy_into_raw();
6072
+ wasm.__wbg_incrementalevaluator_free(ptr, 0);
6073
+ }
6074
+ /**
6075
+ * Drop everything carried (the next evaluation is cold).
6076
+ */
6077
+ clear() {
6078
+ wasm.incrementalevaluator_clear(this.__wbg_ptr);
6079
+ }
6080
+ /**
6081
+ * `evaluateDocument`, reusing everything the edit didn't touch.
6082
+ * @param {string} doc_json
6083
+ * @param {boolean} skip_clash_detection
6084
+ * @returns {any}
6085
+ */
6086
+ evaluate(doc_json, skip_clash_detection) {
6087
+ const ptr0 = passStringToWasm0(doc_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
6088
+ const len0 = WASM_VECTOR_LEN;
6089
+ const ret = wasm.incrementalevaluator_evaluate(this.__wbg_ptr, ptr0, len0, skip_clash_detection);
6090
+ if (ret[2]) {
6091
+ throw takeFromExternrefTable0(ret[1]);
6092
+ }
6093
+ return takeFromExternrefTable0(ret[0]);
6094
+ }
6095
+ /**
6096
+ * A fresh evaluator (its first `evaluate` is cold).
6097
+ */
6098
+ constructor() {
6099
+ const ret = wasm.incrementalevaluator_new();
6100
+ this.__wbg_ptr = ret;
6101
+ IncrementalEvaluatorFinalization.register(this, this.__wbg_ptr, this);
6102
+ return this;
6103
+ }
6104
+ /**
6105
+ * `[reusedSolids, evaluatedSolids, reusedMeshes]` from the last evaluation.
6106
+ * @returns {Uint32Array}
6107
+ */
6108
+ stats() {
6109
+ const ret = wasm.incrementalevaluator_stats(this.__wbg_ptr);
6110
+ var v1 = getArrayU32FromWasm0(ret[0], ret[1]).slice();
6111
+ wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
6112
+ return v1;
6113
+ }
6114
+ };
6115
+ if (Symbol.dispose) IncrementalEvaluator.prototype[Symbol.dispose] = IncrementalEvaluator.prototype.free;
5944
6116
  MdSim = class {
5945
6117
  __destroy_into_raw() {
5946
6118
  const ptr = this.__wbg_ptr;
@@ -8030,6 +8202,48 @@ var init_vcad_kernel_wasm = __esm({
8030
8202
  const ret = wasm.wasmdocumentengine_add_feature(this.__wbg_ptr, ptr0, len0);
8031
8203
  return ret;
8032
8204
  }
8205
+ /**
8206
+ * `apply`, answered with an `EngineDeltaEnvelope` (what changed since
8207
+ * the state before the command) instead of the whole document.
8208
+ * @param {string} command_json
8209
+ * @returns {string}
8210
+ */
8211
+ applyDelta(command_json) {
8212
+ let deferred2_0;
8213
+ let deferred2_1;
8214
+ try {
8215
+ const ptr0 = passStringToWasm0(command_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
8216
+ const len0 = WASM_VECTOR_LEN;
8217
+ const ret = wasm.wasmdocumentengine_applyDelta(this.__wbg_ptr, ptr0, len0);
8218
+ deferred2_0 = ret[0];
8219
+ deferred2_1 = ret[1];
8220
+ return getStringFromWasm0(ret[0], ret[1]);
8221
+ } finally {
8222
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
8223
+ }
8224
+ }
8225
+ /**
8226
+ * `apply_tool`, answered with an `EngineDeltaEnvelope`.
8227
+ * @param {string} tool
8228
+ * @param {string} args_json
8229
+ * @returns {string}
8230
+ */
8231
+ applyToolDelta(tool, args_json) {
8232
+ let deferred3_0;
8233
+ let deferred3_1;
8234
+ try {
8235
+ const ptr0 = passStringToWasm0(tool, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
8236
+ const len0 = WASM_VECTOR_LEN;
8237
+ const ptr1 = passStringToWasm0(args_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
8238
+ const len1 = WASM_VECTOR_LEN;
8239
+ const ret = wasm.wasmdocumentengine_applyToolDelta(this.__wbg_ptr, ptr0, len0, ptr1, len1);
8240
+ deferred3_0 = ret[0];
8241
+ deferred3_1 = ret[1];
8242
+ return getStringFromWasm0(ret[0], ret[1]);
8243
+ } finally {
8244
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
8245
+ }
8246
+ }
8033
8247
  /**
8034
8248
  * Apply a JSON `DocCommand` (see `vcad_app::command`). Returns the
8035
8249
  * shared JSON envelope: `{"ok":true,"result":{…}}` or
@@ -8152,6 +8366,27 @@ var init_vcad_kernel_wasm = __esm({
8152
8366
  const ret = wasm.wasmdocumentengine_delete_feature_by_id(this.__wbg_ptr, ptr0, len0);
8153
8367
  return ret;
8154
8368
  }
8369
+ /**
8370
+ * Evaluate this engine's document through `evaluator` without a JSON
8371
+ * round trip: the materialized document never leaves Rust. `overlay_json`
8372
+ * is `{"parameters"?, "bindings"?}` (host-held parameter state, merged
8373
+ * over the document like `mergeParametersIntoDocument`); pass `""` for
8374
+ * none. Returns the same scene shape as `evaluateDocument`.
8375
+ * @param {IncrementalEvaluator} evaluator
8376
+ * @param {string} overlay_json
8377
+ * @param {boolean} skip_clash_detection
8378
+ * @returns {any}
8379
+ */
8380
+ evaluateIncremental(evaluator, overlay_json, skip_clash_detection) {
8381
+ _assertClass(evaluator, IncrementalEvaluator);
8382
+ const ptr0 = passStringToWasm0(overlay_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
8383
+ const len0 = WASM_VECTOR_LEN;
8384
+ const ret = wasm.wasmdocumentengine_evaluateIncremental(this.__wbg_ptr, evaluator.__wbg_ptr, ptr0, len0, skip_clash_detection);
8385
+ if (ret[2]) {
8386
+ throw takeFromExternrefTable0(ret[1]);
8387
+ }
8388
+ return takeFromExternrefTable0(ret[0]);
8389
+ }
8155
8390
  /**
8156
8391
  * Load a legacy v1 JSON document and migrate to CRDT.
8157
8392
  * @param {string} json
@@ -8466,6 +8701,23 @@ var init_vcad_kernel_wasm = __esm({
8466
8701
  const ret = wasm.wasmdocumentengine_set_visible(this.__wbg_ptr, ptr0, len0, visible);
8467
8702
  return ret;
8468
8703
  }
8704
+ /**
8705
+ * The current state as a full-document envelope (always `ok`) — the
8706
+ * base a host applies deltas to.
8707
+ * @returns {string}
8708
+ */
8709
+ stateEnvelope() {
8710
+ let deferred1_0;
8711
+ let deferred1_1;
8712
+ try {
8713
+ const ret = wasm.wasmdocumentengine_stateEnvelope(this.__wbg_ptr);
8714
+ deferred1_0 = ret[0];
8715
+ deferred1_1 = ret[1];
8716
+ return getStringFromWasm0(ret[0], ret[1]);
8717
+ } finally {
8718
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
8719
+ }
8720
+ }
8469
8721
  /**
8470
8722
  * Deterministic state fingerprint; matches `vcad_engine_state_hash`.
8471
8723
  * @returns {string}
@@ -8909,6 +9161,9 @@ var init_vcad_kernel_wasm = __esm({
8909
9161
  CircuitSimFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
8910
9162
  }, unregister: () => {
8911
9163
  } } : new FinalizationRegistry((ptr) => wasm.__wbg_circuitsim_free(ptr, 1));
9164
+ IncrementalEvaluatorFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
9165
+ }, unregister: () => {
9166
+ } } : new FinalizationRegistry((ptr) => wasm.__wbg_incrementalevaluator_free(ptr, 1));
8912
9167
  MdSimFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
8913
9168
  }, unregister: () => {
8914
9169
  } } : new FinalizationRegistry((ptr) => wasm.__wbg_mdsim_free(ptr, 1));
@@ -11039,9 +11294,9 @@ function workerTransport(worker) {
11039
11294
  pending2.delete(id);
11040
11295
  });
11041
11296
  return {
11042
- request: (req) => new Promise((resolve7) => {
11297
+ request: (req) => new Promise((resolve8) => {
11043
11298
  const id = next++;
11044
- pending2.set(id, resolve7);
11299
+ pending2.set(id, resolve8);
11045
11300
  worker.postMessage({ id, req });
11046
11301
  }),
11047
11302
  dispose: () => worker.terminate()
@@ -11920,11 +12175,11 @@ var init_analyze = __esm({
11920
12175
  type: "module"
11921
12176
  });
11922
12177
  this.worker = worker;
11923
- this.ready = new Promise((resolve7, reject) => {
12178
+ this.ready = new Promise((resolve8, reject) => {
11924
12179
  const onMessage = (e) => {
11925
12180
  const { type, id, message, analysis } = e.data;
11926
12181
  if (type === "ready") {
11927
- resolve7();
12182
+ resolve8();
11928
12183
  return;
11929
12184
  }
11930
12185
  if (type === "error" && id === null) {
@@ -11948,9 +12203,9 @@ var init_analyze = __esm({
11948
12203
  return this.ready;
11949
12204
  }
11950
12205
  request(msg, transfer = []) {
11951
- return this.ensureWorker().then(() => new Promise((resolve7, reject) => {
12206
+ return this.ensureWorker().then(() => new Promise((resolve8, reject) => {
11952
12207
  const id = this.nextId++;
11953
- this.pending.set(id, { resolve: resolve7, reject });
12208
+ this.pending.set(id, { resolve: resolve8, reject });
11954
12209
  this.worker.postMessage({ ...msg, id }, transfer);
11955
12210
  }));
11956
12211
  }
@@ -12567,11 +12822,11 @@ var init_dist = __esm({
12567
12822
  return;
12568
12823
  try {
12569
12824
  const worker = new Worker(new URL("./eval-worker.js", import.meta.url), { type: "module" });
12570
- this.workerReady = new Promise((resolve7, reject) => {
12825
+ this.workerReady = new Promise((resolve8, reject) => {
12571
12826
  const onMessage = (e) => {
12572
12827
  if (e.data.type === "ready") {
12573
12828
  worker.removeEventListener("message", onMessage);
12574
- resolve7();
12829
+ resolve8();
12575
12830
  } else if (e.data.type === "error" && e.data.id === null) {
12576
12831
  worker.removeEventListener("message", onMessage);
12577
12832
  console.warn("[ENGINE] Worker WASM init failed:", e.data.message);
@@ -12794,7 +13049,7 @@ var init_dist = __esm({
12794
13049
  const worker = this.worker;
12795
13050
  const id = Math.random().toString(36).slice(2);
12796
13051
  const skipClash = options.skipClashDetection ?? false;
12797
- return new Promise((resolve7, reject) => {
13052
+ return new Promise((resolve8, reject) => {
12798
13053
  const onMessage = (e) => {
12799
13054
  if (e.data.id !== id)
12800
13055
  return;
@@ -12804,7 +13059,7 @@ var init_dist = __esm({
12804
13059
  if (scene.timing && _Engine.DEV) {
12805
13060
  _Engine.logTiming(scene.timing, e.data.workerTotalMs);
12806
13061
  }
12807
- resolve7(scene);
13062
+ resolve8(scene);
12808
13063
  } else if (e.data.type === "error") {
12809
13064
  reject(new Error(e.data.message));
12810
13065
  }
@@ -19237,12 +19492,12 @@ var init_stdio2 = __esm({
19237
19492
  this.onclose?.();
19238
19493
  }
19239
19494
  send(message) {
19240
- return new Promise((resolve7) => {
19495
+ return new Promise((resolve8) => {
19241
19496
  const json = serializeMessage(message);
19242
19497
  if (this._stdout.write(json)) {
19243
- resolve7();
19498
+ resolve8();
19244
19499
  } else {
19245
- this._stdout.once("drain", resolve7);
19500
+ this._stdout.once("drain", resolve8);
19246
19501
  }
19247
19502
  });
19248
19503
  }
@@ -20286,7 +20541,7 @@ var init_protocol = __esm({
20286
20541
  return;
20287
20542
  }
20288
20543
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
20289
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
20544
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
20290
20545
  options?.signal?.throwIfAborted();
20291
20546
  }
20292
20547
  } catch (error2) {
@@ -20303,7 +20558,7 @@ var init_protocol = __esm({
20303
20558
  */
20304
20559
  request(request, resultSchema, options) {
20305
20560
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
20306
- return new Promise((resolve7, reject) => {
20561
+ return new Promise((resolve8, reject) => {
20307
20562
  const earlyReject = (error2) => {
20308
20563
  reject(error2);
20309
20564
  };
@@ -20381,7 +20636,7 @@ var init_protocol = __esm({
20381
20636
  if (!parseResult.success) {
20382
20637
  reject(parseResult.error);
20383
20638
  } else {
20384
- resolve7(parseResult.data);
20639
+ resolve8(parseResult.data);
20385
20640
  }
20386
20641
  } catch (error2) {
20387
20642
  reject(error2);
@@ -20642,12 +20897,12 @@ var init_protocol = __esm({
20642
20897
  }
20643
20898
  } catch {
20644
20899
  }
20645
- return new Promise((resolve7, reject) => {
20900
+ return new Promise((resolve8, reject) => {
20646
20901
  if (signal.aborted) {
20647
20902
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
20648
20903
  return;
20649
20904
  }
20650
- const timeoutId = setTimeout(resolve7, interval);
20905
+ const timeoutId = setTimeout(resolve8, interval);
20651
20906
  signal.addEventListener("abort", () => {
20652
20907
  clearTimeout(timeoutId);
20653
20908
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -23674,7 +23929,7 @@ var require_compile = __commonJS({
23674
23929
  const schOrFunc = root.refs[ref];
23675
23930
  if (schOrFunc)
23676
23931
  return schOrFunc;
23677
- let _sch = resolve7.call(this, root, ref);
23932
+ let _sch = resolve8.call(this, root, ref);
23678
23933
  if (_sch === void 0) {
23679
23934
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
23680
23935
  const { schemaId } = this.opts;
@@ -23701,7 +23956,7 @@ var require_compile = __commonJS({
23701
23956
  function sameSchemaEnv(s1, s2) {
23702
23957
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
23703
23958
  }
23704
- function resolve7(root, ref) {
23959
+ function resolve8(root, ref) {
23705
23960
  let sch;
23706
23961
  while (typeof (sch = this.refs[ref]) == "string")
23707
23962
  ref = sch;
@@ -24276,7 +24531,7 @@ var require_fast_uri = __commonJS({
24276
24531
  }
24277
24532
  return uri;
24278
24533
  }
24279
- function resolve7(baseURI, relativeURI, options) {
24534
+ function resolve8(baseURI, relativeURI, options) {
24280
24535
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
24281
24536
  const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
24282
24537
  schemelessOptions.skipEscape = true;
@@ -24503,7 +24758,7 @@ var require_fast_uri = __commonJS({
24503
24758
  var fastUri = {
24504
24759
  SCHEMES,
24505
24760
  normalize: normalize2,
24506
- resolve: resolve7,
24761
+ resolve: resolve8,
24507
24762
  resolveComponent,
24508
24763
  equal,
24509
24764
  serialize,
@@ -30675,21 +30930,21 @@ var require_react_development = __commonJS({
30675
30930
  );
30676
30931
  actScopeDepth = prevActScopeDepth;
30677
30932
  }
30678
- function recursivelyFlushAsyncActWork(returnValue, resolve7, reject) {
30933
+ function recursivelyFlushAsyncActWork(returnValue, resolve8, reject) {
30679
30934
  var queue = ReactSharedInternals.actQueue;
30680
30935
  if (null !== queue)
30681
30936
  if (0 !== queue.length)
30682
30937
  try {
30683
30938
  flushActQueue(queue);
30684
30939
  enqueueTask(function() {
30685
- return recursivelyFlushAsyncActWork(returnValue, resolve7, reject);
30940
+ return recursivelyFlushAsyncActWork(returnValue, resolve8, reject);
30686
30941
  });
30687
30942
  return;
30688
30943
  } catch (error2) {
30689
30944
  ReactSharedInternals.thrownErrors.push(error2);
30690
30945
  }
30691
30946
  else ReactSharedInternals.actQueue = null;
30692
- 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve7(returnValue);
30947
+ 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve8(returnValue);
30693
30948
  }
30694
30949
  function flushActQueue(queue) {
30695
30950
  if (!isFlushing) {
@@ -30876,7 +31131,7 @@ var require_react_development = __commonJS({
30876
31131
  ));
30877
31132
  });
30878
31133
  return {
30879
- then: function(resolve7, reject) {
31134
+ then: function(resolve8, reject) {
30880
31135
  didAwaitActCall = true;
30881
31136
  thenable.then(
30882
31137
  function(returnValue) {
@@ -30886,7 +31141,7 @@ var require_react_development = __commonJS({
30886
31141
  flushActQueue(queue), enqueueTask(function() {
30887
31142
  return recursivelyFlushAsyncActWork(
30888
31143
  returnValue,
30889
- resolve7,
31144
+ resolve8,
30890
31145
  reject
30891
31146
  );
30892
31147
  });
@@ -30900,7 +31155,7 @@ var require_react_development = __commonJS({
30900
31155
  ReactSharedInternals.thrownErrors.length = 0;
30901
31156
  reject(_thrownError);
30902
31157
  }
30903
- } else resolve7(returnValue);
31158
+ } else resolve8(returnValue);
30904
31159
  },
30905
31160
  function(error2) {
30906
31161
  popActScope(prevActQueue, prevActScopeDepth);
@@ -30922,15 +31177,15 @@ var require_react_development = __commonJS({
30922
31177
  if (0 < ReactSharedInternals.thrownErrors.length)
30923
31178
  throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
30924
31179
  return {
30925
- then: function(resolve7, reject) {
31180
+ then: function(resolve8, reject) {
30926
31181
  didAwaitActCall = true;
30927
31182
  0 === prevActScopeDepth ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
30928
31183
  return recursivelyFlushAsyncActWork(
30929
31184
  returnValue$jscomp$0,
30930
- resolve7,
31185
+ resolve8,
30931
31186
  reject
30932
31187
  );
30933
- })) : resolve7(returnValue$jscomp$0);
31188
+ })) : resolve8(returnValue$jscomp$0);
30934
31189
  }
30935
31190
  };
30936
31191
  };
@@ -41804,9 +42059,90 @@ var init_CHANGELOG = __esm({
41804
42059
  CHANGELOG_default = {
41805
42060
  $schema: "./changelog.schema.json",
41806
42061
  entries: [
42062
+ {
42063
+ id: "2026-11-07-native-assembly-authoring",
42064
+ version: "0.11.0",
42065
+ date: "2026-11-07",
42066
+ category: "feat",
42067
+ title: "Mac app: assembly, joint, mate and keyframe authoring",
42068
+ summary: "Insert instances, add and edit all five joint kinds with picked anchors, check mates, drag joints via FK, and author keyframes with a timeline that exports video.",
42069
+ features: [
42070
+ "assembly",
42071
+ "joints",
42072
+ "mates",
42073
+ "animation",
42074
+ "native-app"
42075
+ ]
42076
+ },
42077
+ {
42078
+ id: "2026-11-06-native-dfm-fea-clearance",
42079
+ version: "0.11.0",
42080
+ date: "2026-11-06",
42081
+ category: "feat",
42082
+ title: "DFM, stress and clearance in the Mac app",
42083
+ summary: "New Analyze panel in the native app: DFM with one-click undoable fixes, in-process FEA on picked faces with stress overlays, and part interference volumes \u2014 also exposed to agents over the app's MCP server.",
42084
+ features: [
42085
+ "dfm",
42086
+ "fea",
42087
+ "clearance",
42088
+ "native-app",
42089
+ "vcad-2"
42090
+ ],
42091
+ mcpTools: [
42092
+ "dfm_check",
42093
+ "dfm_apply_fix",
42094
+ "analyze_structure",
42095
+ "check_interference",
42096
+ "inspect_faces"
42097
+ ]
42098
+ },
42099
+ {
42100
+ id: "2026-11-06-export-all-documents",
42101
+ version: "0.11.0",
42102
+ date: "2026-11-06",
42103
+ category: "feat",
42104
+ title: "Export all your documents as a zip",
42105
+ summary: "New /export page downloads every cloud document (and this browser's local ones) as .vcad files in one zip, ahead of the move to the vcad 2 Mac app.",
42106
+ features: [
42107
+ "export",
42108
+ "cloud-sync",
42109
+ "vcad-2"
42110
+ ],
42111
+ mcpTools: [
42112
+ "open_in_app",
42113
+ "open_in_browser"
42114
+ ]
42115
+ },
42116
+ {
42117
+ id: "2026-10-28-render-timings-perf",
42118
+ version: "0.11.0",
42119
+ date: "2026-10-28",
42120
+ category: "perf",
42121
+ title: "Faster assembly renders, plus a --timings breakdown",
42122
+ summary: "Assembly renders evaluate parts in parallel, never evaluate a part twice, and serve warm re-renders straight from the cache (rose full body 613 s -> 55 s cold, 330 s -> 6 s warm); --timings shows where time goes.",
42123
+ features: [
42124
+ "render",
42125
+ "performance",
42126
+ "cli"
42127
+ ],
42128
+ mcpTools: []
42129
+ },
42130
+ {
42131
+ id: "2026-10-27-sphere-cube-seams",
42132
+ version: "0.11.0",
42133
+ date: "2026-10-27",
42134
+ category: "fix",
42135
+ title: "Clean sphere/box boolean seams at every resolution",
42136
+ summary: "Sphere-box unions, differences and intersections no longer grow jagged seams, slivers or lose volume depending on segment count; sphere patches are split and tessellated exactly.",
42137
+ features: [
42138
+ "booleans",
42139
+ "tessellation"
42140
+ ],
42141
+ mcpTools: []
42142
+ },
41807
42143
  {
41808
42144
  id: "2026-10-27-section-hatch-all-loops",
41809
- version: "0.10.0",
42145
+ version: "0.11.0",
41810
42146
  date: "2026-10-27",
41811
42147
  category: "fix",
41812
42148
  title: "Section views hatch every cut region",
@@ -41817,6 +42153,32 @@ var init_CHANGELOG = __esm({
41817
42153
  ],
41818
42154
  mcpTools: []
41819
42155
  },
42156
+ {
42157
+ id: "2026-10-27-onshape-step-import",
42158
+ version: "0.11.0",
42159
+ date: "2026-10-27",
42160
+ category: "fix",
42161
+ title: "STEP import: Onshape files import and render solid",
42162
+ summary: "Reads BREP_WITH_VOIDS, honours metre units, walks same_sense=.F. edges the right way, and meshes seamless cylinder/cone walls, drill tips and reversed planes facing outward.",
42163
+ features: [
42164
+ "step-import",
42165
+ "tessellation",
42166
+ "render"
42167
+ ]
42168
+ },
42169
+ {
42170
+ id: "2026-10-27-exact-render-step-curved-faces",
42171
+ version: "0.11.0",
42172
+ date: "2026-10-27",
42173
+ category: "fix",
42174
+ title: "Exact render shows curved faces of imported STEP parts",
42175
+ summary: "vcad-render --photoreal --exact no longer drops the cylinder, cone, sphere and torus faces of Onshape STEP imports, and frames them like the mesh render.",
42176
+ features: [
42177
+ "render",
42178
+ "raytrace",
42179
+ "step-import"
42180
+ ]
42181
+ },
41820
42182
  {
41821
42183
  id: "2026-10-27-cargo-install-vcad-cli",
41822
42184
  version: "0.11.0",
@@ -56840,8 +57202,8 @@ async function openBridge(createServer2, clientInfo, clientCapabilities, hooks)
56840
57202
  await server.connect(serverSide);
56841
57203
  const rpc = (method, params) => {
56842
57204
  const id = nextId3++;
56843
- return new Promise((resolve7) => {
56844
- pending2.set(id, (m) => resolve7(m));
57205
+ return new Promise((resolve8) => {
57206
+ pending2.set(id, (m) => resolve8(m));
56845
57207
  void clientSide.send({
56846
57208
  jsonrpc: "2.0",
56847
57209
  id,
@@ -57178,8 +57540,8 @@ function taskElicitation(bridge, reqParams) {
57178
57540
  method: "elicitation/create",
57179
57541
  params: cleanParams
57180
57542
  };
57181
- return new Promise((resolve7) => {
57182
- record2.pendingInputs.set(key3, resolve7);
57543
+ return new Promise((resolve8) => {
57544
+ record2.pendingInputs.set(key3, resolve8);
57183
57545
  touchTask(record2, "input_required", "waiting for client input");
57184
57546
  });
57185
57547
  }
@@ -57204,11 +57566,11 @@ function handleTaskMethod(id, method, params) {
57204
57566
  if (method === "tasks/update") {
57205
57567
  const responses = params.inputResponses && typeof params.inputResponses === "object" ? params.inputResponses : {};
57206
57568
  for (const [key3, response] of Object.entries(responses)) {
57207
- const resolve7 = record2.pendingInputs.get(key3);
57208
- if (!resolve7) continue;
57569
+ const resolve8 = record2.pendingInputs.get(key3);
57570
+ if (!resolve8) continue;
57209
57571
  record2.pendingInputs.delete(key3);
57210
57572
  delete record2.inputRequests[key3];
57211
- resolve7(response);
57573
+ resolve8(response);
57212
57574
  }
57213
57575
  if (record2.status === "input_required" && Object.keys(record2.inputRequests).length === 0) {
57214
57576
  touchTask(record2, "working", `running ${record2.toolName}`);
@@ -57220,10 +57582,10 @@ function handleTaskMethod(id, method, params) {
57220
57582
  }
57221
57583
  record2.cancelRequested = true;
57222
57584
  if (record2.status === "working" || record2.status === "input_required") {
57223
- for (const [key3, resolve7] of record2.pendingInputs) {
57585
+ for (const [key3, resolve8] of record2.pendingInputs) {
57224
57586
  record2.pendingInputs.delete(key3);
57225
57587
  delete record2.inputRequests[key3];
57226
- resolve7({ action: "cancel" });
57588
+ resolve8({ action: "cancel" });
57227
57589
  }
57228
57590
  touchTask(record2, "cancelled", "cancelled by client");
57229
57591
  }
@@ -57860,7 +58222,8 @@ var init_tool_metadata = __esm({
57860
58222
  import_altium: { title: "Import Altium", annotations: RW },
57861
58223
  import_altium_library: { title: "Import Altium Library", annotations: RO },
57862
58224
  import_eagle: { title: "Import EAGLE", annotations: RW },
57863
- open_in_browser: { title: "Open in Browser", annotations: RW },
58225
+ open_in_app: { title: "Open in vcad", annotations: RW },
58226
+ open_in_browser: { title: "Open in vcad (legacy name)", annotations: RW },
57864
58227
  // ── Physics gym ────────────────────────────────────────────────────────
57865
58228
  create_robot_env: { title: "Create Robot Env", annotations: RW },
57866
58229
  gym_step: { title: "Gym Step", annotations: RW },
@@ -58099,7 +58462,7 @@ function normalizeOp(op, index) {
58099
58462
  return { name, args };
58100
58463
  }
58101
58464
  function resolveSymbolicRefs(args, createdIds, index) {
58102
- const resolve7 = (v) => {
58465
+ const resolve8 = (v) => {
58103
58466
  if (typeof v !== "string") return v;
58104
58467
  const m = SYMBOLIC_REF.exec(v);
58105
58468
  if (!m) return v;
@@ -58119,15 +58482,15 @@ function resolveSymbolicRefs(args, createdIds, index) {
58119
58482
  };
58120
58483
  const out = { ...args };
58121
58484
  for (const key3 of ["part_id", "node_id"]) {
58122
- if (key3 in out) out[key3] = resolve7(out[key3]);
58485
+ if (key3 in out) out[key3] = resolve8(out[key3]);
58123
58486
  }
58124
58487
  if (out.params && typeof out.params === "object" && !Array.isArray(out.params)) {
58125
58488
  const params = { ...out.params };
58126
58489
  for (const key3 of ["child", "left", "right", "sketch"]) {
58127
- if (key3 in params) params[key3] = resolve7(params[key3]);
58490
+ if (key3 in params) params[key3] = resolve8(params[key3]);
58128
58491
  }
58129
58492
  if (Array.isArray(params.sketches)) {
58130
- params.sketches = params.sketches.map(resolve7);
58493
+ params.sketches = params.sketches.map(resolve8);
58131
58494
  }
58132
58495
  out.params = params;
58133
58496
  }
@@ -64060,7 +64423,7 @@ async function flattenSchematic(sheet, netlister) {
64060
64423
  if (def.body.hierarchy) {
64061
64424
  err9(`Sheet '${def.name}' body has its own hierarchy \u2014 nest sheets with \`instances\` instead (ignored)`);
64062
64425
  }
64063
- const resolve7 = (name) => {
64426
+ const resolve8 = (name) => {
64064
64427
  if (ports.has(name)) {
64065
64428
  const bound = binding.get(name);
64066
64429
  if (bound !== void 0) return bound;
@@ -64088,7 +64451,7 @@ async function flattenSchematic(sheet, netlister) {
64088
64451
  if (pins.length === 0) continue;
64089
64452
  if (isAutoName(name) && pins.length < 2) continue;
64090
64453
  usedNames.add(name);
64091
- const flat = resolve7(name);
64454
+ const flat = resolve8(name);
64092
64455
  if (!ports.has(name) && !globals.has(name) && rootNames.has(flat)) {
64093
64456
  err9(
64094
64457
  `Net scope collision: local net '${name}' of sheet instance '${path}' flattens to '${flat}', which the root sheet also uses`
@@ -64112,9 +64475,9 @@ async function flattenSchematic(sheet, netlister) {
64112
64475
  warn(`Hierarchical port '${port}' of sheet '${def.name}' connects to nothing inside the sheet`);
64113
64476
  }
64114
64477
  }
64115
- for (const flag of def.body.power_flags ?? []) outFlags.push({ ...flag, net: resolve7(flag.net) });
64478
+ for (const flag of def.body.power_flags ?? []) outFlags.push({ ...flag, net: resolve8(flag.net) });
64116
64479
  instances.push({ path, sheet: def.name, refs });
64117
- await elaborateAll(def.instances ?? [], path, offset, resolve7, stack);
64480
+ await elaborateAll(def.instances ?? [], path, offset, resolve8, stack);
64118
64481
  };
64119
64482
  await elaborateAll(h.instances ?? [], "", { x: 0, y: 0 }, (n) => n, []);
64120
64483
  const nets = {};
@@ -81687,7 +82050,7 @@ function resolveMeshPath(filename, urdfDir, packageRoots, confineRoot) {
81687
82050
  if (urdfDir) return confined(resolve6(urdfDir, stripped));
81688
82051
  return null;
81689
82052
  }
81690
- function inlineMeshImports(doc, engine, urdfDir, packageRoots, confineRoot) {
82053
+ function inlineMeshImports2(doc, engine, urdfDir, packageRoots, confineRoot) {
81691
82054
  const unresolved = [];
81692
82055
  const meshes = /* @__PURE__ */ new Map();
81693
82056
  const refs = /* @__PURE__ */ new Map();
@@ -81775,7 +82138,7 @@ function importUrdf(input, engine) {
81775
82138
  })
81776
82139
  );
81777
82140
  const commentedFloating = floating_base ? void 0 : engine.urdfCommentedFloatingJoint(arrayBuffer);
81778
- const meshes = inlineMeshImports(doc, engine, urdfDir, packageRoots, confineRoot);
82141
+ const meshes = inlineMeshImports2(doc, engine, urdfDir, packageRoots, confineRoot);
81779
82142
  const robotName = name ?? basename2(sourceLabel).replace(/\.(urdf|xml)$/i, "");
81780
82143
  const parts = Object.values(doc.partDefs ?? {}).map((p) => ({
81781
82144
  id: p.id,
@@ -82277,6 +82640,8 @@ var init_import_pcb = __esm({
82277
82640
 
82278
82641
  // src/tools/share.ts
82279
82642
  import { gzipSync } from "node:zlib";
82643
+ import * as os2 from "node:os";
82644
+ import * as nodePath2 from "node:path";
82280
82645
  function validateAppUrl(raw) {
82281
82646
  try {
82282
82647
  const url = new URL(raw);
@@ -82308,56 +82673,75 @@ function compressForUrl(compact2) {
82308
82673
  const compressed = gzipSync(Buffer.from(compact2, "utf-8"), { level: 9 });
82309
82674
  return base64urlEncode(compressed);
82310
82675
  }
82311
- function openInBrowser(input, engine) {
82312
- const { document_id, document: docInput, name } = input;
82313
- if (!document_id && !docInput) {
82314
- throw new Error(
82315
- "Pass `document_id` (a live session) or `document` (inline IR)."
82316
- );
82676
+ function buildAppLink(doc, opts = {}) {
82677
+ const params = new URLSearchParams();
82678
+ const fileStore = opts.fileStore ?? useFileSessionStore();
82679
+ let via;
82680
+ if (opts.documentId && fileStore && SESSION_ID_RE.test(opts.documentId)) {
82681
+ params.set("session", opts.documentId);
82682
+ const dir = sessionDir();
82683
+ const defaultDir = nodePath2.join(os2.homedir(), ".vcad", "mcp-sessions");
82684
+ if (nodePath2.resolve(dir) !== nodePath2.resolve(defaultDir)) {
82685
+ params.set("dir", dir);
82686
+ }
82687
+ via = "session";
82688
+ } else {
82689
+ params.set("doc", compressForUrl(JSON.stringify(doc)));
82690
+ via = "inline";
82317
82691
  }
82318
- const live = document_id ? getSession(document_id) : parseDocument(docInput);
82319
- const doc = engine ? engine.bakeStepImports(live) : live;
82692
+ if (opts.name) params.set("name", opts.name);
82693
+ return { url: `vcad://open?${params.toString()}`, via };
82694
+ }
82695
+ function legacyWebLink(doc, name) {
82320
82696
  let payload;
82321
- let format;
82322
82697
  try {
82323
82698
  payload = toVCode2(doc);
82324
- format = "vcode";
82325
82699
  } catch {
82326
82700
  payload = JSON.stringify(doc);
82327
- format = "json";
82328
82701
  }
82329
- const encoded = compressForUrl(payload);
82330
82702
  const baseUrl = validateAppUrl(process.env.VCAD_APP_URL || "https://vcad.io");
82331
82703
  const params = new URLSearchParams();
82332
- params.set("doc", encoded);
82333
- if (name) {
82334
- params.set("name", name);
82704
+ params.set("doc", compressForUrl(payload));
82705
+ if (name) params.set("name", name);
82706
+ return `${baseUrl}/#/new?${params.toString()}`;
82707
+ }
82708
+ function openInApp(input, engine) {
82709
+ const { document_id, document: docInput, name } = input;
82710
+ if (!document_id && !docInput) {
82711
+ throw new Error(
82712
+ "Pass `document_id` (a live session) or `document` (inline IR)."
82713
+ );
82335
82714
  }
82336
- const url = `${baseUrl}/#/new?${params.toString()}`;
82337
- const urlLength = url.length;
82338
- const warning = urlLength > 2e3 ? `
82339
-
82340
- Warning: URL is ${urlLength} characters. Some browsers may truncate URLs over ~2000 characters. Consider exporting to a file instead for larger documents.` : "";
82341
- return {
82342
- content: [
82343
- {
82344
- type: "text",
82345
- text: `Open in vcad.io:
82346
- ${url}${warning}
82347
-
82348
- Payload (${format}): ${payload.length} bytes
82349
- Compressed URL param: ${encoded.length} bytes`
82350
- }
82351
- ]
82352
- };
82715
+ const live = document_id ? getSession(document_id) : parseDocument(docInput);
82716
+ const doc = engine ? engine.bakeStepImports(live) : live;
82717
+ const baked = doc !== live;
82718
+ const link = buildAppLink(doc, {
82719
+ documentId: baked ? void 0 : document_id,
82720
+ name
82721
+ });
82722
+ const lines = [
82723
+ `Open in vcad:
82724
+ ${link.url}`,
82725
+ "",
82726
+ `Don't have the vcad app? Download it: ${VCAD_DOWNLOAD_URL}`,
82727
+ link.via === "session" ? `(Link carries session id ${document_id}; the app reads it from this machine's session store, so it works on the machine running this MCP server.)` : `(Document embedded in the link: ${link.url.length} characters.)`
82728
+ ];
82729
+ if (/^(1|true|on)$/i.test(process.env.VCAD_LEGACY_WEB_LINKS || "")) {
82730
+ lines.push("", `Legacy web link (vcad.io, retiring):
82731
+ ${legacyWebLink(doc, name)}`);
82732
+ }
82733
+ return { content: [{ type: "text", text: lines.join("\n") }] };
82353
82734
  }
82354
- var openInBrowserSchema, toolDefs49;
82735
+ var VCAD_DOWNLOAD_URL, SESSION_ID_RE, openInBrowserSchema, DESCRIPTION, toolDefs49;
82355
82736
  var init_share = __esm({
82356
82737
  "src/tools/share.ts"() {
82357
82738
  "use strict";
82358
82739
  init_dist2();
82359
82740
  init_tool_def();
82360
82741
  init_session_core();
82742
+ init_session_store();
82743
+ VCAD_DOWNLOAD_URL = "https://vcad.io/download";
82744
+ SESSION_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
82361
82745
  openInBrowserSchema = {
82362
82746
  type: "object",
82363
82747
  properties: {
@@ -82375,13 +82759,22 @@ var init_share = __esm({
82375
82759
  }
82376
82760
  }
82377
82761
  };
82762
+ DESCRIPTION = "Open a CAD document in the native vcad app via a `vcad://` deep link. Pass a live session's `document_id` (the usual ship path), or an inline IR `document` (JSON or VCode format). Local sessions travel by id; otherwise the document is embedded (gzip + base64url). The result also carries the vcad download page as the fallback for users without the app.";
82378
82763
  toolDefs49 = [
82764
+ {
82765
+ name: "open_in_app",
82766
+ pack: null,
82767
+ description: DESCRIPTION,
82768
+ inputSchema: openInBrowserSchema,
82769
+ handler: (a, c) => openInApp(a, c.engine),
82770
+ behavior: behavior({})
82771
+ },
82379
82772
  {
82380
82773
  name: "open_in_browser",
82381
82774
  pack: null,
82382
- description: "Generate a shareable URL to open a CAD document in vcad.io. Pass a live session's `document_id` (the usual ship path), or an inline IR `document` (JSON or VCode format). Documents are compressed (gzip + base64url) for URL embedding. Note: Very large documents may exceed URL length limits (~2KB).",
82775
+ description: "Legacy alias of `open_in_app` (the vcad.io web editor is retiring). " + DESCRIPTION,
82383
82776
  inputSchema: openInBrowserSchema,
82384
- handler: (a, c) => openInBrowser(a, c.engine),
82777
+ handler: (a, c) => openInApp(a, c.engine),
82385
82778
  behavior: behavior({})
82386
82779
  }
82387
82780
  ];
@@ -85791,13 +86184,13 @@ ${issues.map((i) => i.problem).join("\n")}`
85791
86184
  }
85792
86185
  async function hasFfmpeg() {
85793
86186
  if (ffmpegAvailable !== null) return ffmpegAvailable;
85794
- ffmpegAvailable = await new Promise((resolve7) => {
86187
+ ffmpegAvailable = await new Promise((resolve8) => {
85795
86188
  try {
85796
86189
  const p = spawn("ffmpeg", ["-version"], { stdio: "ignore" });
85797
- p.on("error", () => resolve7(false));
85798
- p.on("exit", (code) => resolve7(code === 0));
86190
+ p.on("error", () => resolve8(false));
86191
+ p.on("exit", (code) => resolve8(code === 0));
85799
86192
  } catch {
85800
- resolve7(false);
86193
+ resolve8(false);
85801
86194
  }
85802
86195
  });
85803
86196
  return ffmpegAvailable;
@@ -85836,13 +86229,13 @@ function startMp4Encoder(width, height, fps) {
85836
86229
  const exitError = (code) => new Error(
85837
86230
  `ffmpeg exited ${code}: ${Buffer.concat(errChunks).toString().slice(-400)}`
85838
86231
  );
85839
- const done = new Promise((resolve7, reject) => {
86232
+ const done = new Promise((resolve8, reject) => {
85840
86233
  p.on("error", (e) => {
85841
86234
  failure = e;
85842
86235
  reject(e);
85843
86236
  });
85844
86237
  p.on("close", (code) => {
85845
- if (code === 0) resolve7(Buffer.concat(out));
86238
+ if (code === 0) resolve8(Buffer.concat(out));
85846
86239
  else {
85847
86240
  failure ??= exitError(code);
85848
86241
  reject(failure);
@@ -85853,15 +86246,15 @@ function startMp4Encoder(width, height, fps) {
85853
86246
  });
85854
86247
  return {
85855
86248
  writeFrame(rgba) {
85856
- return new Promise((resolve7, reject) => {
86249
+ return new Promise((resolve8, reject) => {
85857
86250
  if (failure) return reject(failure);
85858
86251
  if (p.exitCode !== null || p.stdin.destroyed) {
85859
86252
  return reject(failure ?? exitError(p.exitCode));
85860
86253
  }
85861
- if (p.stdin.write(rgba)) return resolve7();
86254
+ if (p.stdin.write(rgba)) return resolve8();
85862
86255
  const onDrain = () => {
85863
86256
  p.removeListener("close", onClose);
85864
- resolve7();
86257
+ resolve8();
85865
86258
  };
85866
86259
  const onClose = () => {
85867
86260
  p.stdin.removeListener("drain", onDrain);
@@ -86403,7 +86796,7 @@ function buildInstructions(kernelPrompt) {
86403
86796
  "Workflow: `open_document` \u2192 author \u2192 see \u2192 measure \u2192 ship.",
86404
86797
  "- Author whole parts with `create_cad_loon` (the full modeling vocabulary in one call); make surgical edits with `create`/`update`/`delete` (one node per call \u2014 mutation results report a compact `changed` diff of affected parts).",
86405
86798
  "- See your work with `render_view` (isometric PNG); measure with `inspect_cad` (whole-document volume, area, bbox, center of mass), `inspect_part` / `describe_scene` (per-part bbox, size, center, material), and `measure` (min distance/overlap between two parts, or one part's bbox+volume+center of mass).",
86406
- "- Ship with `export_cad` (STL/GLB/STEP) or `open_in_browser` (vcad.io deep link).",
86799
+ "- Ship with `export_cad` (STL/GLB/STEP) or `open_in_app` (vcad:// deep link into the native app).",
86407
86800
  "- Fix in place: when geometry is wrong, prefer `update` on the offending node over deleting parts and starting over.",
86408
86801
  "- Cut sheet parts you already modelled: `flat_pattern_from_solid` turns any constant-thickness solid \u2014 extruded sketch, boolean, imported STEP \u2014 into a fab-ready DXF plus a bend table, no sheet-metal re-authoring. Called without `part_id` it does the whole document and groups identical parts into one pattern \xD7 quantity; hand its `nest_input` to `sheet_metal_nest`, then `sheet_metal_cost`, for a quote. It fails closed: the emitted profile re-extruded by the detected thickness must reproduce the solid's volume.",
86409
86802
  "- Deliver the project bill of materials with `bom_create` \u2192 `bom_export` (markdown/CSV/JSON with landed-cost totals): link quote_manufacturing quotes on manufactured lines, and source COTS hardware (bearings, shafts, standoffs, screws, ferrite magnets) with `search_mechanical_parts`. Check electronic lines against live LCSC/JLCPCB stock and price with `bom_check_stock` (or one part with `check_part_stock`). All BOM prices are estimates and flagged as such.",
@@ -87303,8 +87696,8 @@ var init_server3 = __esm({
87303
87696
  init_order_feed();
87304
87697
  init_animate();
87305
87698
  PKG_VERSION = (() => {
87306
- if ("0.11.0-main.138") {
87307
- return "0.11.0-main.138";
87699
+ if ("0.11.0-main.140") {
87700
+ return "0.11.0-main.140";
87308
87701
  }
87309
87702
  try {
87310
87703
  const req = createRequire2(import.meta.url);
@@ -87313,8 +87706,8 @@ var init_server3 = __esm({
87313
87706
  return "0.0.0";
87314
87707
  }
87315
87708
  })();
87316
- BUILD_SHA = "2df8f6d220243cc013bc875337b0aceb4b6b25b3";
87317
- BUILD_TIME = "2026-10-28T01:27:09.038Z";
87709
+ BUILD_SHA = "4a5ca79b1144c3ab693e34c74fc8a20ff18d6242";
87710
+ BUILD_TIME = "2026-11-07T14:45:02.882Z";
87318
87711
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
87319
87712
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
87320
87713
  INSTANCE_ID = randomUUID7().slice(0, 8);
@@ -87518,6 +87911,7 @@ var init_server3 = __esm({
87518
87911
  "import_altium",
87519
87912
  "import_altium_library",
87520
87913
  "import_eagle",
87914
+ "open_in_app",
87521
87915
  "open_in_browser",
87522
87916
  // ── Physics gym ────────────────────────────────────────────
87523
87917
  "create_robot_env",
@@ -87687,11 +88081,11 @@ var init_index = __esm({
87687
88081
  // src/npx-entry.ts
87688
88082
  init_dist();
87689
88083
  import { readFileSync as readFileSync10 } from "node:fs";
87690
- import { dirname as dirname5, join as join5 } from "node:path";
88084
+ import { dirname as dirname5, join as join6 } from "node:path";
87691
88085
  import { fileURLToPath as fileURLToPath3 } from "node:url";
87692
88086
  primeKernelWasm(
87693
88087
  readFileSync10(
87694
- join5(
88088
+ join6(
87695
88089
  dirname5(fileURLToPath3(import.meta.url)),
87696
88090
  "vcad_kernel_wasm_bg.wasm"
87697
88091
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.11.0-main.138",
3
+ "version": "0.11.0-main.140",
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": "2df8f6d220243cc013bc875337b0aceb4b6b25b3",
23
- "builtAt": "2026-10-28T01:27:09.038Z"
22
+ "sha": "4a5ca79b1144c3ab693e34c74fc8a20ff18d6242",
23
+ "builtAt": "2026-11-07T14:45:02.882Z"
24
24
  }
25
25
  }
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/vcad_kernel_wasm_bg.wasm
3
- size: 35419240 bytes
4
- sha256: dd437e1d919dd4a61ab3ba0c9f6fa0f8e01ca3f1b16c592df3b5d4045103b53e
3
+ size: 37267118 bytes
4
+ sha256: 345ccd3c52425074524246e9532459d8dc662d94cd9060ac15ef403c17bcbb3c