@vcad/mcp 0.10.0-main.131 → 0.10.0-main.132

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 +98 -90
  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 5ba01b5a98082b32c94a94415030e2581bf3288e at 2026-10-21T16:56:57.309Z. Source: https://github.com/ecto/vcad
9
+ Built from 362c46b798588ed58f200c9d529b3d11b2b2ff73 at 2026-10-21T17:31:51.205Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -12492,6 +12492,7 @@ var init_dist = __esm({
12492
12492
  evaluateDocument: wasmModule7.evaluateDocument,
12493
12493
  evalVcadSource: wasmModule7.evalVcadSource,
12494
12494
  evalVcadSourceWithModules: wasmModule7.evalVcadSourceWithModules,
12495
+ evalLoonDocument: wasmModule7.evalLoonDocument,
12495
12496
  evalVcadSourceParametric: wasmModule7.evalVcadSourceParametric,
12496
12497
  documentParameterGradient: wasmModule7.documentParameterGradient,
12497
12498
  documentSensitivities: wasmModule7.documentSensitivities,
@@ -13394,6 +13395,22 @@ var init_dist = __esm({
13394
13395
  * With an empty map this is exactly {@link evalVcadSource}. Returns null
13395
13396
  * if the kernel doesn't support module-aware loon evaluation.
13396
13397
  */
13398
+ /**
13399
+ * Evaluate loon source to a session document stamped with its provenance
13400
+ * (`doc.source`: program, modules, origin dir/file, SHA-256), in the kernel.
13401
+ * Null on kernels predating the export.
13402
+ */
13403
+ evalLoonDocument(source, modules, origin = {}) {
13404
+ if (typeof this.kernel.evalLoonDocument !== "function")
13405
+ return null;
13406
+ const doc = JSON.parse(this.kernel.evalLoonDocument(source, JSON.stringify(modules), origin.baseDir, origin.path));
13407
+ if (doc.source) {
13408
+ doc.source.diverged ??= false;
13409
+ doc.source.diverged_by ??= [];
13410
+ doc.source.modules ??= {};
13411
+ }
13412
+ return doc;
13413
+ }
13397
13414
  evalVcadSourceWithModules(source, modules) {
13398
13415
  if (!Object.keys(modules).length)
13399
13416
  return this.evalVcadSource(source);
@@ -41686,6 +41703,18 @@ var init_CHANGELOG = __esm({
41686
41703
  "cli"
41687
41704
  ]
41688
41705
  },
41706
+ {
41707
+ id: "2026-10-21-photoreal-cyclorama",
41708
+ version: "0.10.0",
41709
+ date: "2026-10-21",
41710
+ category: "feat",
41711
+ title: "Seamless cyclorama backdrop for photoreal renders",
41712
+ summary: "--backdrop cyclorama (vcad render --cyclorama) puts the subject on a matte floor that curves into a back wall, with no horizon line or edge in frame.",
41713
+ features: [
41714
+ "photoreal",
41715
+ "render"
41716
+ ]
41717
+ },
41689
41718
  {
41690
41719
  id: "2026-10-21-mac-sim-teardown-race",
41691
41720
  version: "0.10.0",
@@ -51705,79 +51734,8 @@ var init_loon_assets = __esm({
51705
51734
  }
51706
51735
  });
51707
51736
 
51708
- // src/tools/source-provenance.ts
51709
- import { createHash } from "node:crypto";
51710
- import { readFileSync as readFileSync3 } from "node:fs";
51711
- function sourceHash(text) {
51712
- return createHash("sha256").update(text, "utf8").digest("hex");
51713
- }
51714
- function attachLoonSource(doc, { text, modules, base_dir, path }) {
51715
- const source = {
51716
- language: "loon",
51717
- text,
51718
- modules: modules && Object.keys(modules).length ? { ...modules } : {},
51719
- hash: sourceHash(text),
51720
- diverged: false,
51721
- diverged_by: []
51722
- };
51723
- if (base_dir) source.base_dir = base_dir;
51724
- if (path) source.path = path;
51725
- doc.source = source;
51726
- }
51727
- function markSourceDiverged(documentId, tool) {
51728
- const src = documents.get(documentId)?.source;
51729
- if (!src) return false;
51730
- const firstTime = !src.diverged;
51731
- src.diverged = true;
51732
- const by = src.diverged_by ??= [];
51733
- if (by[by.length - 1] !== tool) by.push(tool);
51734
- if (by.length > MAX_DIVERGED_BY) by.splice(0, by.length - MAX_DIVERGED_BY);
51735
- return firstTime;
51736
- }
51737
- function sourceStatus(doc) {
51738
- const src = doc?.source;
51739
- if (!src) return { source_stale: false };
51740
- const path = src.path;
51741
- if (path) {
51742
- let onDisk = null;
51743
- try {
51744
- onDisk = readFileSync3(path, "utf8");
51745
- } catch {
51746
- return {
51747
- source_stale: true,
51748
- source_path: path,
51749
- reason: `The source file ${path} can no longer be read \u2014 this session is no longer backed by the file it was loaded from.`
51750
- };
51751
- }
51752
- if (sourceHash(onDisk) !== src.hash) {
51753
- return {
51754
- source_stale: true,
51755
- source_path: path,
51756
- reason: `${path} changed on disk since this session was evaluated from it \u2014 the session's geometry is from the OLD source. Re-load the file to pick up the edits.`
51757
- };
51758
- }
51759
- }
51760
- if (src.diverged) {
51761
- const by = src.diverged_by ?? [];
51762
- return {
51763
- source_stale: true,
51764
- ...path ? { source_path: path } : {},
51765
- reason: `This session has been edited directly (${by.join(", ") || "mutation"}), and those edits cannot round-trip back to loon. The stored source describes the document's ORIGIN, not its current state` + (path ? ` \u2014 saving would not reproduce ${path}, and re-evaluating ${path} would discard the edits.` : `.`)
51766
- };
51767
- }
51768
- return { source_stale: false, ...path ? { source_path: path } : {} };
51769
- }
51770
- var MAX_DIVERGED_BY;
51771
- var init_source_provenance = __esm({
51772
- "src/tools/source-provenance.ts"() {
51773
- "use strict";
51774
- init_session_core();
51775
- MAX_DIVERGED_BY = 8;
51776
- }
51777
- });
51778
-
51779
51737
  // src/tools/loon.ts
51780
- import { readFileSync as readFileSync4 } from "node:fs";
51738
+ import { readFileSync as readFileSync3 } from "node:fs";
51781
51739
  import { delimiter, isAbsolute as isAbsolute3, join as join2, resolve as resolve2, sep as sep2 } from "node:path";
51782
51740
  function composeLoonProgram(input) {
51783
51741
  const { source, use_loons, loons } = input;
@@ -51803,7 +51761,7 @@ function readModule(base, name) {
51803
51761
  const file = resolve2(join2(root, ...name.split(".")) + ext);
51804
51762
  if (file !== root && !file.startsWith(root + sep2)) continue;
51805
51763
  try {
51806
- return readFileSync4(file, "utf8");
51764
+ return readFileSync3(file, "utf8");
51807
51765
  } catch {
51808
51766
  }
51809
51767
  }
@@ -51870,11 +51828,10 @@ function evalCadLoon(input, engine) {
51870
51828
  const modules = composeLoonModules(input);
51871
51829
  let doc;
51872
51830
  try {
51873
- doc = engine.evalVcadSourceWithModules(source, modules);
51831
+ doc = engine.evalLoonDocument(source, modules, { baseDir: base_dir });
51874
51832
  } catch (e) {
51875
51833
  throw explainEvalError(e, parsed, missingModules(source, modules));
51876
51834
  }
51877
- if (doc) attachLoonSource(doc, { text: source, modules, base_dir });
51878
51835
  if (!doc) {
51879
51836
  const text2 = Object.keys(modules).length ? "Error: this kernel build cannot resolve loon modules ([use ...]) \u2014 update the kernel, or inline the modules into `source`" : "Error: Loon evaluation not supported by this engine build";
51880
51837
  return { result: { content: [{ type: "text", text: text2 }] }, doc: null };
@@ -51948,7 +51905,6 @@ var init_loon = __esm({
51948
51905
  init_session_core();
51949
51906
  init_loon_assets();
51950
51907
  init_remote();
51951
- init_source_provenance();
51952
51908
  init_tool_def();
51953
51909
  createCadLoonSchema = {
51954
51910
  type: "object",
@@ -52604,7 +52560,7 @@ var init_session_store = __esm({
52604
52560
  });
52605
52561
 
52606
52562
  // src/tools/artifact-store.ts
52607
- import { createHash as createHash2, randomBytes } from "node:crypto";
52563
+ import { createHash, randomBytes } from "node:crypto";
52608
52564
  function ttlMs() {
52609
52565
  const raw = process.env.MCP_ARTIFACT_TTL_MS;
52610
52566
  const n = raw ? parseInt(raw, 10) : NaN;
@@ -52700,7 +52656,7 @@ function storeArtifact(files) {
52700
52656
  const manifest = stored.map((f) => ({
52701
52657
  file: f.name,
52702
52658
  bytes: f.buf.length,
52703
- sha256: createHash2("sha256").update(f.buf).digest("hex")
52659
+ sha256: createHash("sha256").update(f.buf).digest("hex")
52704
52660
  }));
52705
52661
  const bytes = stored.reduce((n, f) => n + f.buf.length, 0);
52706
52662
  const expiresAt = now + ttlMs();
@@ -52835,7 +52791,7 @@ async function loadDurable(id) {
52835
52791
  manifest: Array.isArray(row.manifest) ? row.manifest : files.map((f) => ({
52836
52792
  file: f.name,
52837
52793
  bytes: f.buf.length,
52838
- sha256: createHash2("sha256").update(f.buf).digest("hex")
52794
+ sha256: createHash("sha256").update(f.buf).digest("hex")
52839
52795
  })),
52840
52796
  bytes: typeof row.bytes === "number" ? row.bytes : files.reduce((n, f) => n + f.buf.length, 0),
52841
52797
  createdAt: row.created_at ? Date.parse(row.created_at) : Date.now(),
@@ -52895,6 +52851,64 @@ var init_artifact_store = __esm({
52895
52851
  }
52896
52852
  });
52897
52853
 
52854
+ // src/tools/source-provenance.ts
52855
+ import { createHash as createHash2 } from "node:crypto";
52856
+ import { readFileSync as readFileSync4 } from "node:fs";
52857
+ function sourceHash(text) {
52858
+ return createHash2("sha256").update(text, "utf8").digest("hex");
52859
+ }
52860
+ function markSourceDiverged(documentId, tool) {
52861
+ const src = documents.get(documentId)?.source;
52862
+ if (!src) return false;
52863
+ const firstTime = !src.diverged;
52864
+ src.diverged = true;
52865
+ const by = src.diverged_by ??= [];
52866
+ if (by[by.length - 1] !== tool) by.push(tool);
52867
+ if (by.length > MAX_DIVERGED_BY) by.splice(0, by.length - MAX_DIVERGED_BY);
52868
+ return firstTime;
52869
+ }
52870
+ function sourceStatus(doc) {
52871
+ const src = doc?.source;
52872
+ if (!src) return { source_stale: false };
52873
+ const path = src.path;
52874
+ if (path) {
52875
+ let onDisk = null;
52876
+ try {
52877
+ onDisk = readFileSync4(path, "utf8");
52878
+ } catch {
52879
+ return {
52880
+ source_stale: true,
52881
+ source_path: path,
52882
+ reason: `The source file ${path} can no longer be read \u2014 this session is no longer backed by the file it was loaded from.`
52883
+ };
52884
+ }
52885
+ if (sourceHash(onDisk) !== src.hash) {
52886
+ return {
52887
+ source_stale: true,
52888
+ source_path: path,
52889
+ reason: `${path} changed on disk since this session was evaluated from it \u2014 the session's geometry is from the OLD source. Re-load the file to pick up the edits.`
52890
+ };
52891
+ }
52892
+ }
52893
+ if (src.diverged) {
52894
+ const by = src.diverged_by ?? [];
52895
+ return {
52896
+ source_stale: true,
52897
+ ...path ? { source_path: path } : {},
52898
+ reason: `This session has been edited directly (${by.join(", ") || "mutation"}), and those edits cannot round-trip back to loon. The stored source describes the document's ORIGIN, not its current state` + (path ? ` \u2014 saving would not reproduce ${path}, and re-evaluating ${path} would discard the edits.` : `.`)
52899
+ };
52900
+ }
52901
+ return { source_stale: false, ...path ? { source_path: path } : {} };
52902
+ }
52903
+ var MAX_DIVERGED_BY;
52904
+ var init_source_provenance = __esm({
52905
+ "src/tools/source-provenance.ts"() {
52906
+ "use strict";
52907
+ init_session_core();
52908
+ MAX_DIVERGED_BY = 8;
52909
+ }
52910
+ });
52911
+
52898
52912
  // src/tools/session.ts
52899
52913
  import { writeFileSync as writeFileSync2, readFileSync as readFileSync5 } from "node:fs";
52900
52914
  import { dirname, resolve as resolve3 } from "node:path";
@@ -53211,18 +53225,12 @@ async function loadDocumentFromPath(path, store, engine) {
53211
53225
  const modules = composeLoonModules({ source: raw, base_dir: baseDir });
53212
53226
  let doc;
53213
53227
  try {
53214
- doc = engine.evalVcadSourceWithModules(raw, modules) ?? null;
53228
+ doc = engine.evalLoonDocument(raw, modules, { baseDir, path: abs });
53215
53229
  } catch (e) {
53216
53230
  return fail2(`Loon evaluation of ${abs} failed: ${e.message}`);
53217
53231
  }
53218
53232
  if (!doc) return fail2(`Loon evaluation of ${abs} produced no document.`);
53219
53233
  const imports = assetNote(resolveLoonAssets(doc, { base_dir: baseDir }, engine));
53220
- attachLoonSource(doc, {
53221
- text: raw,
53222
- modules,
53223
- base_dir: baseDir,
53224
- path: abs
53225
- });
53226
53234
  const id = registerSession(doc);
53227
53235
  return {
53228
53236
  content: [
@@ -87053,8 +87061,8 @@ var init_server3 = __esm({
87053
87061
  init_order_feed();
87054
87062
  init_animate();
87055
87063
  PKG_VERSION = (() => {
87056
- if ("0.10.0-main.131") {
87057
- return "0.10.0-main.131";
87064
+ if ("0.10.0-main.132") {
87065
+ return "0.10.0-main.132";
87058
87066
  }
87059
87067
  try {
87060
87068
  const req = createRequire2(import.meta.url);
@@ -87063,8 +87071,8 @@ var init_server3 = __esm({
87063
87071
  return "0.0.0";
87064
87072
  }
87065
87073
  })();
87066
- BUILD_SHA = "5ba01b5a98082b32c94a94415030e2581bf3288e";
87067
- BUILD_TIME = "2026-10-21T16:56:57.309Z";
87074
+ BUILD_SHA = "362c46b798588ed58f200c9d529b3d11b2b2ff73";
87075
+ BUILD_TIME = "2026-10-21T17:31:51.205Z";
87068
87076
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
87069
87077
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
87070
87078
  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.131",
3
+ "version": "0.10.0-main.132",
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": "5ba01b5a98082b32c94a94415030e2581bf3288e",
23
- "builtAt": "2026-10-21T16:56:57.309Z"
22
+ "sha": "362c46b798588ed58f200c9d529b3d11b2b2ff73",
23
+ "builtAt": "2026-10-21T17:31:51.205Z"
24
24
  }
25
25
  }