@vcad/mcp 0.10.0-main.115 → 0.10.0-main.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/index.mjs +49 -301
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -6,4 +6,4 @@ vcad's MCP server as a self-contained bundle (server + BRep kernel WASM).
6
6
  { "mcpServers": { "vcad": { "command": "npx", "args": ["-y", "@vcad/mcp"] } } }
7
7
  ```
8
8
 
9
- Built from 8ad12f403ad86c964867f288c8ef53b7790be8c8 at 2026-10-20T23:56:43.258Z. Source: https://github.com/ecto/vcad
9
+ Built from 72d19cb9100f1a027b8c00459e6f0994d641f28e at 2026-10-21T00:31:46.946Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -40941,24 +40941,6 @@ var init_registry2 = __esm({
40941
40941
  setWasm(wasm3) {
40942
40942
  this.wasm = wasm3;
40943
40943
  }
40944
- /**
40945
- * Plan a CRUD tool call via the Rust executor. Returns `null` if the
40946
- * wasm binding isn't present (old kernel build, test harness, etc.)
40947
- * so callers can fall back to the TS `executeCrud` path.
40948
- *
40949
- * `docJson` is a `JSON.stringify(document)` of the current store
40950
- * snapshot — the planner needs it for id/existence validation.
40951
- */
40952
- planCrud(tool, args, docJson) {
40953
- if (!this.wasm?.plan_chat_tool)
40954
- return null;
40955
- try {
40956
- const raw = this.wasm.plan_chat_tool(tool, JSON.stringify(args), docJson);
40957
- return JSON.parse(raw);
40958
- } catch {
40959
- return null;
40960
- }
40961
- }
40962
40944
  /** Get all loaded schema entries. */
40963
40945
  getSchemas() {
40964
40946
  return this.schemas;
@@ -41539,20 +41521,6 @@ function partIdMap(doc) {
41539
41521
  const copy = { roots: doc.roots, partIds: { ...doc.partIds ?? {} } };
41540
41522
  return ensurePartIds(copy).partIds;
41541
41523
  }
41542
- function movePartId(doc, oldRoot, newRoot) {
41543
- const map = idMap(doc);
41544
- const from = String(oldRoot);
41545
- const to = String(newRoot);
41546
- if (from === to)
41547
- return;
41548
- const id = map[from] ?? mint(map, newRoot);
41549
- delete map[from];
41550
- map[to] = id;
41551
- }
41552
- function forgetPartId(doc, root) {
41553
- if (doc.partIds)
41554
- delete doc.partIds[String(root)];
41555
- }
41556
41524
  function rootForPartId(doc, id) {
41557
41525
  const key3 = String(id).trim();
41558
41526
  if (!key3)
@@ -41577,9 +41545,6 @@ function rootForPartId(doc, id) {
41577
41545
  return done(byName, "name");
41578
41546
  return void 0;
41579
41547
  }
41580
- function rootIndexForPartId(doc, id) {
41581
- return rootForPartId(doc, id)?.index ?? -1;
41582
- }
41583
41548
  function partIdDeprecation(input, resolved) {
41584
41549
  if (!resolved || resolved.matchedBy === "stable")
41585
41550
  return void 0;
@@ -41595,150 +41560,6 @@ var init_part_ids = __esm({
41595
41560
  });
41596
41561
 
41597
41562
  // ../core/dist/commands/document-mutations.js
41598
- function nextNodeId(doc) {
41599
- let max = 0;
41600
- for (const k of Object.keys(doc.nodes)) {
41601
- const n = Number(k);
41602
- if (Number.isFinite(n) && n > max)
41603
- max = n;
41604
- }
41605
- return max + 1;
41606
- }
41607
- function findRootIndex(doc, partId) {
41608
- return rootIndexForPartId(doc, partId);
41609
- }
41610
- function collectChildNodeIds(doc, rootId) {
41611
- const seen = /* @__PURE__ */ new Set();
41612
- const stack = [rootId];
41613
- while (stack.length > 0) {
41614
- const id = stack.pop();
41615
- if (seen.has(id))
41616
- continue;
41617
- seen.add(id);
41618
- const node = doc.nodes[String(id)];
41619
- if (!node)
41620
- continue;
41621
- for (const child of opChildren(node.op))
41622
- stack.push(child);
41623
- }
41624
- return seen;
41625
- }
41626
- function opChildren(op) {
41627
- switch (op.type) {
41628
- case "Union":
41629
- case "Difference":
41630
- case "Intersection":
41631
- return [op.left, op.right];
41632
- case "Translate":
41633
- case "Rotate":
41634
- case "Scale":
41635
- case "LinearPattern":
41636
- case "CircularPattern":
41637
- case "Shell":
41638
- case "Fillet":
41639
- case "Chamfer":
41640
- case "EdgeBlend":
41641
- return [op.child];
41642
- case "Extrude":
41643
- case "Revolve":
41644
- return [op.sketch];
41645
- case "Sweep":
41646
- return [op.sketch];
41647
- case "Loft":
41648
- return op.sketches ?? [];
41649
- default:
41650
- return [];
41651
- }
41652
- }
41653
- function applyToolOutcome(doc, outcome) {
41654
- switch (outcome.kind) {
41655
- case "add_feature": {
41656
- const id = nextNodeId(doc);
41657
- const node = {
41658
- id,
41659
- name: outcome.name ?? null,
41660
- op: outcome.op
41661
- };
41662
- doc.nodes[String(id)] = node;
41663
- const children = new Set(opChildren(node.op));
41664
- const consumedIdxs = [];
41665
- doc.roots.forEach((r, i) => {
41666
- if (children.has(r.root))
41667
- consumedIdxs.push(i);
41668
- });
41669
- if (consumedIdxs.length > 0) {
41670
- const first = doc.roots[consumedIdxs[0]];
41671
- const firstPartId = String(first.root);
41672
- doc.roots[consumedIdxs[0]] = { ...first, root: id };
41673
- movePartId(doc, first.root, id);
41674
- if (doc.part_materials[firstPartId] !== void 0) {
41675
- doc.part_materials[String(id)] = doc.part_materials[firstPartId];
41676
- delete doc.part_materials[firstPartId];
41677
- }
41678
- for (let k = consumedIdxs.length - 1; k >= 1; k--) {
41679
- const idx = consumedIdxs[k];
41680
- delete doc.part_materials[String(doc.roots[idx].root)];
41681
- forgetPartId(doc, doc.roots[idx].root);
41682
- doc.roots.splice(idx, 1);
41683
- }
41684
- } else {
41685
- const entry = { root: id, material: "default" };
41686
- doc.roots.push(entry);
41687
- }
41688
- return { partId: partIdForNode(doc, id), nodeId: String(id) };
41689
- }
41690
- case "remove_part": {
41691
- const idx = findRootIndex(doc, outcome.part_id);
41692
- if (idx < 0) {
41693
- throw new Error(`remove_part: no root entry with id "${outcome.part_id}" in document`);
41694
- }
41695
- const entry = doc.roots[idx];
41696
- const removedId = partIdForRoot(doc, entry);
41697
- doc.roots.splice(idx, 1);
41698
- forgetPartId(doc, entry.root);
41699
- const reachableFromOthers = /* @__PURE__ */ new Set();
41700
- for (const r of doc.roots) {
41701
- for (const id of collectChildNodeIds(doc, r.root)) {
41702
- reachableFromOthers.add(id);
41703
- }
41704
- }
41705
- const exclusive = collectChildNodeIds(doc, entry.root);
41706
- for (const id of exclusive) {
41707
- if (!reachableFromOthers.has(id))
41708
- delete doc.nodes[String(id)];
41709
- }
41710
- delete doc.part_materials[String(entry.root)];
41711
- return { partId: removedId };
41712
- }
41713
- case "set_part_material": {
41714
- const idx = findRootIndex(doc, outcome.part_id);
41715
- if (idx < 0) {
41716
- throw new Error(`set_part_material: no root entry with id "${outcome.part_id}"`);
41717
- }
41718
- const prev = doc.roots[idx];
41719
- doc.roots[idx] = { root: prev.root, material: outcome.material, visible: prev.visible };
41720
- doc.part_materials[String(prev.root)] = outcome.material;
41721
- return { partId: partIdForRoot(doc, prev) };
41722
- }
41723
- case "update_params": {
41724
- const node = doc.nodes[outcome.node_id];
41725
- if (!node) {
41726
- throw new Error(`update_params: no node with id "${outcome.node_id}" in document`);
41727
- }
41728
- const op = node.op;
41729
- for (const [k, v] of Object.entries(outcome.params)) {
41730
- if (k === "type")
41731
- continue;
41732
- op[k] = v;
41733
- }
41734
- const owner = doc.roots.find((r) => collectChildNodeIds(doc, r.root).has(Number(outcome.node_id)));
41735
- return {
41736
- partId: owner ? partIdForRoot(doc, owner) : outcome.node_id,
41737
- nodeId: outcome.node_id
41738
- };
41739
- }
41740
- }
41741
- }
41742
41563
  function listPartsFromDocument(doc) {
41743
41564
  return doc.roots.map((entry) => {
41744
41565
  const node = doc.nodes[String(entry.root)];
@@ -42132,6 +41953,26 @@ var init_CHANGELOG = __esm({
42132
41953
  "apply_edits"
42133
41954
  ]
42134
41955
  },
41956
+ {
41957
+ id: "2026-10-20-mcp-apply-edits-engine",
41958
+ version: "0.10.0",
41959
+ date: "2026-10-20",
41960
+ category: "fix",
41961
+ title: "apply_edits runs on the document engine",
41962
+ summary: `MCP apply_edits now applies every op through the Rust document engine, like the single-op tools; "@N" resolves to op N's stable part id. The legacy planner fallback is gone.`,
41963
+ features: [
41964
+ "mcp",
41965
+ "engine",
41966
+ "batch-edit"
41967
+ ],
41968
+ mcpTools: [
41969
+ "apply_edits",
41970
+ "create",
41971
+ "update",
41972
+ "delete",
41973
+ "set_material"
41974
+ ]
41975
+ },
42135
41976
  {
42136
41977
  id: "2026-10-20-lossless-import",
42137
41978
  version: "undefined",
@@ -55894,23 +55735,31 @@ function engineErrorMessage(toolName, args, err9) {
55894
55735
  }
55895
55736
  }
