@vcad/mcp 0.10.0-main.123 → 0.10.0-main.124

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 +93 -316
  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 4c65cd9f4d93e78adf4900e8e3459a0b33d38dce at 2026-10-21T13:05:13.604Z. Source: https://github.com/ecto/vcad
9
+ Built from 72bb34aea80bd70051717281e832338ab01f1f3d at 2026-10-21T13:06:52.166Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -31321,154 +31321,6 @@ var init_parameters_store = __esm({
31321
31321
  }
31322
31322
  });
31323
31323
 
31324
- // ../core/dist/stores/ecad-sync.js
31325
- function padsFromPins(pins) {
31326
- const n = pins.length;
31327
- const pitch = 2.54;
31328
- return pins.map((pin, i) => ({
31329
- number: pin.number,
31330
- padType: "SMD",
31331
- shape: { type: "RoundRect", width: 1.5, height: 1.5, cornerRatio: 0.25 },
31332
- position: { x: (i - (n - 1) / 2) * pitch, y: 0 },
31333
- layers: [...FALLBACK_PAD_LAYERS]
31334
- }));
31335
- }
31336
- function syncSchematicToPcbData(pcb, schematic, netlist, opts) {
31337
- const placeUnplaced = opts?.placeUnplaced ?? true;
31338
- const next = structuredClone(pcb);
31339
- let changed = false;
31340
- const existingRefs = new Set(next.footprints.map((fp) => fp.ref));
31341
- let added = 0;
31342
- for (const comp of placeUnplaced ? schematic.components : []) {
31343
- if (existingRefs.has(comp.ref))
31344
- continue;
31345
- let pads = [];
31346
- let graphics = [];
31347
- if (comp.properties?.footprintTemplate) {
31348
- try {
31349
- const template = JSON.parse(comp.properties.footprintTemplate);
31350
- pads = template.pads ?? [];
31351
- graphics = template.graphics ?? [];
31352
- } catch {
31353
- }
31354
- }
31355
- if (pads.length === 0)
31356
- pads = padsFromPins(comp.pins);
31357
- const fpCount = next.footprints.length;
31358
- const staggerX = 10 + (fpCount + added) % 5 * 10;
31359
- const staggerY = 10 + Math.floor((fpCount + added) / 5) * 10;
31360
- next.footprints.push({
31361
- ref: comp.ref,
31362
- value: comp.value,
31363
- footprintName: comp.footprintId ?? comp.ref,
31364
- position: { x: staggerX, y: staggerY },
31365
- pads,
31366
- graphics
31367
- });
31368
- added++;
31369
- changed = true;
31370
- }
31371
- if (netlist) {
31372
- const padNet = /* @__PURE__ */ new Map();
31373
- const netNames = /* @__PURE__ */ new Set();
31374
- for (const net of netlist.nets) {
31375
- netNames.add(net.name);
31376
- for (const c of net.connections) {
31377
- padNet.set(`${c.component_ref}:${c.pin_number}`, net.name);
31378
- }
31379
- }
31380
- for (const fp of next.footprints) {
31381
- for (const pad of fp.pads) {
31382
- const wanted = padNet.get(`${fp.ref}:${pad.number}`);
31383
- if (wanted !== pad.net) {
31384
- if (wanted)
31385
- pad.net = wanted;
31386
- else
31387
- delete pad.net;
31388
- changed = true;
31389
- }
31390
- }
31391
- }
31392
- const known = new Set(next.nets.map((n) => n.name));
31393
- for (const name of netNames) {
31394
- if (!known.has(name)) {
31395
- next.nets.push({ id: name, name });
31396
- changed = true;
31397
- }
31398
- }
31399
- }
31400
- return { pcb: next, changed };
31401
- }
31402
- var FALLBACK_PAD_LAYERS;
31403
- var init_ecad_sync = __esm({
31404
- "../core/dist/stores/ecad-sync.js"() {
31405
- "use strict";
31406
- FALLBACK_PAD_LAYERS = ["FCu", "FPaste", "FMask"];
31407
- }
31408
- });
31409
-
31410
- // ../core/dist/utils/pcb-layers.js
31411
- function isCopperLayer(layer) {
31412
- return COPPER_RE.test(layer);
31413
- }
31414
- function innerCopperIndex(layer) {
31415
- const m = COPPER_RE.exec(layer);
31416
- return m?.[2] ? Number(m[2]) : 0;
31417
- }
31418
- function innerCopperLayerName(n) {
31419
- return `In${n}Cu`;
31420
- }
31421
- function copperLayerNames(count) {
31422
- if (!Number.isInteger(count) || count < 1) {
31423
- throw new Error(`invalid copper layer count ${count}`);
31424
- }
31425
- if (count === 1)
31426
- return ["FCu"];
31427
- const inner = Array.from({ length: count - 2 }, (_, i) => innerCopperLayerName(i + 1));
31428
- return ["FCu", ...inner, "BCu"];
31429
- }
31430
- function assertSupportedCopperCount(count) {
31431
- const ok4 = Number.isInteger(count) && count >= 1 && (count === 1 || count % 2 === 0) && count <= MAX_COPPER_LAYERS;
31432
- if (!ok4) {
31433
- throw new Error(`unsupported PCB layer count ${count}: expected 1 or an even number from 2 to ${MAX_COPPER_LAYERS}`);
31434
- }
31435
- }
31436
- function copperSortKey(layer) {
31437
- if (layer === "FCu")
31438
- return 0;
31439
- if (layer === "BCu")
31440
- return Number.MAX_SAFE_INTEGER;
31441
- return innerCopperIndex(layer);
31442
- }
31443
- function boardCopperLayers(pcb) {
31444
- const seen = /* @__PURE__ */ new Set();
31445
- const add = (l) => {
31446
- if (l && isCopperLayer(l))
31447
- seen.add(l);
31448
- };
31449
- for (const l of pcb?.stackup?.layers ?? [])
31450
- add(l.layer);
31451
- for (const t2 of pcb?.traces ?? [])
31452
- add(t2.layer);
31453
- for (const z of pcb?.zones ?? [])
31454
- add(z.layer);
31455
- for (const v of pcb?.vias ?? []) {
31456
- add(v.startLayer);
31457
- add(v.endLayer);
31458
- }
31459
- if (seen.size === 0)
31460
- return ["FCu", "BCu"];
31461
- return [...seen].sort((a, b) => copperSortKey(a) - copperSortKey(b));
31462
- }
31463
- var COPPER_RE, MAX_COPPER_LAYERS;
31464
- var init_pcb_layers = __esm({
31465
- "../core/dist/utils/pcb-layers.js"() {
31466
- "use strict";
31467
- COPPER_RE = /^(FCu|BCu|In(\d+)Cu)$/;
31468
- MAX_COPPER_LAYERS = 32;
31469
- }
31470
- });
31471
-
31472
31324
  // ../core/dist/stores/document-store.js
