@vcad/mcp 0.11.0-main.138 → 0.11.0-main.139
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 +1 -1
- package/index.mjs +203 -101
- 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
|
|
9
|
+
Built from e8048d392e648e962e9df6ae719559a9322ba0d8 at 2026-11-07T02:30:11.369Z. Source: https://github.com/ecto/vcad
|
package/index.mjs
CHANGED
|
@@ -11039,9 +11039,9 @@ function workerTransport(worker) {
|
|
|
11039
11039
|
pending2.delete(id);
|
|
11040
11040
|
});
|
|
11041
11041
|
return {
|
|
11042
|
-
request: (req) => new Promise((
|
|
11042
|
+
request: (req) => new Promise((resolve8) => {
|
|
11043
11043
|
const id = next++;
|
|
11044
|
-
pending2.set(id,
|
|
11044
|
+
pending2.set(id, resolve8);
|
|
11045
11045
|
worker.postMessage({ id, req });
|
|
11046
11046
|
}),
|
|
11047
11047
|
dispose: () => worker.terminate()
|
|
@@ -11920,11 +11920,11 @@ var init_analyze = __esm({
|
|
|
11920
11920
|
type: "module"
|
|
11921
11921
|
});
|
|
11922
11922
|
this.worker = worker;
|
|
11923
|
-
this.ready = new Promise((
|
|
11923
|
+
this.ready = new Promise((resolve8, reject) => {
|
|
11924
11924
|
const onMessage = (e) => {
|
|
11925
11925
|
const { type, id, message, analysis } = e.data;
|
|
11926
11926
|
if (type === "ready") {
|
|
11927
|
-
|
|
11927
|
+
resolve8();
|
|
11928
11928
|
return;
|
|
11929
11929
|
}
|
|
11930
11930
|
if (type === "error" && id === null) {
|
|
@@ -11948,9 +11948,9 @@ var init_analyze = __esm({
|
|
|
11948
11948
|
return this.ready;
|
|
11949
11949
|
}
|
|
11950
11950
|
request(msg, transfer = []) {
|
|
11951
|
-
return this.ensureWorker().then(() => new Promise((
|
|
11951
|
+
return this.ensureWorker().then(() => new Promise((resolve8, reject) => {
|
|
11952
11952
|
const id = this.nextId++;
|
|
11953
|
-
this.pending.set(id, { resolve:
|
|
11953
|
+
this.pending.set(id, { resolve: resolve8, reject });
|
|
11954
11954
|
this.worker.postMessage({ ...msg, id }, transfer);
|
|
11955
11955
|
}));
|
|
11956
11956
|
}
|
|
@@ -12567,11 +12567,11 @@ var init_dist = __esm({
|
|
|
12567
12567
|
return;
|
|
12568
12568
|
try {
|
|
12569
12569
|
const worker = new Worker(new URL("./eval-worker.js", import.meta.url), { type: "module" });
|
|
12570
|
-
this.workerReady = new Promise((
|
|
12570
|
+
this.workerReady = new Promise((resolve8, reject) => {
|
|
12571
12571
|
const onMessage = (e) => {
|
|
12572
12572
|
if (e.data.type === "ready") {
|
|
12573
12573
|
worker.removeEventListener("message", onMessage);
|
|
12574
|
-
|
|
12574
|
+
resolve8();
|
|
12575
12575
|
} else if (e.data.type === "error" && e.data.id === null) {
|
|
12576
12576
|
worker.removeEventListener("message", onMessage);
|
|
12577
12577
|
console.warn("[ENGINE] Worker WASM init failed:", e.data.message);
|
|
@@ -12794,7 +12794,7 @@ var init_dist = __esm({
|
|
|
12794
12794
|
const worker = this.worker;
|
|
12795
12795
|
const id = Math.random().toString(36).slice(2);
|
|
12796
12796
|
const skipClash = options.skipClashDetection ?? false;
|
|
12797
|
-
return new Promise((
|
|
12797
|
+
return new Promise((resolve8, reject) => {
|
|
12798
12798
|
const onMessage = (e) => {
|
|
12799
12799
|
if (e.data.id !== id)
|
|
12800
12800
|
return;
|
|
@@ -12804,7 +12804,7 @@ var init_dist = __esm({
|
|
|
12804
12804
|
if (scene.timing && _Engine.DEV) {
|
|
12805
12805
|
_Engine.logTiming(scene.timing, e.data.workerTotalMs);
|
|
12806
12806
|
}
|
|
12807
|
-
|
|
12807
|
+
resolve8(scene);
|
|
12808
12808
|
} else if (e.data.type === "error") {
|
|
12809
12809
|
reject(new Error(e.data.message));
|
|
12810
12810
|
}
|
|
@@ -19237,12 +19237,12 @@ var init_stdio2 = __esm({
|
|
|
19237
19237
|
this.onclose?.();
|
|
19238
19238
|
}
|
|
19239
19239
|
send(message) {
|
|
19240
|
-
return new Promise((
|
|
19240
|
+
return new Promise((resolve8) => {
|
|
19241
19241
|
const json = serializeMessage(message);
|
|
19242
19242
|
if (this._stdout.write(json)) {
|
|
19243
|
-
|
|
19243
|
+
resolve8();
|
|
19244
19244
|
} else {
|
|
19245
|
-
this._stdout.once("drain",
|
|
19245
|
+
this._stdout.once("drain", resolve8);
|
|
19246
19246
|
}
|
|
19247
19247
|
});
|
|
19248
19248
|
}
|
|
@@ -20286,7 +20286,7 @@ var init_protocol = __esm({
|
|
|
20286
20286
|
return;
|
|
20287
20287
|
}
|
|
20288
20288
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
20289
|
-
await new Promise((
|
|
20289
|
+
await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
|
|
20290
20290
|
options?.signal?.throwIfAborted();
|
|
20291
20291
|
}
|
|
20292
20292
|
} catch (error2) {
|
|
@@ -20303,7 +20303,7 @@ var init_protocol = __esm({
|
|
|
20303
20303
|
*/
|
|
20304
20304
|
request(request, resultSchema, options) {
|
|
20305
20305
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
20306
|
-
return new Promise((
|
|
20306
|
+
return new Promise((resolve8, reject) => {
|
|
20307
20307
|
const earlyReject = (error2) => {
|
|
20308
20308
|
reject(error2);
|
|
20309
20309
|
};
|
|
@@ -20381,7 +20381,7 @@ var init_protocol = __esm({
|
|
|
20381
20381
|
if (!parseResult.success) {
|
|
20382
20382
|
reject(parseResult.error);
|
|
20383
20383
|
} else {
|
|
20384
|
-
|
|
20384
|
+
resolve8(parseResult.data);
|
|
20385
20385
|
}
|
|
20386
20386
|
} catch (error2) {
|
|
20387
20387
|
reject(error2);
|
|
@@ -20642,12 +20642,12 @@ var init_protocol = __esm({
|
|
|
20642
20642
|
}
|
|
20643
20643
|
} catch {
|
|
20644
20644
|
}
|
|
20645
|
-
return new Promise((
|
|
20645
|
+
return new Promise((resolve8, reject) => {
|
|
20646
20646
|
if (signal.aborted) {
|
|
20647
20647
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
20648
20648
|
return;
|
|
20649
20649
|
}
|
|
20650
|
-
const timeoutId = setTimeout(
|
|
20650
|
+
const timeoutId = setTimeout(resolve8, interval);
|
|
20651
20651
|
signal.addEventListener("abort", () => {
|
|
20652
20652
|
clearTimeout(timeoutId);
|
|
20653
20653
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -23674,7 +23674,7 @@ var require_compile = __commonJS({
|
|
|
23674
23674
|
const schOrFunc = root.refs[ref];
|
|
23675
23675
|
if (schOrFunc)
|
|
23676
23676
|
return schOrFunc;
|
|
23677
|
-
let _sch =
|
|
23677
|
+
let _sch = resolve8.call(this, root, ref);
|
|
23678
23678
|
if (_sch === void 0) {
|
|
23679
23679
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
23680
23680
|
const { schemaId } = this.opts;
|
|
@@ -23701,7 +23701,7 @@ var require_compile = __commonJS({
|
|
|
23701
23701
|
function sameSchemaEnv(s1, s2) {
|
|
23702
23702
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
23703
23703
|
}
|
|
23704
|
-
function
|
|
23704
|
+
function resolve8(root, ref) {
|
|
23705
23705
|
let sch;
|
|
23706
23706
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
23707
23707
|
ref = sch;
|
|
@@ -24276,7 +24276,7 @@ var require_fast_uri = __commonJS({
|
|
|
24276
24276
|
}
|
|
24277
24277
|
return uri;
|
|
24278
24278
|
}
|
|
24279
|
-
function
|
|
24279
|
+
function resolve8(baseURI, relativeURI, options) {
|
|
24280
24280
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
24281
24281
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
24282
24282
|
schemelessOptions.skipEscape = true;
|
|
@@ -24503,7 +24503,7 @@ var require_fast_uri = __commonJS({
|
|
|
24503
24503
|
var fastUri = {
|
|
24504
24504
|
SCHEMES,
|
|
24505
24505
|
normalize: normalize2,
|
|
24506
|
-
resolve:
|
|
24506
|
+
resolve: resolve8,
|
|
24507
24507
|
resolveComponent,
|
|
24508
24508
|
equal,
|
|
24509
24509
|
serialize,
|
|
@@ -30675,21 +30675,21 @@ var require_react_development = __commonJS({
|
|
|
30675
30675
|
);
|
|
30676
30676
|
actScopeDepth = prevActScopeDepth;
|
|
30677
30677
|
}
|
|
30678
|
-
function recursivelyFlushAsyncActWork(returnValue,
|
|
30678
|
+
function recursivelyFlushAsyncActWork(returnValue, resolve8, reject) {
|
|
30679
30679
|
var queue = ReactSharedInternals.actQueue;
|
|
30680
30680
|
if (null !== queue)
|
|
30681
30681
|
if (0 !== queue.length)
|
|
30682
30682
|
try {
|
|
30683
30683
|
flushActQueue(queue);
|
|
30684
30684
|
enqueueTask(function() {
|
|
30685
|
-
return recursivelyFlushAsyncActWork(returnValue,
|
|
30685
|
+
return recursivelyFlushAsyncActWork(returnValue, resolve8, reject);
|
|
30686
30686
|
});
|
|
30687
30687
|
return;
|
|
30688
30688
|
} catch (error2) {
|
|
30689
30689
|
ReactSharedInternals.thrownErrors.push(error2);
|
|
30690
30690
|
}
|
|
30691
30691
|
else ReactSharedInternals.actQueue = null;
|
|
30692
|
-
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) :
|
|
30692
|
+
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve8(returnValue);
|
|
30693
30693
|
}
|
|
30694
30694
|
function flushActQueue(queue) {
|
|
30695
30695
|
if (!isFlushing) {
|
|
@@ -30876,7 +30876,7 @@ var require_react_development = __commonJS({
|
|
|
30876
30876
|
));
|
|
30877
30877
|
});
|
|
30878
30878
|
return {
|
|
30879
|
-
then: function(
|
|
30879
|
+
then: function(resolve8, reject) {
|
|
30880
30880
|
didAwaitActCall = true;
|
|
30881
30881
|
thenable.then(
|
|
30882
30882
|
function(returnValue) {
|
|
@@ -30886,7 +30886,7 @@ var require_react_development = __commonJS({
|
|
|
30886
30886
|
flushActQueue(queue), enqueueTask(function() {
|
|
30887
30887
|
return recursivelyFlushAsyncActWork(
|
|
30888
30888
|
returnValue,
|
|
30889
|
-
|
|
30889
|
+
resolve8,
|
|
30890
30890
|
reject
|
|
30891
30891
|
);
|
|
30892
30892
|
});
|
|
@@ -30900,7 +30900,7 @@ var require_react_development = __commonJS({
|
|
|
30900
30900
|
ReactSharedInternals.thrownErrors.length = 0;
|
|
30901
30901
|
reject(_thrownError);
|
|
30902
30902
|
}
|
|
30903
|
-
} else
|
|
30903
|
+
} else resolve8(returnValue);
|
|
30904
30904
|
},
|
|
30905
30905
|
function(error2) {
|
|
30906
30906
|
popActScope(prevActQueue, prevActScopeDepth);
|
|
@@ -30922,15 +30922,15 @@ var require_react_development = __commonJS({
|
|
|
30922
30922
|
if (0 < ReactSharedInternals.thrownErrors.length)
|
|
30923
30923
|
throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
|
|
30924
30924
|
return {
|
|
30925
|
-
then: function(
|
|
30925
|
+
then: function(resolve8, reject) {
|
|
30926
30926
|
didAwaitActCall = true;
|
|
30927
30927
|
0 === prevActScopeDepth ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
|
|
30928
30928
|
return recursivelyFlushAsyncActWork(
|
|
30929
30929
|
returnValue$jscomp$0,
|
|
30930
|
-
|
|
30930
|
+
resolve8,
|
|
30931
30931
|
reject
|
|
30932
30932
|
);
|
|
30933
|
-
})) :
|
|
30933
|
+
})) : resolve8(returnValue$jscomp$0);
|
|
30934
30934
|
}
|
|
30935
30935
|
};
|
|
30936
30936
|
};
|
|
@@ -41804,9 +41804,53 @@ var init_CHANGELOG = __esm({
|
|
|
41804
41804
|
CHANGELOG_default = {
|
|
41805
41805
|
$schema: "./changelog.schema.json",
|
|
41806
41806
|
entries: [
|
|
41807
|
+
{
|
|
41808
|
+
id: "2026-11-06-export-all-documents",
|
|
41809
|
+
version: "0.11.0",
|
|
41810
|
+
date: "2026-11-06",
|
|
41811
|
+
category: "feat",
|
|
41812
|
+
title: "Export all your documents as a zip",
|
|
41813
|
+
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.",
|
|
41814
|
+
features: [
|
|
41815
|
+
"export",
|
|
41816
|
+
"cloud-sync",
|
|
41817
|
+
"vcad-2"
|
|
41818
|
+
],
|
|
41819
|
+
mcpTools: [
|
|
41820
|
+
"open_in_app",
|
|
41821
|
+
"open_in_browser"
|
|
41822
|
+
]
|
|
41823
|
+
},
|
|
41824
|
+
{
|
|
41825
|
+
id: "2026-10-28-render-timings-perf",
|
|
41826
|
+
version: "0.11.0",
|
|
41827
|
+
date: "2026-10-28",
|
|
41828
|
+
category: "perf",
|
|
41829
|
+
title: "Faster assembly renders, plus a --timings breakdown",
|
|
41830
|
+
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.",
|
|
41831
|
+
features: [
|
|
41832
|
+
"render",
|
|
41833
|
+
"performance",
|
|
41834
|
+
"cli"
|
|
41835
|
+
],
|
|
41836
|
+
mcpTools: []
|
|
41837
|
+
},
|
|
41838
|
+
{
|
|
41839
|
+
id: "2026-10-27-sphere-cube-seams",
|
|
41840
|
+
version: "0.11.0",
|
|
41841
|
+
date: "2026-10-27",
|
|
41842
|
+
category: "fix",
|
|
41843
|
+
title: "Clean sphere/box boolean seams at every resolution",
|
|
41844
|
+
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.",
|
|
41845
|
+
features: [
|
|
41846
|
+
"booleans",
|
|
41847
|
+
"tessellation"
|
|
41848
|
+
],
|
|
41849
|
+
mcpTools: []
|
|
41850
|
+
},
|
|
41807
41851
|
{
|
|
41808
41852
|
id: "2026-10-27-section-hatch-all-loops",
|
|
41809
|
-
version: "0.
|
|
41853
|
+
version: "0.11.0",
|
|
41810
41854
|
date: "2026-10-27",
|
|
41811
41855
|
category: "fix",
|
|
41812
41856
|
title: "Section views hatch every cut region",
|
|
@@ -41817,6 +41861,32 @@ var init_CHANGELOG = __esm({
|
|
|
41817
41861
|
],
|
|
41818
41862
|
mcpTools: []
|
|
41819
41863
|
},
|
|
41864
|
+
{
|
|
41865
|
+
id: "2026-10-27-onshape-step-import",
|
|
41866
|
+
version: "0.11.0",
|
|
41867
|
+
date: "2026-10-27",
|
|
41868
|
+
category: "fix",
|
|
41869
|
+
title: "STEP import: Onshape files import and render solid",
|
|
41870
|
+
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.",
|
|
41871
|
+
features: [
|
|
41872
|
+
"step-import",
|
|
41873
|
+
"tessellation",
|
|
41874
|
+
"render"
|
|
41875
|
+
]
|
|
41876
|
+
},
|
|
41877
|
+
{
|
|
41878
|
+
id: "2026-10-27-exact-render-step-curved-faces",
|
|
41879
|
+
version: "0.11.0",
|
|
41880
|
+
date: "2026-10-27",
|
|
41881
|
+
category: "fix",
|
|
41882
|
+
title: "Exact render shows curved faces of imported STEP parts",
|
|
41883
|
+
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.",
|
|
41884
|
+
features: [
|
|
41885
|
+
"render",
|
|
41886
|
+
"raytrace",
|
|
41887
|
+
"step-import"
|
|
41888
|
+
]
|
|
41889
|
+
},
|
|
41820
41890
|
{
|
|
41821
41891
|
id: "2026-10-27-cargo-install-vcad-cli",
|
|
41822
41892
|
version: "0.11.0",
|
|
@@ -56840,8 +56910,8 @@ async function openBridge(createServer2, clientInfo, clientCapabilities, hooks)
|
|
|
56840
56910
|
await server.connect(serverSide);
|
|
56841
56911
|
const rpc = (method, params) => {
|
|
56842
56912
|
const id = nextId3++;
|
|
56843
|
-
return new Promise((
|
|
56844
|
-
pending2.set(id, (m) =>
|
|
56913
|
+
return new Promise((resolve8) => {
|
|
56914
|
+
pending2.set(id, (m) => resolve8(m));
|
|
56845
56915
|
void clientSide.send({
|
|
56846
56916
|
jsonrpc: "2.0",
|
|
56847
56917
|
id,
|
|
@@ -57178,8 +57248,8 @@ function taskElicitation(bridge, reqParams) {
|
|
|
57178
57248
|
method: "elicitation/create",
|
|
57179
57249
|
params: cleanParams
|
|
57180
57250
|
};
|
|
57181
|
-
return new Promise((
|
|
57182
|
-
record2.pendingInputs.set(key3,
|
|
57251
|
+
return new Promise((resolve8) => {
|
|
57252
|
+
record2.pendingInputs.set(key3, resolve8);
|
|
57183
57253
|
touchTask(record2, "input_required", "waiting for client input");
|
|
57184
57254
|
});
|
|
57185
57255
|
}
|
|
@@ -57204,11 +57274,11 @@ function handleTaskMethod(id, method, params) {
|
|
|
57204
57274
|
if (method === "tasks/update") {
|
|
57205
57275
|
const responses = params.inputResponses && typeof params.inputResponses === "object" ? params.inputResponses : {};
|
|
57206
57276
|
for (const [key3, response] of Object.entries(responses)) {
|
|
57207
|
-
const
|
|
57208
|
-
if (!
|
|
57277
|
+
const resolve8 = record2.pendingInputs.get(key3);
|
|
57278
|
+
if (!resolve8) continue;
|
|
57209
57279
|
record2.pendingInputs.delete(key3);
|
|
57210
57280
|
delete record2.inputRequests[key3];
|
|
57211
|
-
|
|
57281
|
+
resolve8(response);
|
|
57212
57282
|
}
|
|
57213
57283
|
if (record2.status === "input_required" && Object.keys(record2.inputRequests).length === 0) {
|
|
57214
57284
|
touchTask(record2, "working", `running ${record2.toolName}`);
|
|
@@ -57220,10 +57290,10 @@ function handleTaskMethod(id, method, params) {
|
|
|
57220
57290
|
}
|
|
57221
57291
|
record2.cancelRequested = true;
|
|
57222
57292
|
if (record2.status === "working" || record2.status === "input_required") {
|
|
57223
|
-
for (const [key3,
|
|
57293
|
+
for (const [key3, resolve8] of record2.pendingInputs) {
|
|
57224
57294
|
record2.pendingInputs.delete(key3);
|
|
57225
57295
|
delete record2.inputRequests[key3];
|
|
57226
|
-
|
|
57296
|
+
resolve8({ action: "cancel" });
|
|
57227
57297
|
}
|
|
57228
57298
|
touchTask(record2, "cancelled", "cancelled by client");
|
|
57229
57299
|
}
|
|
@@ -57860,7 +57930,8 @@ var init_tool_metadata = __esm({
|
|
|
57860
57930
|
import_altium: { title: "Import Altium", annotations: RW },
|
|
57861
57931
|
import_altium_library: { title: "Import Altium Library", annotations: RO },
|
|
57862
57932
|
import_eagle: { title: "Import EAGLE", annotations: RW },
|
|
57863
|
-
|
|
57933
|
+
open_in_app: { title: "Open in vcad", annotations: RW },
|
|
57934
|
+
open_in_browser: { title: "Open in vcad (legacy name)", annotations: RW },
|
|
57864
57935
|
// ── Physics gym ────────────────────────────────────────────────────────
|
|
57865
57936
|
create_robot_env: { title: "Create Robot Env", annotations: RW },
|
|
57866
57937
|
gym_step: { title: "Gym Step", annotations: RW },
|
|
@@ -58099,7 +58170,7 @@ function normalizeOp(op, index) {
|
|
|
58099
58170
|
return { name, args };
|
|
58100
58171
|
}
|
|
58101
58172
|
function resolveSymbolicRefs(args, createdIds, index) {
|
|
58102
|
-
const
|
|
58173
|
+
const resolve8 = (v) => {
|
|
58103
58174
|
if (typeof v !== "string") return v;
|
|
58104
58175
|
const m = SYMBOLIC_REF.exec(v);
|
|
58105
58176
|
if (!m) return v;
|
|
@@ -58119,15 +58190,15 @@ function resolveSymbolicRefs(args, createdIds, index) {
|
|
|
58119
58190
|
};
|
|
58120
58191
|
const out = { ...args };
|
|
58121
58192
|
for (const key3 of ["part_id", "node_id"]) {
|
|
58122
|
-
if (key3 in out) out[key3] =
|
|
58193
|
+
if (key3 in out) out[key3] = resolve8(out[key3]);
|
|
58123
58194
|
}
|
|
58124
58195
|
if (out.params && typeof out.params === "object" && !Array.isArray(out.params)) {
|
|
58125
58196
|
const params = { ...out.params };
|
|
58126
58197
|
for (const key3 of ["child", "left", "right", "sketch"]) {
|
|
58127
|
-
if (key3 in params) params[key3] =
|
|
58198
|
+
if (key3 in params) params[key3] = resolve8(params[key3]);
|
|
58128
58199
|
}
|
|
58129
58200
|
if (Array.isArray(params.sketches)) {
|
|
58130
|
-
params.sketches = params.sketches.map(
|
|
58201
|
+
params.sketches = params.sketches.map(resolve8);
|
|
58131
58202
|
}
|
|
58132
58203
|
out.params = params;
|
|
58133
58204
|
}
|
|
@@ -64060,7 +64131,7 @@ async function flattenSchematic(sheet, netlister) {
|
|
|
64060
64131
|
if (def.body.hierarchy) {
|
|
64061
64132
|
err9(`Sheet '${def.name}' body has its own hierarchy \u2014 nest sheets with \`instances\` instead (ignored)`);
|
|
64062
64133
|
}
|
|
64063
|
-
const
|
|
64134
|
+
const resolve8 = (name) => {
|
|
64064
64135
|
if (ports.has(name)) {
|
|
64065
64136
|
const bound = binding.get(name);
|
|
64066
64137
|
if (bound !== void 0) return bound;
|
|
@@ -64088,7 +64159,7 @@ async function flattenSchematic(sheet, netlister) {
|
|
|
64088
64159
|
if (pins.length === 0) continue;
|
|
64089
64160
|
if (isAutoName(name) && pins.length < 2) continue;
|
|
64090
64161
|
usedNames.add(name);
|
|
64091
|
-
const flat =
|
|
64162
|
+
const flat = resolve8(name);
|
|
64092
64163
|
if (!ports.has(name) && !globals.has(name) && rootNames.has(flat)) {
|
|
64093
64164
|
err9(
|
|
64094
64165
|
`Net scope collision: local net '${name}' of sheet instance '${path}' flattens to '${flat}', which the root sheet also uses`
|
|
@@ -64112,9 +64183,9 @@ async function flattenSchematic(sheet, netlister) {
|
|
|
64112
64183
|
warn(`Hierarchical port '${port}' of sheet '${def.name}' connects to nothing inside the sheet`);
|
|
64113
64184
|
}
|
|
64114
64185
|
}
|
|
64115
|
-
for (const flag of def.body.power_flags ?? []) outFlags.push({ ...flag, net:
|
|
64186
|
+
for (const flag of def.body.power_flags ?? []) outFlags.push({ ...flag, net: resolve8(flag.net) });
|
|
64116
64187
|
instances.push({ path, sheet: def.name, refs });
|
|
64117
|
-
await elaborateAll(def.instances ?? [], path, offset,
|
|
64188
|
+
await elaborateAll(def.instances ?? [], path, offset, resolve8, stack);
|
|
64118
64189
|
};
|
|
64119
64190
|
await elaborateAll(h.instances ?? [], "", { x: 0, y: 0 }, (n) => n, []);
|
|
64120
64191
|
const nets = {};
|
|
@@ -82277,6 +82348,8 @@ var init_import_pcb = __esm({
|
|
|
82277
82348
|
|
|
82278
82349
|
// src/tools/share.ts
|
|
82279
82350
|
import { gzipSync } from "node:zlib";
|
|
82351
|
+
import * as os2 from "node:os";
|
|
82352
|
+
import * as nodePath2 from "node:path";
|
|
82280
82353
|
function validateAppUrl(raw) {
|
|
82281
82354
|
try {
|
|
82282
82355
|
const url = new URL(raw);
|
|
@@ -82308,56 +82381,75 @@ function compressForUrl(compact2) {
|
|
|
82308
82381
|
const compressed = gzipSync(Buffer.from(compact2, "utf-8"), { level: 9 });
|
|
82309
82382
|
return base64urlEncode(compressed);
|
|
82310
82383
|
}
|
|
82311
|
-
function
|
|
82312
|
-
const
|
|
82313
|
-
|
|
82314
|
-
|
|
82315
|
-
|
|
82316
|
-
);
|
|
82384
|
+
function buildAppLink(doc, opts = {}) {
|
|
82385
|
+
const params = new URLSearchParams();
|
|
82386
|
+
const fileStore = opts.fileStore ?? useFileSessionStore();
|
|
82387
|
+
let via;
|
|
82388
|
+
if (opts.documentId && fileStore && SESSION_ID_RE.test(opts.documentId)) {
|
|
82389
|
+
params.set("session", opts.documentId);
|
|
82390
|
+
const dir = sessionDir();
|
|
82391
|
+
const defaultDir = nodePath2.join(os2.homedir(), ".vcad", "mcp-sessions");
|
|
82392
|
+
if (nodePath2.resolve(dir) !== nodePath2.resolve(defaultDir)) {
|
|
82393
|
+
params.set("dir", dir);
|
|
82394
|
+
}
|
|
82395
|
+
via = "session";
|
|
82396
|
+
} else {
|
|
82397
|
+
params.set("doc", compressForUrl(JSON.stringify(doc)));
|
|
82398
|
+
via = "inline";
|
|
82317
82399
|
}
|
|
82318
|
-
|
|
82319
|
-
|
|
82400
|
+
if (opts.name) params.set("name", opts.name);
|
|
82401
|
+
return { url: `vcad://open?${params.toString()}`, via };
|
|
82402
|
+
}
|
|
82403
|
+
function legacyWebLink(doc, name) {
|
|
82320
82404
|
let payload;
|
|
82321
|
-
let format;
|
|
82322
82405
|
try {
|
|
82323
82406
|
payload = toVCode2(doc);
|
|
82324
|
-
format = "vcode";
|
|
82325
82407
|
} catch {
|
|
82326
82408
|
payload = JSON.stringify(doc);
|
|
82327
|
-
format = "json";
|
|
82328
82409
|
}
|
|
82329
|
-
const encoded = compressForUrl(payload);
|
|
82330
82410
|
const baseUrl = validateAppUrl(process.env.VCAD_APP_URL || "https://vcad.io");
|
|
82331
82411
|
const params = new URLSearchParams();
|
|
82332
|
-
params.set("doc",
|
|
82333
|
-
if (name)
|
|
82334
|
-
|
|
82412
|
+
params.set("doc", compressForUrl(payload));
|
|
82413
|
+
if (name) params.set("name", name);
|
|
82414
|
+
return `${baseUrl}/#/new?${params.toString()}`;
|
|
82415
|
+
}
|
|
82416
|
+
function openInApp(input, engine) {
|
|
82417
|
+
const { document_id, document: docInput, name } = input;
|
|
82418
|
+
if (!document_id && !docInput) {
|
|
82419
|
+
throw new Error(
|
|
82420
|
+
"Pass `document_id` (a live session) or `document` (inline IR)."
|
|
82421
|
+
);
|
|
82335
82422
|
}
|
|
82336
|
-
const
|
|
82337
|
-
const
|
|
82338
|
-
const
|
|
82339
|
-
|
|
82340
|
-
|
|
82341
|
-
|
|
82342
|
-
|
|
82343
|
-
|
|
82344
|
-
|
|
82345
|
-
|
|
82346
|
-
|
|
82347
|
-
|
|
82348
|
-
|
|
82349
|
-
|
|
82350
|
-
|
|
82351
|
-
|
|
82352
|
-
|
|
82423
|
+
const live = document_id ? getSession(document_id) : parseDocument(docInput);
|
|
82424
|
+
const doc = engine ? engine.bakeStepImports(live) : live;
|
|
82425
|
+
const baked = doc !== live;
|
|
82426
|
+
const link = buildAppLink(doc, {
|
|
82427
|
+
documentId: baked ? void 0 : document_id,
|
|
82428
|
+
name
|
|
82429
|
+
});
|
|
82430
|
+
const lines = [
|
|
82431
|
+
`Open in vcad:
|
|
82432
|
+
${link.url}`,
|
|
82433
|
+
"",
|
|
82434
|
+
`Don't have the vcad app? Download it: ${VCAD_DOWNLOAD_URL}`,
|
|
82435
|
+
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.)`
|
|
82436
|
+
];
|
|
82437
|
+
if (/^(1|true|on)$/i.test(process.env.VCAD_LEGACY_WEB_LINKS || "")) {
|
|
82438
|
+
lines.push("", `Legacy web link (vcad.io, retiring):
|
|
82439
|
+
${legacyWebLink(doc, name)}`);
|
|
82440
|
+
}
|
|
82441
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
82353
82442
|
}
|
|
82354
|
-
var openInBrowserSchema, toolDefs49;
|
|
82443
|
+
var VCAD_DOWNLOAD_URL, SESSION_ID_RE, openInBrowserSchema, DESCRIPTION, toolDefs49;
|
|
82355
82444
|
var init_share = __esm({
|
|
82356
82445
|
"src/tools/share.ts"() {
|
|
82357
82446
|
"use strict";
|
|
82358
82447
|
init_dist2();
|
|
82359
82448
|
init_tool_def();
|
|
82360
82449
|
init_session_core();
|
|
82450
|
+
init_session_store();
|
|
82451
|
+
VCAD_DOWNLOAD_URL = "https://vcad.io/download";
|
|
82452
|
+
SESSION_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
82361
82453
|
openInBrowserSchema = {
|
|
82362
82454
|
type: "object",
|
|
82363
82455
|
properties: {
|
|
@@ -82375,13 +82467,22 @@ var init_share = __esm({
|
|
|
82375
82467
|
}
|
|
82376
82468
|
}
|
|
82377
82469
|
};
|
|
82470
|
+
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
82471
|
toolDefs49 = [
|
|
82472
|
+
{
|
|
82473
|
+
name: "open_in_app",
|
|
82474
|
+
pack: null,
|
|
82475
|
+
description: DESCRIPTION,
|
|
82476
|
+
inputSchema: openInBrowserSchema,
|
|
82477
|
+
handler: (a, c) => openInApp(a, c.engine),
|
|
82478
|
+
behavior: behavior({})
|
|
82479
|
+
},
|
|
82379
82480
|
{
|
|
82380
82481
|
name: "open_in_browser",
|
|
82381
82482
|
pack: null,
|
|
82382
|
-
description: "
|
|
82483
|
+
description: "Legacy alias of `open_in_app` (the vcad.io web editor is retiring). " + DESCRIPTION,
|
|
82383
82484
|
inputSchema: openInBrowserSchema,
|
|
82384
|
-
handler: (a, c) =>
|
|
82485
|
+
handler: (a, c) => openInApp(a, c.engine),
|
|
82385
82486
|
behavior: behavior({})
|
|
82386
82487
|
}
|
|
82387
82488
|
];
|
|
@@ -85791,13 +85892,13 @@ ${issues.map((i) => i.problem).join("\n")}`
|
|
|
85791
85892
|
}
|
|
85792
85893
|
async function hasFfmpeg() {
|
|
85793
85894
|
if (ffmpegAvailable !== null) return ffmpegAvailable;
|
|
85794
|
-
ffmpegAvailable = await new Promise((
|
|
85895
|
+
ffmpegAvailable = await new Promise((resolve8) => {
|
|
85795
85896
|
try {
|
|
85796
85897
|
const p = spawn("ffmpeg", ["-version"], { stdio: "ignore" });
|
|
85797
|
-
p.on("error", () =>
|
|
85798
|
-
p.on("exit", (code) =>
|
|
85898
|
+
p.on("error", () => resolve8(false));
|
|
85899
|
+
p.on("exit", (code) => resolve8(code === 0));
|
|
85799
85900
|
} catch {
|
|
85800
|
-
|
|
85901
|
+
resolve8(false);
|
|
85801
85902
|
}
|
|
85802
85903
|
});
|
|
85803
85904
|
return ffmpegAvailable;
|
|
@@ -85836,13 +85937,13 @@ function startMp4Encoder(width, height, fps) {
|
|
|
85836
85937
|
const exitError = (code) => new Error(
|
|
85837
85938
|
`ffmpeg exited ${code}: ${Buffer.concat(errChunks).toString().slice(-400)}`
|
|
85838
85939
|
);
|
|
85839
|
-
const done = new Promise((
|
|
85940
|
+
const done = new Promise((resolve8, reject) => {
|
|
85840
85941
|
p.on("error", (e) => {
|
|
85841
85942
|
failure = e;
|
|
85842
85943
|
reject(e);
|
|
85843
85944
|
});
|
|
85844
85945
|
p.on("close", (code) => {
|
|
85845
|
-
if (code === 0)
|
|
85946
|
+
if (code === 0) resolve8(Buffer.concat(out));
|
|
85846
85947
|
else {
|
|
85847
85948
|
failure ??= exitError(code);
|
|
85848
85949
|
reject(failure);
|
|
@@ -85853,15 +85954,15 @@ function startMp4Encoder(width, height, fps) {
|
|
|
85853
85954
|
});
|
|
85854
85955
|
return {
|
|
85855
85956
|
writeFrame(rgba) {
|
|
85856
|
-
return new Promise((
|
|
85957
|
+
return new Promise((resolve8, reject) => {
|
|
85857
85958
|
if (failure) return reject(failure);
|
|
85858
85959
|
if (p.exitCode !== null || p.stdin.destroyed) {
|
|
85859
85960
|
return reject(failure ?? exitError(p.exitCode));
|
|
85860
85961
|
}
|
|
85861
|
-
if (p.stdin.write(rgba)) return
|
|
85962
|
+
if (p.stdin.write(rgba)) return resolve8();
|
|
85862
85963
|
const onDrain = () => {
|
|
85863
85964
|
p.removeListener("close", onClose);
|
|
85864
|
-
|
|
85965
|
+
resolve8();
|
|
85865
85966
|
};
|
|
85866
85967
|
const onClose = () => {
|
|
85867
85968
|
p.stdin.removeListener("drain", onDrain);
|
|
@@ -86403,7 +86504,7 @@ function buildInstructions(kernelPrompt) {
|
|
|
86403
86504
|
"Workflow: `open_document` \u2192 author \u2192 see \u2192 measure \u2192 ship.",
|
|
86404
86505
|
"- 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
86506
|
"- 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 `
|
|
86507
|
+
"- Ship with `export_cad` (STL/GLB/STEP) or `open_in_app` (vcad:// deep link into the native app).",
|
|
86407
86508
|
"- Fix in place: when geometry is wrong, prefer `update` on the offending node over deleting parts and starting over.",
|
|
86408
86509
|
"- 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
86510
|
"- 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 +87404,8 @@ var init_server3 = __esm({
|
|
|
87303
87404
|
init_order_feed();
|
|
87304
87405
|
init_animate();
|
|
87305
87406
|
PKG_VERSION = (() => {
|
|
87306
|
-
if ("0.11.0-main.
|
|
87307
|
-
return "0.11.0-main.
|
|
87407
|
+
if ("0.11.0-main.139") {
|
|
87408
|
+
return "0.11.0-main.139";
|
|
87308
87409
|
}
|
|
87309
87410
|
try {
|
|
87310
87411
|
const req = createRequire2(import.meta.url);
|
|
@@ -87313,8 +87414,8 @@ var init_server3 = __esm({
|
|
|
87313
87414
|
return "0.0.0";
|
|
87314
87415
|
}
|
|
87315
87416
|
})();
|
|
87316
|
-
BUILD_SHA = "
|
|
87317
|
-
BUILD_TIME = "2026-
|
|
87417
|
+
BUILD_SHA = "e8048d392e648e962e9df6ae719559a9322ba0d8";
|
|
87418
|
+
BUILD_TIME = "2026-11-07T02:30:11.369Z";
|
|
87318
87419
|
SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
|
|
87319
87420
|
VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
|
|
87320
87421
|
INSTANCE_ID = randomUUID7().slice(0, 8);
|
|
@@ -87518,6 +87619,7 @@ var init_server3 = __esm({
|
|
|
87518
87619
|
"import_altium",
|
|
87519
87620
|
"import_altium_library",
|
|
87520
87621
|
"import_eagle",
|
|
87622
|
+
"open_in_app",
|
|
87521
87623
|
"open_in_browser",
|
|
87522
87624
|
// ── Physics gym ────────────────────────────────────────────
|
|
87523
87625
|
"create_robot_env",
|
|
@@ -87687,11 +87789,11 @@ var init_index = __esm({
|
|
|
87687
87789
|
// src/npx-entry.ts
|
|
87688
87790
|
init_dist();
|
|
87689
87791
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
87690
|
-
import { dirname as dirname5, join as
|
|
87792
|
+
import { dirname as dirname5, join as join6 } from "node:path";
|
|
87691
87793
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
87692
87794
|
primeKernelWasm(
|
|
87693
87795
|
readFileSync10(
|
|
87694
|
-
|
|
87796
|
+
join6(
|
|
87695
87797
|
dirname5(fileURLToPath3(import.meta.url)),
|
|
87696
87798
|
"vcad_kernel_wasm_bg.wasm"
|
|
87697
87799
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vcad/mcp",
|
|
3
|
-
"version": "0.11.0-main.
|
|
3
|
+
"version": "0.11.0-main.139",
|
|
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": "
|
|
23
|
-
"builtAt": "2026-
|
|
22
|
+
"sha": "e8048d392e648e962e9df6ae719559a9322ba0d8",
|
|
23
|
+
"builtAt": "2026-11-07T02:30:11.369Z"
|
|
24
24
|
}
|
|
25
25
|
}
|