55896
55737
  function runMutationViaEngine(toolName, toolArgs, doc, documentId) {
55897
- if (!ENGINE_LOWERED_TOOLS.has(toolName)) return null;
55898
- if (process.env.VCAD_MCP_ENGINE_APPLY === "0") return null;
55738
+ if (!ENGINE_LOWERED_TOOLS.has(toolName)) {
55739
+ throw new Error(`Tool "${toolName}" is not lowered by the document engine.`);
55740
+ }
55899
55741
  const wasm3 = getKernelWasmSync();
55900
55742
  const factory = wasm3?.WasmDocumentEngine;
55901
- if (!factory || typeof factory.withReplica !== "function") return null;
55743
+ if (!factory || typeof factory.withReplica !== "function") {
55744
+ throw new Error(
55745
+ `${toolName}: kernel WASM has no WasmDocumentEngine \u2014 ensure the kernel is initialized and up to date.`
55746
+ );
55747
+ }
55902
55748
  const cachedEngine = takeCachedEngine(documentId, doc);
55903
55749
  const engine = cachedEngine ?? factory.withReplica(0);
55904
55750
  let keep = false;
55905
55751
  try {
55906
- if (typeof engine.apply_tool !== "function") return null;
55752
+ if (typeof engine.apply_tool !== "function") {
55753
+ throw new Error(
55754
+ `${toolName}: kernel WASM predates WasmDocumentEngine.apply_tool \u2014 rebuild the kernel WASM.`
55755
+ );
55756
+ }
55907
55757
  const deprecation = typeof toolArgs.part_id === "string" ? partIdDeprecation(toolArgs.part_id, rootForPartId(doc, toolArgs.part_id)) : void 0;
55908
55758
  const args = engineArgs(toolName, toolArgs, doc);
55909
55759
  if (!cachedEngine) engine.import_ir(JSON.stringify(doc));
55910
55760
  const envelope = JSON.parse(engine.apply_tool(toolName, JSON.stringify(args)));
55911
55761
  if (!envelope.ok || !envelope.result) {
55912
55762
  const err9 = envelope.error ?? { kind: "invalid", message: "engine returned no result" };
55913
- if (err9.kind === "unsupported") return null;
55914
55763
  throw new Error(engineErrorMessage(toolName, args, err9));
55915
55764
  }
55916
55765
  const next = envelope.result.document;
@@ -55933,7 +55782,9 @@ function runMutationViaEngine(toolName, toolArgs, doc, documentId) {
55933
55782
  payload.part_id = args.part_id ?? args.part_ids;
55934
55783
  payload.material = toolArgs.material;
55935
55784
  } else {
55936
- const partId = envelope.result.createdFeatureId ?? (typeof args.part_id === "string" ? args.part_id : void 0);
55785
+ const params = args.params;
55786
+ const edited = args.part_id ?? args.child ?? params?.child;
55787
+ const partId = envelope.result.createdFeatureId ?? (typeof edited === "string" ? edited : void 0);
55937
55788
  if (partId) {
55938
55789
  payload.part_id = partId;
55939
55790
  const part = parts.find((p) => p.id === partId);
@@ -55951,102 +55802,9 @@ function runMutationViaEngine(toolName, toolArgs, doc, documentId) {
55951
55802
  if (!keep) engine.free?.();
55952
55803
  }
55953
55804
  }
55954
- function runMutation(toolName, rawArgs, doc, documentId, opts = {}) {
55805
+ function runMutation(toolName, rawArgs, doc, documentId) {
55955
55806
  const toolArgs = normalizeNodeRefs(toolName, rawArgs, doc);
55956
- if (opts.engine !== false) {
55957
- const viaEngine = runMutationViaEngine(toolName, toolArgs, doc, documentId);
55958
- if (viaEngine) return viaEngine;
55959
- }
55960
- if (documentId) markDocumentWritten(documentId);
55961
- if (toolName === "delete") {
55962
- const partId = String(toolArgs.part_id ?? "");
55963
- if (!partId) throw new Error("delete: missing `part_id`");
55964
- const deprecation = partIdDeprecation(partId, rootForPartId(doc, partId));
55965
- const applied2 = applyToolOutcome(doc, {
55966
- kind: "remove_part",
55967
- part_id: partId
55968
- });
55969
- return {
55970
- content: [
55971
- {
55972
- type: "text",
55973
- text: JSON.stringify({
55974
- document_id: documentId,
55975
- removed: applied2.partId,
55976
- ...deprecation ? { warnings: [deprecation] } : {}
55977
- })
55978
- }
55979
- ]
55980
- };
55981
- }
55982
- if (toolName === "set_material") {
55983
- const partId = String(toolArgs.part_id ?? "");
55984
- const material = String(
55985
- toolArgs.material ?? ""
55986
- );
55987
- if (!partId) throw new Error("set_material: missing `part_id` (bulk forms not yet supported via MCP)");
55988
- if (!material) throw new Error("set_material: missing `material`");
55989
- const deprecation = partIdDeprecation(partId, rootForPartId(doc, partId));
55990
- const applied2 = applyToolOutcome(doc, {
55991
- kind: "set_part_material",
55992
- part_id: partId,
55993
- material
55994
- });
55995
- return {
55996
- content: [
55997
- {
55998
- type: "text",
55999
- text: JSON.stringify({
56000
- document_id: documentId,
56001
- part_id: applied2.partId,
56002
- material,
56003
- ...deprecation ? { warnings: [deprecation] } : {}
56004
- })
56005
- }
56006
- ]
56007
- };
56008
- }
56009
- const plannerArgs = toolName === "create" ? applyParamDefaults(toolArgs) : toolArgs;
56010
- const planned = commandRegistry.planCrud(
56011
- toolName,
56012
- plannerArgs,
56013
- JSON.stringify(doc)
56014
- );
56015
- if (!planned) {
56016
- throw new Error(
56017
- `Tool "${toolName}" \u2014 Rust planner unavailable. Ensure commandRegistry.setWasm() has been called during MCP server boot.`
56018
- );
56019
- }
56020
- if (planned.status === "error") {
56021
- throw new Error(enrichPlannerError(toolName, plannerArgs, planned.result));
56022
- }
56023
- if (!planned.outcome) {
56024
- return {
56025
- content: [
56026
- {
56027
- type: "text",
56028
- text: JSON.stringify({
56029
- document_id: documentId,
56030
- result: planned.result
56031
- })
56032
- }
56033
- ]
56034
- };
56035
- }
56036
- const applied = applyToolOutcome(doc, planned.outcome);
56037
- return {
56038
- content: [
56039
- {
56040
- type: "text",
56041
- text: JSON.stringify({
56042
- document_id: documentId,
56043
- result: planned.result,
56044
- part_id: applied.partId,
56045
- node_id: applied.nodeId
56046
- })
56047
- }
56048
- ]
56049
- };
55807
+ return runMutationViaEngine(toolName, toolArgs, doc, documentId);
56050
55808
  }
56051
55809
  function handleMeasureRead(toolName, doc, args, engine, pose) {
56052
55810
  if (!engine) {
@@ -58248,7 +58006,7 @@ function normalizeOp(op, index) {
58248
58006
  }
58249
58007
  return { name, args };
58250
58008
  }
58251
- function resolveSymbolicRefs(args, createdIds, index, doc) {
58009
+ function resolveSymbolicRefs(args, createdIds, index) {
58252
58010
  const resolve7 = (v) => {
58253
58011
  if (typeof v !== "string") return v;
58254
58012
  const m = SYMBOLIC_REF.exec(v);
@@ -58262,7 +58020,7 @@ function resolveSymbolicRefs(args, createdIds, index, doc) {
58262
58020
  const id = createdIds[refIdx];
58263
58021
  if (id === void 0) {
58264
58022
  throw new Error(
58265
- `"@${refIdx}" refers to op ${refIdx}, which did not create a node`
58023
+ `"@${refIdx}" refers to op ${refIdx}, which did not create a part`
58266
58024
  );
58267
58025
  }
58268
58026
  return id;
@@ -58271,12 +58029,6 @@ function resolveSymbolicRefs(args, createdIds, index, doc) {
58271
58029
  for (const key3 of ["part_id", "node_id"]) {
58272
58030
  if (key3 in out) out[key3] = resolve7(out[key3]);
58273
58031
  }
58274
- if (typeof args.part_id === "string" && SYMBOLIC_REF.test(args.part_id)) {
58275
- const nodeId = String(out.part_id);
58276
- if (doc.roots.some((r) => String(r.root) === nodeId)) {
58277
- out.part_id = partIdForNode(doc, nodeId);
58278
- }
58279
- }
58280
58032
  if (out.params && typeof out.params === "object" && !Array.isArray(out.params)) {
58281
58033
  const params = { ...out.params };
58282
58034
  for (const key3 of ["child", "left", "right", "sketch"]) {
@@ -58298,12 +58050,9 @@ function applyOps(doc, ops, documentId) {
58298
58050
  try {
58299
58051
  result = runMutation(
58300
58052
  name,
58301
- resolveSymbolicRefs(args, createdIds, i, doc),
58053
+ resolveSymbolicRefs(args, createdIds, i),
58302
58054
  doc,
58303
- documentId,
58304
- // Legacy planner: "@N" and raw numeric child refs address the
58305
- // planner's node numbering (see runMutation).
58306
- { engine: false }
58055
+ documentId
58307
58056
  );
58308
58057
  } catch (err9) {
58309
58058
  throw new BatchOpError(i, name, err9);
@@ -58317,7 +58066,7 @@ function applyOps(doc, ops, documentId) {
58317
58066
  const { document_id: _docId, ...rest } = parsed;
58318
58067
  void _docId;
58319
58068
  createdIds.push(
58320
- name === "create" && typeof rest.node_id === "string" ? rest.node_id : void 0
58069
+ name === "create" && typeof rest.part_id === "string" ? rest.part_id : void 0
58321
58070
  );
58322
58071
  results.push({ index: i, op: name, ...rest });
58323
58072
  }
@@ -58405,7 +58154,6 @@ var init_batch_edit = __esm({
58405
58154
  init_registry_dispatch();
58406
58155
  init_integrity();
58407
58156
  init_tool_def();
58408
- init_part_ids2();
58409
58157
  ALLOWED_OPS = ["create", "update", "delete", "set_material"];
58410
58158
  MAX_BATCH_OPS = 50;
58411
58159
  applyEditsSchema = {
@@ -58417,7 +58165,7 @@ var init_batch_edit = __esm({
58417
58165
  },
58418
58166
  ops: {
58419
58167
  type: "array",
58420
- description: `Ordered list of edit ops applied atomically (all-or-nothing). Each op is \`{op, ...args}\` where op is one of create/update/delete/set_material and the remaining fields are that tool's arguments (minus document_id): create {op, type, params}, update {op, node_id|part_id, ...fields}, delete {op, part_id}, set_material {op, part_id, material}. Later ops may reference nodes created by earlier ops in the same batch symbolically: "@N" (in params.child/left/right/sketch or part_id/node_id) resolves to the node created by op index N \u2014 no need to predict node ids. Max ${MAX_BATCH_OPS} per call.`,
58168
+ description: `Ordered list of edit ops applied atomically (all-or-nothing). Each op is \`{op, ...args}\` where op is one of create/update/delete/set_material and the remaining fields are that tool's arguments (minus document_id): create {op, type, params}, update {op, node_id|part_id, ...fields}, delete {op, part_id}, set_material {op, part_id, material}. Later ops may reference parts from earlier ops in the same batch symbolically: "@N" (in params.child/left/right/sketch or part_id/node_id) resolves to the part created by op index N (for an in-place edit such as translate, the part it edited) \u2014 no need to predict ids. Max ${MAX_BATCH_OPS} per call.`,
58421
58169
  items: { type: "object" }
58422
58170
  },
58423
58171
  dry_run: {
@@ -58445,7 +58193,7 @@ var init_batch_edit = __esm({
58445
58193
  {
58446
58194
  name: "apply_edits",
58447
58195
  pack: null,
58448
- description: "Apply an ordered list of edit ops (create/update/delete/set_material) to a session document atomically \u2014 all-or-nothing. One call replaces N single-node round-trips: it returns one aggregated `changed` diff over every op and one integrity certificate, and a subsequent `undo` rewinds the whole batch. Any op failing restores the pre-call document byte-for-byte and reports the failing op index. Pass `dry_run: true` to validate and get the per-op plan without mutating. Each op is `{op, ...args}` (e.g. {op:'create', type:'cube', params:{size:{x,y,z}}}); later ops reference nodes created earlier in the batch as \"@N\" (op index N), so a boolean chain never predicts node ids.",
58196
+ description: "Apply an ordered list of edit ops (create/update/delete/set_material) to a session document atomically \u2014 all-or-nothing. One call replaces N single-node round-trips: it returns one aggregated `changed` diff over every op and one integrity certificate, and a subsequent `undo` rewinds the whole batch. Any op failing restores the pre-call document byte-for-byte and reports the failing op index. Pass `dry_run: true` to validate and get the per-op plan without mutating. Each op is `{op, ...args}` (e.g. {op:'create', type:'cube', params:{size:{x,y,z}}}); later ops reference parts created earlier in the batch as \"@N\" (op index N), so a boolean chain never predicts node ids.",
58449
58197
  inputSchema: applyEditsSchema,
58450
58198
  handler: (a, c) => applyEdits(a, c.engine),
58451
58199
  // mount: a batch edit is a milestone — refresh the viewer at the bottom
@@ -87491,8 +87239,8 @@ var init_server3 = __esm({
87491
87239
  init_order_feed();
87492
87240
  init_animate();
87493
87241
  PKG_VERSION = (() => {
87494
- if ("0.10.0-main.115") {
87495
- return "0.10.0-main.115";
87242
+ if ("0.10.0-main.116") {
87243
+ return "0.10.0-main.116";
87496
87244
  }
87497
87245
  try {
87498
87246
  const req = createRequire2(import.meta.url);
@@ -87501,8 +87249,8 @@ var init_server3 = __esm({
87501
87249
  return "0.0.0";
87502
87250
  }
87503
87251
  })();
87504
- BUILD_SHA = "8ad12f403ad86c964867f288c8ef53b7790be8c8";
87505
- BUILD_TIME = "2026-10-20T23:56:43.258Z";
87252
+ BUILD_SHA = "72d19cb9100f1a027b8c00459e6f0994d641f28e";
87253
+ BUILD_TIME = "2026-10-21T00:31:46.946Z";
87506
87254
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
87507
87255
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
87508
87256
  INSTANCE_ID = randomUUID7().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.10.0-main.115",
3
+ "version": "0.10.0-main.116",
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": "8ad12f403ad86c964867f288c8ef53b7790be8c8",
23
- "builtAt": "2026-10-20T23:56:43.258Z"
22
+ "sha": "72d19cb9100f1a027b8c00459e6f0994d641f28e",
23
+ "builtAt": "2026-10-21T00:31:46.946Z"
24
24
  }
25
25
  }