31473
31325
  function crdtF64(v) {
31474
31326
  return { F64: v };
@@ -31621,36 +31473,6 @@ function getOrCreateDrawingFeature(state) {
31621
31473
  }
31622
31474
  return "";
31623
31475
  }
31624
- function getOrCreateConstraintsFeature(state) {
31625
- const engine = state._crdtEngine;
31626
- if (_constraintsFeatureId)
31627
- return _constraintsFeatureId;
31628
- const featuresJson = engine.get_ordered_features_json();
31629
- const features = JSON.parse(featuresJson);
31630
- const existing = features.find((f) => f.kind === "design-constraints");
31631
- if (existing) {
31632
- _constraintsFeatureId = existing.id;
31633
- return existing.id;
31634
- }
31635
- const result = applyCommand(engine, { type: "create_feature", kind: "design-constraints" });
31636
- if (result.createdFeatureId) {
31637
- _constraintsFeatureId = result.createdFeatureId;
31638
- return result.createdFeatureId;
31639
- }
31640
- return "";
31641
- }
31642
- function setCrdtConstraints(state, constraints) {
31643
- const fid = getOrCreateConstraintsFeature(state);
31644
- if (!fid)
31645
- return {};
31646
- const result = applyCommand(state._crdtEngine, {
31647
- type: "set_param",
31648
- id: fid,
31649
- key: "constraints",
31650
- value: crdtStr(JSON.stringify(constraints))
31651
- });
31652
- return applyLegacyResult(result);
31653
- }
31654
31476
  function getOrCreateSchematicFeature(state) {
31655
31477
  const engine = state._crdtEngine;
31656
31478
  if (_schematicFeatureId)
@@ -31669,20 +31491,6 @@ function getOrCreateSchematicFeature(state) {
31669
31491
  }
31670
31492
  return "";
31671
31493
  }
31672
- function getPcbBoardFeatureId(state) {
31673
- const engine = state._crdtEngine;
31674
- const featuresJson = engine.get_ordered_features_json();
31675
- const features = JSON.parse(featuresJson);
31676
- const pcb = features.find((f) => f.kind === "pcb-board");
31677
- return pcb?.id ?? "";
31678
- }
31679
- function setCrdtPcb(state, pcb) {
31680
- const pcbFid = getPcbBoardFeatureId(state);
31681
- if (!pcbFid)
31682
- return {};
31683
- const result = applyCommand(state._crdtEngine, { type: "set_param", id: pcbFid, key: "board", value: crdtStr(JSON.stringify(pcb)) });
31684
- return applyLegacyResult(result);
31685
- }
31686
31494
  function applyEdit(get, set, tool, args) {
31687
31495
  const engine = get()._crdtEngine;
31688
31496
  if (!engine)
@@ -31695,23 +31503,21 @@ function applyEdit(get, set, tool, args) {
31695
31503
  set(applyApiResult(envelope.result));
31696
31504
  return true;
31697
31505
  }
31698
- function addPcbToDocument(get, set, pcbBoard, boardName2) {
31506
+ function addBoard(get, set, tool, args) {
31699
31507
  const engine = get()._crdtEngine;
31700
31508
  if (!engine) {
31701
31509
  console.error("[PCB] Cannot create board: CRDT engine not initialized");
31702
31510
  return 0;
31703
31511
  }
31704
- const params = {
31705
- name: crdtStr(boardName2),
31706
- board: crdtStr(JSON.stringify(pcbBoard)),
31707
- material: crdtStr("__pcb_fr4__")
31708
- };
31709
- const result = applyCommand(engine, { type: "create_feature", kind: "pcb-board", params });
31710
- set({ ...applyLegacyResult(result), isDirty: true });
31711
- const pcbPart = result.parts.find((p) => p.kind === "pcb-board");
31712
- return pcbPart ? pcbPart.boardNodeId : 0;
31512
+ const envelope = applyToolCall(engine, tool, args);
31513
+ if (!envelope.ok)
31514
+ throw new Error(envelope.error.message);
31515
+ set(applyApiResult(envelope.result));
31516
+ const created = envelope.result.parts.find((p) => p.id === envelope.result.createdFeatureId);
31517
+ const board = created ?? envelope.result.parts.find((p) => p.kind === "pcb-board");
31518
+ return board?.boardNodeId ?? 0;
31713
31519
  }
31714
- var _sceneSettingsFeatureId, _schematicFeatureId, _analysisStudiesFeatureId, _drawingSettingsFeatureId, _constraintsFeatureId, useDocumentStore;
31520
+ var _sceneSettingsFeatureId, _schematicFeatureId, _analysisStudiesFeatureId, _drawingSettingsFeatureId, useDocumentStore;
31715
31521
  var init_document_store = __esm({
31716
31522
  "../core/dist/stores/document-store.js"() {
31717
31523
  "use strict";
@@ -31724,13 +31530,10 @@ var init_document_store = __esm({
31724
31530
  init_types3();
31725
31531
  init_ui_store();
31726
31532
  init_parameters_store();
31727
- init_ecad_sync();
31728
- init_pcb_layers();
31729
31533
  _sceneSettingsFeatureId = null;
31730
31534
  _schematicFeatureId = null;
31731
31535
  _analysisStudiesFeatureId = null;
31732
31536
  _drawingSettingsFeatureId = null;
31733
- _constraintsFeatureId = null;
31734
31537
  useDocumentStore = create((set, get) => ({
31735
31538
  document: createDocument(),
31736
31539
  parts: [],
@@ -32625,43 +32428,36 @@ var init_document_store = __esm({
32625
32428
  },
32626
32429
  newDocument: (id, name) => {
32627
32430
  const state = get();
32431
+ let engine = state._crdtEngine;
32432
+ let view = {
32433
+ document: createDocument(),
32434
+ parts: [],
32435
+ partIndex: /* @__PURE__ */ new Map(),
32436
+ consumedParts: {},
32437
+ nextNodeId: 1
32438
+ };
32628
32439
  if (state._crdtEngineClass) {
32629
32440
  _sceneSettingsFeatureId = null;
32630
32441
  _schematicFeatureId = null;
32631
32442
  _analysisStudiesFeatureId = null;
32632
32443
  _drawingSettingsFeatureId = null;
32633
- const engine = new state._crdtEngineClass();
32634
- set({
32635
- document: createDocument(),
32636
- parts: [],
32637
- partIndex: /* @__PURE__ */ new Map(),
32638
- consumedParts: {},
32639
- nextNodeId: 1,
32640
- isDirty: false,
32641
- documentId: id,
32642
- documentName: name,
32643
- lastSavedAt: null,
32644
- isParameterDragging: false,
32645
- isTransientEval: false,
32646
- loonSource: null,
32647
- _crdtEngine: engine
32648
- });
32649
- } else {
32650
- set({
32651
- document: createDocument(),
32652
- parts: [],
32653
- partIndex: /* @__PURE__ */ new Map(),
32654
- consumedParts: {},
32655
- nextNodeId: 1,
32656
- isDirty: false,
32657
- documentId: id,
32658
- documentName: name,
32659
- lastSavedAt: null,
32660
- isParameterDragging: false,
32661
- isTransientEval: false,
32662
- loonSource: null
32444
+ engine = new state._crdtEngineClass();
32445
+ view = applyLegacyResult({
32446
+ document: JSON.parse(engine.get_document_json()),
32447
+ parts: JSON.parse(engine.get_parts_json())
32663
32448
  });
32664
32449
  }
32450
+ set({
32451
+ ...view,
32452
+ isDirty: false,
32453
+ documentId: id,
32454
+ documentName: name,
32455
+ lastSavedAt: null,
32456
+ isParameterDragging: false,
32457
+ isTransientEval: false,
32458
+ loonSource: null,
32459
+ _crdtEngine: engine
32460
+ });
32665
32461
  },
32666
32462
  clearDirtyNodes: () => {
32667
32463
  return /* @__PURE__ */ new Set();
@@ -32828,73 +32624,24 @@ var init_document_store = __esm({
32828
32624
  set(applyLegacyResult(result));
32829
32625
  },
32830
32626
  initPcb: (options) => {
32831
- const w = options?.width ?? 50;
32832
- const h = options?.height ?? 30;
32833
- const layerCount = options?.layers ?? 2;
32834
- const thickness = options?.thickness ?? 1.6;
32835
- const traceWidth = options?.traceWidth ?? 0.15;
32836
- const clearance = options?.clearance ?? 0.15;
32837
- const boardName2 = options?.name ?? "PCB Board";
32838
- assertSupportedCopperCount(layerCount);
32839
- const copperNames = copperLayerNames(layerCount);
32840
- const dielectricPerLayer = layerCount > 1 ? thickness / (layerCount - 1) : thickness;
32841
- const stackupLayers = copperNames.map((layer, i) => i === 0 ? { layer, copperThickness: 0.035 } : {
32842
- layer,
32843
- copperThickness: 0.035,
32844
- dielectricThickness: dielectricPerLayer,
32845
- dielectricEr: 4.5,
32846
- material: "FR4"
32627
+ return addBoard(get, set, "pcb_init", {
32628
+ width: options?.width,
32629
+ height: options?.height,
32630
+ layers: options?.layers,
32631
+ thickness: options?.thickness,
32632
+ trace_width: options?.traceWidth,
32633
+ clearance: options?.clearance,
32634
+ name: options?.name
32847
32635
  });
32848
- const pcbBoard = {
32849
- outline: {
32850
- vertices: [
32851
- { x: 0, y: 0 },
32852
- { x: w, y: 0 },
32853
- { x: w, y: h },
32854
- { x: 0, y: h }
32855
- ],
32856
- thickness
32857
- },
32858
- stackup: { layers: stackupLayers },
32859
- nets: [],
32860
- rules: {
32861
- defaultRules: {
32862
- name: "Default",
32863
- traceWidth,
32864
- clearance,
32865
- viaDiameter: 0.6,
32866
- viaDrill: 0.3
32867
- },
32868
- edgeClearance: 0.25,
32869
- holeToHole: 0.25,
32870
- minAnnularRing: 0.13,
32871
- minDrill: 0.2,
32872
- // KiCad's microvia defaults (uvia_min_drill / uvia_min_size).
32873
- minMicroviaDrill: 0.1,
32874
- minMicroviaDiameter: 0.2,
32875
- inferredFloors: []
32876
- },
32877
- footprints: [],
32878
- traces: [],
32879
- vias: [],
32880
- zones: []
32881
- };
32882
- return addPcbToDocument(get, set, pcbBoard, boardName2);
32883
32636
  },
32884
32637
  importPcb: (pcb, name) => {
32885
- return addPcbToDocument(get, set, pcb, name ?? "Imported PCB");
32638
+ return addBoard(get, set, "pcb_import", { board: pcb, name: name ?? "Imported PCB" });
32886
32639
  },
32887
- syncSchematicToPcb: (boardNodeId, netlist, opts) => {
32888
- const state = get();
32889
- const pcb = state.document.pcb;
32890
- const schematic = state.document.schematic;
32640
+ syncSchematicToPcb: (_boardNodeId, netlist, opts) => {
32641
+ const { pcb, schematic } = get().document;
32891
32642
  if (!pcb || !schematic)
32892
32643
  return;
32893
- const { pcb: nextPcb, changed } = syncSchematicToPcbData(pcb, schematic, netlist, opts);
32894
- if (!changed)
32895
- return;
32896
- const patch = setCrdtPcb(state, nextPcb);
32897
- set({ ...patch, isDirty: true });
32644
+ applyEdit(get, set, "pcb_sync_schematic", { netlist, place_unplaced: opts?.placeUnplaced });
32898
32645
  },
32899
32646
  moveSchematicComponent: (idx, position) => {
32900
32647
  applyEdit(get, set, "sch_move_component", { index: idx, position: { x: position.x, y: position.y } });
@@ -32993,7 +32740,7 @@ var init_document_store = __esm({
32993
32740
  const next = mergeSketchConstraints(state.document.constraints ?? [], sketchNode, session);
32994
32741
  if (next.length === 0 && (state.document.constraints ?? []).length === 0)
32995
32742
  return;
32996
- set({ ...setCrdtConstraints(state, next), isDirty: true });
32743
+ applyEdit(get, set, "set_design_constraints", { constraints: next });
32997
32744
  },
32998
32745
  addDesignConstraint: (constraint) => {
32999
32746
  if (!applyEdit(get, set, "add_design_constraint", { constraint }))
@@ -33019,20 +32766,7 @@ var init_document_store = __esm({
33019
32766
  const resultJson = wasm3.solveDesignConstraints(JSON.stringify(state.document), JSON.stringify(opts?.extraFixed ? { extraFixed: opts.extraFixed } : {}));
33020
32767
  const result = JSON.parse(resultJson);
33021
32768
  const { report } = result;
33022
- let patch = {};
33023
- const movedBoard = report.groups.find((g) => g.converged && getNodePcb(result.document, g.node));
33024
- if (movedBoard && (report.movedFootprints.length > 0 || report.movedVertices.length > 0)) {
33025
- const pcb = getNodePcb(result.document, movedBoard.node);
33026
- if (pcb)
33027
- patch = setCrdtPcb(get(), structuredClone(pcb));
33028
- }
33029
- if (report.drivenValues.length > 0) {
33030
- patch = {
33031
- ...patch,
33032
- ...setCrdtConstraints(get(), result.document.constraints ?? [])
33033
- };
33034
- }
33035
- set({ ...patch, isDirty: true });
32769
+ applyEdit(get, set, "apply_design_solve", { document: result.document, report });
33036
32770
  return report;
33037
32771
  } catch (e) {
33038
32772
  console.warn("[document-store] solveDesignConstraints failed:", e);
@@ -50253,6 +49987,49 @@ var init_changelog = __esm({
50253
49987
  }
50254
49988
  });
50255
49989
 
49990
+ // ../core/dist/utils/pcb-layers.js
49991
+ function isCopperLayer(layer) {
49992
+ return COPPER_RE.test(layer);
49993
+ }
49994
+ function innerCopperIndex(layer) {
49995
+ const m = COPPER_RE.exec(layer);
49996
+ return m?.[2] ? Number(m[2]) : 0;
49997
+ }
49998
+ function copperSortKey(layer) {
49999
+ if (layer === "FCu")
50000
+ return 0;
50001
+ if (layer === "BCu")
50002
+ return Number.MAX_SAFE_INTEGER;
50003
+ return innerCopperIndex(layer);
50004
+ }
50005
+ function boardCopperLayers(pcb) {
50006
+ const seen = /* @__PURE__ */ new Set();
50007
+ const add = (l) => {
50008
+ if (l && isCopperLayer(l))
50009
+ seen.add(l);
50010
+ };
50011
+ for (const l of pcb?.stackup?.layers ?? [])
50012
+ add(l.layer);
50013
+ for (const t2 of pcb?.traces ?? [])
50014
+ add(t2.layer);
50015
+ for (const z of pcb?.zones ?? [])
50016
+ add(z.layer);
50017
+ for (const v of pcb?.vias ?? []) {
50018
+ add(v.startLayer);
50019
+ add(v.endLayer);
50020
+ }
50021
+ if (seen.size === 0)
50022
+ return ["FCu", "BCu"];
50023
+ return [...seen].sort((a, b) => copperSortKey(a) - copperSortKey(b));
50024
+ }
50025
+ var COPPER_RE;
50026
+ var init_pcb_layers = __esm({
50027
+ "../core/dist/utils/pcb-layers.js"() {
50028
+ "use strict";
50029
+ COPPER_RE = /^(FCu|BCu|In(\d+)Cu)$/;
50030
+ }
50031
+ });
50032
+
50256
50033
  // ../core/dist/index.js
50257
50034
  var init_dist3 = __esm({
50258
50035
  "../core/dist/index.js"() {
@@ -87174,8 +86951,8 @@ var init_server3 = __esm({
87174
86951
  init_order_feed();
87175
86952
  init_animate();
87176
86953
  PKG_VERSION = (() => {
87177
- if ("0.10.0-main.123") {
87178
- return "0.10.0-main.123";
86954
+ if ("0.10.0-main.124") {
86955
+ return "0.10.0-main.124";
87179
86956
  }
87180
86957
  try {
87181
86958
  const req = createRequire2(import.meta.url);
@@ -87184,8 +86961,8 @@ var init_server3 = __esm({
87184
86961
  return "0.0.0";
87185
86962
  }
87186
86963
  })();
87187
- BUILD_SHA = "4c65cd9f4d93e78adf4900e8e3459a0b33d38dce";
87188
- BUILD_TIME = "2026-10-21T13:05:13.604Z";
86964
+ BUILD_SHA = "72bb34aea80bd70051717281e832338ab01f1f3d";
86965
+ BUILD_TIME = "2026-10-21T13:06:52.166Z";
87189
86966
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
87190
86967
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
87191
86968
  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.123",
3
+ "version": "0.10.0-main.124",
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": "4c65cd9f4d93e78adf4900e8e3459a0b33d38dce",
23
- "builtAt": "2026-10-21T13:05:13.604Z"
22
+ "sha": "72bb34aea80bd70051717281e832338ab01f1f3d",
23
+ "builtAt": "2026-10-21T13:06:52.166Z"
24
24
  }
25
25
  }