@vcad/mcp 0.9.4-main.39 → 0.9.4-main.41
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 +425 -87
- package/package.json +3 -3
- package/vcad_kernel_wasm_bg.wasm +0 -0
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 b00f071e4b839c6448769107ed84182597d763ed at 2026-07-26T14:41:39.682Z. Source: https://github.com/ecto/vcad
|
package/index.mjs
CHANGED
|
@@ -165,6 +165,7 @@ __export(vcad_kernel_wasm_exports, {
|
|
|
165
165
|
estimate_cost_for_process: () => estimate_cost_for_process,
|
|
166
166
|
eulerXyzDegToQuat: () => eulerXyzDegToQuat,
|
|
167
167
|
evalVcadSource: () => evalVcadSource,
|
|
168
|
+
evalVcadSourceParametric: () => evalVcadSourceParametric,
|
|
168
169
|
evalVcadSourceWithModules: () => evalVcadSourceWithModules,
|
|
169
170
|
evaluateDocument: () => evaluateDocument,
|
|
170
171
|
evaluateSheetMetalChain: () => evaluateSheetMetalChain,
|
|
@@ -1777,6 +1778,17 @@ function evalVcadSource(source) {
|
|
|
1777
1778
|
}
|
|
1778
1779
|
return takeFromExternrefTable0(ret[0]);
|
|
1779
1780
|
}
|
|
1781
|
+
function evalVcadSourceParametric(source, modules_json) {
|
|
1782
|
+
const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1783
|
+
const len0 = WASM_VECTOR_LEN;
|
|
1784
|
+
var ptr1 = isLikeNone(modules_json) ? 0 : passStringToWasm0(modules_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1785
|
+
var len1 = WASM_VECTOR_LEN;
|
|
1786
|
+
const ret = wasm.evalVcadSourceParametric(ptr0, len0, ptr1, len1);
|
|
1787
|
+
if (ret[2]) {
|
|
1788
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
1789
|
+
}
|
|
1790
|
+
return takeFromExternrefTable0(ret[0]);
|
|
1791
|
+
}
|
|
1780
1792
|
function evalVcadSourceWithModules(source, modules_json) {
|
|
1781
1793
|
const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1782
1794
|
const len0 = WASM_VECTOR_LEN;
|
|
@@ -8984,6 +8996,38 @@ function costSheetMetalChain(chain, kernel2, rates, quantity2 = 1) {
|
|
|
8984
8996
|
}
|
|
8985
8997
|
return { breakdown: parsed.breakdown, rates: parsed.rates };
|
|
8986
8998
|
}
|
|
8999
|
+
function flattenSolidToSheetMetal(mesh, kernel2, options = {}) {
|
|
9000
|
+
if (!kernel2.flattenSolidToSheetMetal) {
|
|
9001
|
+
throw new Error("kernel.flattenSolidToSheetMetal not available \u2014 rebuild @vcad/kernel-wasm");
|
|
9002
|
+
}
|
|
9003
|
+
const request = {
|
|
9004
|
+
positions: Array.from(mesh.positions),
|
|
9005
|
+
indices: Array.from(mesh.indices),
|
|
9006
|
+
material: options.material,
|
|
9007
|
+
manualK: options.manualK,
|
|
9008
|
+
shopProfile: options.shopProfile,
|
|
9009
|
+
volumeTolFrac: options.volumeTolFrac,
|
|
9010
|
+
planeAngleTolDeg: options.planeAngleTolDeg,
|
|
9011
|
+
planeOffsetTol: options.planeOffsetTol
|
|
9012
|
+
};
|
|
9013
|
+
const parsed = JSON.parse(kernel2.flattenSolidToSheetMetal(JSON.stringify(request)));
|
|
9014
|
+
if (parsed.error) {
|
|
9015
|
+
throw new Error(parsed.error);
|
|
9016
|
+
}
|
|
9017
|
+
return {
|
|
9018
|
+
flatPattern: parsed.flat_pattern,
|
|
9019
|
+
model: parsed.model,
|
|
9020
|
+
dxf: parsed.dxf,
|
|
9021
|
+
violations: parsed.violations,
|
|
9022
|
+
thickness: parsed.thickness,
|
|
9023
|
+
panels: parsed.panels,
|
|
9024
|
+
bends: parsed.bends,
|
|
9025
|
+
solidVolumeMm3: parsed.solid_volume_mm3,
|
|
9026
|
+
recoveredVolumeMm3: parsed.recovered_volume_mm3,
|
|
9027
|
+
volumeErrorFrac: parsed.volume_error_frac,
|
|
9028
|
+
warnings: parsed.warnings ?? []
|
|
9029
|
+
};
|
|
9030
|
+
}
|
|
8987
9031
|
var DEFAULT_SHOP_PROFILE, DEFAULT_COST_RATES, DEFAULT_NESTING_PARAMS;
|
|
8988
9032
|
var init_sheet_metal = __esm({
|
|
8989
9033
|
"../engine/dist/sheet-metal.js"() {
|
|
@@ -11526,6 +11570,7 @@ var init_dist = __esm({
|
|
|
11526
11570
|
WasmAnnotationLayer: wasmModule7.WasmAnnotationLayer,
|
|
11527
11571
|
projectMesh: wasmModule7.projectMesh,
|
|
11528
11572
|
importStepBuffer: wasmModule7.importStepBuffer,
|
|
11573
|
+
documentToStepBuffer: wasmModule7.documentToStepBuffer,
|
|
11529
11574
|
importUrdfBuffer: wasmModule7.importUrdfBuffer,
|
|
11530
11575
|
exportProjectedViewToDxf: wasmModule7.exportProjectedViewToDxf,
|
|
11531
11576
|
offsetSectionMesh: wasmModule7.offsetSectionMesh,
|
|
@@ -11551,6 +11596,7 @@ var init_dist = __esm({
|
|
|
11551
11596
|
getSheetMetalBendTable: wasmModule7.getSheetMetalBendTable,
|
|
11552
11597
|
getSheetMetalShopCatalog: wasmModule7.getSheetMetalShopCatalog,
|
|
11553
11598
|
sheetMetalFoldedStep: wasmModule7.sheetMetalFoldedStep,
|
|
11599
|
+
flattenSolidToSheetMetal: wasmModule7.flattenSolidToSheetMetal,
|
|
11554
11600
|
mesh_clearance: wasmModule7.mesh_clearance,
|
|
11555
11601
|
topologyOptimizeBox: wasmModule7.topologyOptimizeBox,
|
|
11556
11602
|
topologyOptimizeMesh: wasmModule7.topologyOptimizeMesh,
|
|
@@ -12127,6 +12173,12 @@ var init_dist = __esm({
|
|
|
12127
12173
|
nestSheetMetalParts(parts, params) {
|
|
12128
12174
|
return nestSheetMetalParts2(parts, this.kernel, params);
|
|
12129
12175
|
}
|
|
12176
|
+
/** Recover a flat pattern (panels, bends, DXF) from a solid part's mesh —
|
|
12177
|
+
* the mechanical counterpart of `board_from_solid`. Throws when the solid
|
|
12178
|
+
* is not constant-thickness sheet. */
|
|
12179
|
+
flattenSolidToSheetMetal(mesh, options) {
|
|
12180
|
+
return flattenSolidToSheetMetal(mesh, this.kernel, options);
|
|
12181
|
+
}
|
|
12130
12182
|
/** Compute a feasible bend sequence (outermost-first) for the
|
|
12131
12183
|
* sheet-metal part in `doc`. Returns `null` if there is none. */
|
|
12132
12184
|
sheetMetalSequence(doc) {
|
|
@@ -12202,6 +12254,19 @@ var init_dist = __esm({
|
|
|
12202
12254
|
return null;
|
|
12203
12255
|
return foldedSheetMetalStep(chain, this.kernel);
|
|
12204
12256
|
}
|
|
12257
|
+
/**
|
|
12258
|
+
* Export the document's scene roots to a STEP AP214 buffer, preserving
|
|
12259
|
+
* BRep through booleans, transforms, fillets, and sweeps — one STEP body
|
|
12260
|
+
* per visible root. Throws when a root evaluated to mesh-only geometry
|
|
12261
|
+
* (the kernel error names the offending roots) or when the loaded WASM
|
|
12262
|
+
* kernel predates the binding.
|
|
12263
|
+
*/
|
|
12264
|
+
documentStep(doc) {
|
|
12265
|
+
if (!this.kernel.documentToStepBuffer) {
|
|
12266
|
+
throw new Error("documentToStepBuffer is not available in this kernel build \u2014 rebuild the WASM kernel");
|
|
12267
|
+
}
|
|
12268
|
+
return this.kernel.documentToStepBuffer(JSON.stringify(doc));
|
|
12269
|
+
}
|
|
12205
12270
|
/** Create a detail view (magnified region) from a projected view.
|
|
12206
12271
|
*
|
|
12207
12272
|
* @param view - The parent projected view
|
|
@@ -40977,6 +41042,23 @@ var init_CHANGELOG = __esm({
|
|
|
40977
41042
|
"verify_receipt"
|
|
40978
41043
|
]
|
|
40979
41044
|
},
|
|
41045
|
+
{
|
|
41046
|
+
id: "2026-07-26-step-export-booleans",
|
|
41047
|
+
version: "0.9.4",
|
|
41048
|
+
date: "2026-07-26",
|
|
41049
|
+
category: "feat",
|
|
41050
|
+
title: "STEP export works on real parts, booleans included",
|
|
41051
|
+
summary: "STEP AP214 export now serializes the evaluated BRep \u2014 booleans, transforms, fillets, and sweeps keep analytic faces \u2014 with one named body per part; mesh-only parts are refused by name.",
|
|
41052
|
+
features: [
|
|
41053
|
+
"step",
|
|
41054
|
+
"export",
|
|
41055
|
+
"booleans",
|
|
41056
|
+
"cnc"
|
|
41057
|
+
],
|
|
41058
|
+
mcpTools: [
|
|
41059
|
+
"export_cad"
|
|
41060
|
+
]
|
|
41061
|
+
},
|
|
40980
41062
|
{
|
|
40981
41063
|
id: "2026-07-26-render-loon-directly",
|
|
40982
41064
|
version: "0.9.4",
|
|
@@ -40990,6 +41072,20 @@ var init_CHANGELOG = __esm({
|
|
|
40990
41072
|
"rendering"
|
|
40991
41073
|
]
|
|
40992
41074
|
},
|
|
41075
|
+
{
|
|
41076
|
+
id: "2026-07-26-photoreal-path-tracer",
|
|
41077
|
+
version: "0.9.4",
|
|
41078
|
+
date: "2026-07-26",
|
|
41079
|
+
category: "feat",
|
|
41080
|
+
title: "Photorealistic rendering with --photoreal",
|
|
41081
|
+
summary: "vcad-render gains a physically-based path tracer: GGX materials with clearcoat, studio softbox lighting, global illumination, and a real camera lens with depth of field.",
|
|
41082
|
+
features: [
|
|
41083
|
+
"rendering",
|
|
41084
|
+
"raytracing",
|
|
41085
|
+
"cli",
|
|
41086
|
+
"materials"
|
|
41087
|
+
]
|
|
41088
|
+
},
|
|
40993
41089
|
{
|
|
40994
41090
|
id: "2026-07-26-parametric-loon-datums",
|
|
40995
41091
|
version: "0.9.4",
|
|
@@ -41048,6 +41144,24 @@ var init_CHANGELOG = __esm({
|
|
|
41048
41144
|
"export_cad"
|
|
41049
41145
|
]
|
|
41050
41146
|
},
|
|
41147
|
+
{
|
|
41148
|
+
id: "2026-07-26-flat-pattern-from-solid",
|
|
41149
|
+
version: "0.9.4",
|
|
41150
|
+
date: "2026-07-26",
|
|
41151
|
+
category: "feat",
|
|
41152
|
+
title: "Flat patterns from parts you already modelled",
|
|
41153
|
+
summary: "flat_pattern_from_solid turns any constant-thickness solid into a fab-ready DXF plus a bend table \u2014 no sheet-metal re-authoring \u2014 batching a whole assembly into unique patterns x quantity.",
|
|
41154
|
+
features: [
|
|
41155
|
+
"sheet-metal",
|
|
41156
|
+
"manufacturing",
|
|
41157
|
+
"mcp"
|
|
41158
|
+
],
|
|
41159
|
+
mcpTools: [
|
|
41160
|
+
"flat_pattern_from_solid",
|
|
41161
|
+
"sheet_metal_nest",
|
|
41162
|
+
"sheet_metal_cost"
|
|
41163
|
+
]
|
|
41164
|
+
},
|
|
41051
41165
|
{
|
|
41052
41166
|
id: "2026-07-26-fastener-forms",
|
|
41053
41167
|
version: "0.9.4",
|
|
@@ -47874,13 +47988,13 @@ function computeIntegrity(doc, engine) {
|
|
|
47874
47988
|
cx += v * (p1[0] + p2[0] + p3[0]) / 4;
|
|
47875
47989
|
cy += v * (p1[1] + p2[1] + p3[1]) / 4;
|
|
47876
47990
|
cz += v * (p1[2] + p2[2] + p3[2]) / 4;
|
|
47877
|
-
for (const
|
|
47878
|
-
bbox.min.x = Math.min(bbox.min.x,
|
|
47879
|
-
bbox.min.y = Math.min(bbox.min.y,
|
|
47880
|
-
bbox.min.z = Math.min(bbox.min.z,
|
|
47881
|
-
bbox.max.x = Math.max(bbox.max.x,
|
|
47882
|
-
bbox.max.y = Math.max(bbox.max.y,
|
|
47883
|
-
bbox.max.z = Math.max(bbox.max.z,
|
|
47991
|
+
for (const q2 of [p1, p2, p3]) {
|
|
47992
|
+
bbox.min.x = Math.min(bbox.min.x, q2[0]);
|
|
47993
|
+
bbox.min.y = Math.min(bbox.min.y, q2[1]);
|
|
47994
|
+
bbox.min.z = Math.min(bbox.min.z, q2[2]);
|
|
47995
|
+
bbox.max.x = Math.max(bbox.max.x, q2[0]);
|
|
47996
|
+
bbox.max.y = Math.max(bbox.max.y, q2[1]);
|
|
47997
|
+
bbox.max.z = Math.max(bbox.max.z, q2[2]);
|
|
47884
47998
|
}
|
|
47885
47999
|
}
|
|
47886
48000
|
const label = labels[partIndex] ?? `part ${partIndex + 1}`;
|
|
@@ -50295,8 +50409,8 @@ function buildPartLabels(doc) {
|
|
|
50295
50409
|
});
|
|
50296
50410
|
}
|
|
50297
50411
|
function eulerXyzDegToQuat2(rotation) {
|
|
50298
|
-
const
|
|
50299
|
-
return [
|
|
50412
|
+
const q2 = exportKernel().eulerXyzDegToQuat(rotation.x, rotation.y, rotation.z);
|
|
50413
|
+
return [q2[0], q2[1], q2[2], q2[3]];
|
|
50300
50414
|
}
|
|
50301
50415
|
function buildGlb(inputMeshes, name, animation) {
|
|
50302
50416
|
let f32Len = 0;
|
|
@@ -51125,9 +51239,9 @@ var init_store = __esm({
|
|
|
51125
51239
|
async listOrders(userId, filter) {
|
|
51126
51240
|
try {
|
|
51127
51241
|
const limit = typeof filter.limit === "number" ? filter.limit : 50;
|
|
51128
|
-
let
|
|
51129
|
-
if (filter.status)
|
|
51130
|
-
const res = await fabricateFetch(this.url("orders",
|
|
51242
|
+
let q2 = `?user_id=eq.${encodeURIComponent(userId)}&order=created_at.desc&limit=${limit}`;
|
|
51243
|
+
if (filter.status) q2 += `&state=eq.${encodeURIComponent(filter.status)}`;
|
|
51244
|
+
const res = await fabricateFetch(this.url("orders", q2), {
|
|
51131
51245
|
method: "GET",
|
|
51132
51246
|
headers: this.headers()
|
|
51133
51247
|
});
|
|
@@ -51331,8 +51445,8 @@ var init_store = __esm({
|
|
|
51331
51445
|
* can retry before deciding what to say. Never throws. */
|
|
51332
51446
|
async postRow(table, row, onConflict) {
|
|
51333
51447
|
try {
|
|
51334
|
-
const
|
|
51335
|
-
const res = await fabricateFetch(this.url(table,
|
|
51448
|
+
const q2 = onConflict ? `?on_conflict=${onConflict}` : "";
|
|
51449
|
+
const res = await fabricateFetch(this.url(table, q2), {
|
|
51336
51450
|
method: "POST",
|
|
51337
51451
|
headers: this.headers({
|
|
51338
51452
|
Prefer: onConflict ? "resolution=merge-duplicates,return=minimal" : "return=minimal"
|
|
@@ -53378,6 +53492,7 @@ var init_tool_metadata = __esm({
|
|
|
53378
53492
|
// ── Sheet metal ────────────────────────────────────────────────────────
|
|
53379
53493
|
sheet_metal_create: { title: "Create Sheet Metal", annotations: RW },
|
|
53380
53494
|
sheet_metal_unfold: { title: "Unfold Sheet Metal", annotations: RO },
|
|
53495
|
+
flat_pattern_from_solid: { title: "Flat Pattern From Solid", annotations: RO },
|
|
53381
53496
|
sheet_metal_check: { title: "Check Sheet Metal", annotations: RO },
|
|
53382
53497
|
sheet_metal_materials: { title: "Sheet Metal Materials", annotations: RO },
|
|
53383
53498
|
sheet_metal_bend_table: { title: "Sheet Metal Bend Table", annotations: RO },
|
|
@@ -54693,34 +54808,34 @@ var init_broker = __esm({
|
|
|
54693
54808
|
);
|
|
54694
54809
|
const built = [];
|
|
54695
54810
|
for (const adapter of eligible) {
|
|
54696
|
-
let
|
|
54811
|
+
let q2;
|
|
54697
54812
|
try {
|
|
54698
|
-
|
|
54813
|
+
q2 = await adapter.quote(req);
|
|
54699
54814
|
} catch {
|
|
54700
|
-
|
|
54815
|
+
q2 = null;
|
|
54701
54816
|
}
|
|
54702
|
-
if (!
|
|
54817
|
+
if (!q2) continue;
|
|
54703
54818
|
const landed2 = estimateLandedCost({
|
|
54704
54819
|
region: adapter.region,
|
|
54705
54820
|
supportsDdp: adapter.supportsDdp
|
|
54706
54821
|
});
|
|
54707
|
-
const markedUp = applyMargin(
|
|
54822
|
+
const markedUp = applyMargin(q2.fab_cost_minor);
|
|
54708
54823
|
const totalMinor = markedUp + landed2.shipping_minor + landed2.duty_minor;
|
|
54709
|
-
const orderable = CONTRACTED_FABS.has(adapter.key) &&
|
|
54824
|
+
const orderable = CONTRACTED_FABS.has(adapter.key) && q2.pricing_basis === "binding";
|
|
54710
54825
|
built.push({
|
|
54711
|
-
fabCost:
|
|
54826
|
+
fabCost: q2.fab_cost_minor,
|
|
54712
54827
|
option: {
|
|
54713
54828
|
fab: adapter.key,
|
|
54714
54829
|
fab_label: adapter.label,
|
|
54715
54830
|
region: adapter.region,
|
|
54716
54831
|
unit_price_minor: Math.round(totalMinor / req.quantity),
|
|
54717
54832
|
total_minor: totalMinor,
|
|
54718
|
-
lead_time_days:
|
|
54719
|
-
in_spec:
|
|
54720
|
-
pricing_basis:
|
|
54833
|
+
lead_time_days: q2.lead_time_days,
|
|
54834
|
+
in_spec: q2.in_spec,
|
|
54835
|
+
pricing_basis: q2.pricing_basis,
|
|
54721
54836
|
supports_ddp: adapter.supportsDdp,
|
|
54722
54837
|
orderable,
|
|
54723
|
-
notes:
|
|
54838
|
+
notes: q2.notes
|
|
54724
54839
|
}
|
|
54725
54840
|
});
|
|
54726
54841
|
}
|
|
@@ -55910,7 +56025,7 @@ function measureGroups(engine, candidates, groupA, groupB) {
|
|
|
55910
56025
|
error: `No part with id or name ${missing.map((m) => `"${m}"`).join(", ")}. Available: ${available || "none"}`
|
|
55911
56026
|
};
|
|
55912
56027
|
}
|
|
55913
|
-
const overlap = a.parts.filter((p) => b.parts.some((
|
|
56028
|
+
const overlap = a.parts.filter((p) => b.parts.some((q2) => q2.id === p.id));
|
|
55914
56029
|
if (overlap.length > 0) {
|
|
55915
56030
|
return {
|
|
55916
56031
|
error: `Parts cannot appear in both groups: ${overlap.map((p) => p.id).join(", ")}`
|
|
@@ -57979,17 +58094,19 @@ function exportCad(input, engine) {
|
|
|
57979
58094
|
const filename = String(args.filename ?? "");
|
|
57980
58095
|
const stepExt = filename.toLowerCase().split(".").pop();
|
|
57981
58096
|
if (stepExt === "step" || stepExt === "stp") {
|
|
57982
|
-
const
|
|
57983
|
-
if (
|
|
57984
|
-
|
|
57985
|
-
|
|
57986
|
-
|
|
58097
|
+
const foldedStep = engine.foldedSheetMetalStep(ir);
|
|
58098
|
+
if (foldedStep !== null) {
|
|
58099
|
+
const bytes3 = new TextEncoder().encode(foldedStep);
|
|
58100
|
+
return deliver(filename, bytes3, {
|
|
58101
|
+
format: stepExt,
|
|
58102
|
+
parts: 1,
|
|
58103
|
+
note: "Folded sheet-metal body (AP214) with cylindrical bend faces \u2014 bends/angles/directions auto-detect in 3D fab pipelines."
|
|
58104
|
+
});
|
|
57987
58105
|
}
|
|
57988
|
-
const bytes2 =
|
|
58106
|
+
const bytes2 = engine.documentStep(ir);
|
|
57989
58107
|
return deliver(filename, bytes2, {
|
|
57990
58108
|
format: stepExt,
|
|
57991
|
-
|
|
57992
|
-
note: "Folded sheet-metal body (AP214) with cylindrical bend faces \u2014 bends/angles/directions auto-detect in 3D fab pipelines."
|
|
58109
|
+
note: "BRep AP214 export \u2014 analytic faces (planes/cylinders/spheres/cones/tori/NURBS) preserved through booleans; ready for CNC quoting."
|
|
57993
58110
|
});
|
|
57994
58111
|
}
|
|
57995
58112
|
const scene = engine.evaluate(ir);
|
|
@@ -58021,7 +58138,7 @@ function exportCad(input, engine) {
|
|
|
58021
58138
|
bytes = toGlbBytes(scene, filename);
|
|
58022
58139
|
break;
|
|
58023
58140
|
default:
|
|
58024
|
-
throw new Error(`Unsupported format: .${ext}. Use .stl, .glb, or .step
|
|
58141
|
+
throw new Error(`Unsupported format: .${ext}. Use .stl, .glb, or .step`);
|
|
58025
58142
|
}
|
|
58026
58143
|
return deliver(filename, bytes, {
|
|
58027
58144
|
format: ext,
|
|
@@ -58060,7 +58177,7 @@ var init_export = __esm({
|
|
|
58060
58177
|
},
|
|
58061
58178
|
filename: {
|
|
58062
58179
|
type: "string",
|
|
58063
|
-
description: "Output filename with extension (.stl, .glb, or
|
|
58180
|
+
description: "Output filename with extension (.stl, .glb, or .step/.stp), relative to the server working directory (or VCAD_MCP_EXPORT_DIR if set). STEP is a BRep AP214 export: booleans, transforms, fillets, and sweeps keep true analytic faces (the format CNC vendors quote from). Sheet-metal documents export the FOLDED body with cylindrical bend faces auto-detected by 3D fab pipelines (e.g. SendCutSend). Parts built from imported meshes have no BRep and are refused by name \u2014 export those as STL."
|
|
58064
58181
|
},
|
|
58065
58182
|
joint_state: jointStateSchemaProp
|
|
58066
58183
|
},
|
|
@@ -58070,7 +58187,7 @@ var init_export = __esm({
|
|
|
58070
58187
|
{
|
|
58071
58188
|
name: "export_cad",
|
|
58072
58189
|
pack: null,
|
|
58073
|
-
description: "Export a CAD document to a file. Supports STL (3D printing), GLB (visualization), and
|
|
58190
|
+
description: "Export a CAD document to a file. Supports STL (3D printing), GLB (visualization), and STEP AP214 (CNC quoting: BRep with true analytic faces, preserved through booleans/transforms/fillets/sweeps; sheet-metal documents export the FOLDED body with cylindrical bend faces that 3D fab pipelines like SendCutSend auto-detect). Mesh-only parts (imported meshes) can't go to STEP and are refused by name \u2014 use STL for those. Format is determined by file extension. Pass `joint_state` to export a jointed assembly at a real pose (joint id or name \u2192 degrees, or mm for sliders) instead of its zero pose.",
|
|
58074
58191
|
inputSchema: exportCadSchema,
|
|
58075
58192
|
handler: (a, c) => exportCad(a, c.engine),
|
|
58076
58193
|
behavior: behavior({})
|
|
@@ -60068,10 +60185,10 @@ function detectStaleNets(pcb) {
|
|
|
60068
60185
|
const onSegBody = (p, t2) => segDist(p, t2) <= t2.width / 2 + 0.02;
|
|
60069
60186
|
const anchored = (p, selfIdx, halfW) => {
|
|
60070
60187
|
if (pads.some(
|
|
60071
|
-
(
|
|
60188
|
+
(q2) => Math.hypot(p.x - q2.pos.x, p.y - q2.pos.y) <= q2.halfExtent + halfW + 0.02
|
|
60072
60189
|
))
|
|
60073
60190
|
return true;
|
|
60074
|
-
if (vias.some((
|
|
60191
|
+
if (vias.some((q2) => Math.hypot(p.x - q2.x, p.y - q2.y) <= halfW + 0.42)) return true;
|
|
60075
60192
|
for (let j = 0; j < traces.length; j++) {
|
|
60076
60193
|
if (j === selfIdx) continue;
|
|
60077
60194
|
if (segDist(p, traces[j]) <= traces[j].width / 2 + halfW + 0.02) return true;
|
|
@@ -61871,7 +61988,7 @@ function seedScan(residual, lo, hi, perDim = 12) {
|
|
|
61871
61988
|
const idx = new Array(n).fill(0);
|
|
61872
61989
|
const total = Math.pow(perDim, n);
|
|
61873
61990
|
for (let c = 0; c < total; c++) {
|
|
61874
|
-
const x = idx.map((
|
|
61991
|
+
const x = idx.map((q2, d) => lo[d] + (hi[d] - lo[d]) * q2 / (perDim - 1));
|
|
61875
61992
|
const cost = sumSq(residual(x));
|
|
61876
61993
|
if (cost < best.cost) {
|
|
61877
61994
|
best.cost = cost;
|
|
@@ -62412,7 +62529,7 @@ function calcRf(args) {
|
|
|
62412
62529
|
return fail2("topology must be 'series_rlc' or 'parallel_rlc'");
|
|
62413
62530
|
}
|
|
62414
62531
|
const f0 = 1 / (2 * Math.PI * Math.sqrt(l * c));
|
|
62415
|
-
const
|
|
62532
|
+
const q2 = topology === "series_rlc" ? r > 0 ? 1 / r * Math.sqrt(l / c) : Infinity : r * Math.sqrt(c / l);
|
|
62416
62533
|
const fStart = args.f_start_hz ?? f0 * 0.1;
|
|
62417
62534
|
const fStop = args.f_stop_hz ?? f0 * 10;
|
|
62418
62535
|
const points = Math.min(256, Math.max(3, Math.round(args.points ?? 21)));
|
|
@@ -62458,7 +62575,7 @@ function calcRf(args) {
|
|
|
62458
62575
|
success: true,
|
|
62459
62576
|
topology,
|
|
62460
62577
|
resonance_hz: Math.round(f0),
|
|
62461
|
-
q_factor: Number.isFinite(
|
|
62578
|
+
q_factor: Number.isFinite(q2) ? r3(q2) : 999999,
|
|
62462
62579
|
z_at_resonance_ohm: r3(mag(z0re, z0im)),
|
|
62463
62580
|
best_match: {
|
|
62464
62581
|
f_hz: best.f_hz,
|
|
@@ -62473,8 +62590,8 @@ function calcRf(args) {
|
|
|
62473
62590
|
l_henry: l,
|
|
62474
62591
|
c_farad: c
|
|
62475
62592
|
}),
|
|
62476
|
-
...Number.isFinite(
|
|
62477
|
-
emClaim("q_factor", r3(
|
|
62593
|
+
...Number.isFinite(q2) ? [
|
|
62594
|
+
emClaim("q_factor", r3(q2), "dimensionless", "rlc-analytic", {
|
|
62478
62595
|
topology,
|
|
62479
62596
|
r_ohm: r,
|
|
62480
62597
|
l_henry: l,
|
|
@@ -63053,17 +63170,17 @@ async function setBoardOutline(args) {
|
|
|
63053
63170
|
};
|
|
63054
63171
|
}
|
|
63055
63172
|
function scoreFootprintFamily(query, fam) {
|
|
63056
|
-
const
|
|
63057
|
-
if (!
|
|
63173
|
+
const q2 = query.toLowerCase().trim();
|
|
63174
|
+
if (!q2) return 0;
|
|
63058
63175
|
const cands = [fam.family, fam.label, ...fam.aliases].map((s) => s.toLowerCase());
|
|
63059
63176
|
let best = 0;
|
|
63060
63177
|
for (const c of cands) {
|
|
63061
|
-
if (c ===
|
|
63178
|
+
if (c === q2) {
|
|
63062
63179
|
best = Math.max(best, 1);
|
|
63063
|
-
} else if (c.includes(
|
|
63180
|
+
} else if (c.includes(q2) || q2.includes(c)) {
|
|
63064
63181
|
best = Math.max(best, 0.75);
|
|
63065
63182
|
} else {
|
|
63066
|
-
const sim = 1 - editDistance(
|
|
63183
|
+
const sim = 1 - editDistance(q2, c) / Math.max(q2.length, c.length);
|
|
63067
63184
|
best = Math.max(best, sim * 0.6);
|
|
63068
63185
|
}
|
|
63069
63186
|
}
|
|
@@ -64696,16 +64813,16 @@ function windSegClosestPt(a, b, c, d) {
|
|
|
64696
64813
|
};
|
|
64697
64814
|
let best = [a, clamp(a, c, d)];
|
|
64698
64815
|
let bestD = Infinity;
|
|
64699
|
-
for (const [p,
|
|
64816
|
+
for (const [p, q2] of [
|
|
64700
64817
|
[a, clamp(a, c, d)],
|
|
64701
64818
|
[b, clamp(b, c, d)],
|
|
64702
64819
|
[c, clamp(c, a, b)],
|
|
64703
64820
|
[d, clamp(d, a, b)]
|
|
64704
64821
|
]) {
|
|
64705
|
-
const dd = Math.hypot(p.x -
|
|
64822
|
+
const dd = Math.hypot(p.x - q2.x, p.y - q2.y);
|
|
64706
64823
|
if (dd < bestD) {
|
|
64707
64824
|
bestD = dd;
|
|
64708
|
-
best = [p,
|
|
64825
|
+
best = [p, q2];
|
|
64709
64826
|
}
|
|
64710
64827
|
}
|
|
64711
64828
|
return { x: (best[0].x + best[1].x) / 2, y: (best[0].y + best[1].y) / 2 };
|
|
@@ -65323,7 +65440,7 @@ function calcMotorInduction(args, polePairs, turnsPerPhase, windingFactor, inner
|
|
|
65323
65440
|
outer_radius_mm: outerR,
|
|
65324
65441
|
end_effect_factor: endEffect
|
|
65325
65442
|
};
|
|
65326
|
-
const claim2 = (
|
|
65443
|
+
const claim2 = (q2, v, unit) => emClaim(q2, sig6(v), unit, "thin-sheet-induction", inductionInputs);
|
|
65327
65444
|
return {
|
|
65328
65445
|
content: [
|
|
65329
65446
|
{
|
|
@@ -65751,11 +65868,11 @@ function polygonCentroid(poly) {
|
|
|
65751
65868
|
let cy = 0;
|
|
65752
65869
|
for (let i = 0; i < poly.length; i++) {
|
|
65753
65870
|
const p = poly[i];
|
|
65754
|
-
const
|
|
65755
|
-
const cross = p.x *
|
|
65871
|
+
const q2 = poly[(i + 1) % poly.length];
|
|
65872
|
+
const cross = p.x * q2.y - q2.x * p.y;
|
|
65756
65873
|
a += cross;
|
|
65757
|
-
cx += (p.x +
|
|
65758
|
-
cy += (p.y +
|
|
65874
|
+
cx += (p.x + q2.x) * cross;
|
|
65875
|
+
cy += (p.y + q2.y) * cross;
|
|
65759
65876
|
}
|
|
65760
65877
|
if (Math.abs(a) < 1e-12) {
|
|
65761
65878
|
const n = poly.length || 1;
|
|
@@ -74151,8 +74268,8 @@ function normaliseEngravings(raw) {
|
|
|
74151
74268
|
if (Array.isArray(p) && p.length >= 2)
|
|
74152
74269
|
return { x: Number(p[0]), y: Number(p[1]) };
|
|
74153
74270
|
if (p && typeof p === "object" && "x" in p && "y" in p) {
|
|
74154
|
-
const
|
|
74155
|
-
return { x: Number(
|
|
74271
|
+
const q2 = p;
|
|
74272
|
+
return { x: Number(q2.x), y: Number(q2.y) };
|
|
74156
74273
|
}
|
|
74157
74274
|
return null;
|
|
74158
74275
|
}).filter((p) => p !== null) : [];
|
|
@@ -74817,6 +74934,222 @@ var init_sheet_metal2 = __esm({
|
|
|
74817
74934
|
}
|
|
74818
74935
|
});
|
|
74819
74936
|
|
|
74937
|
+
// src/tools/flat-pattern.ts
|
|
74938
|
+
function q(v, dp = 3) {
|
|
74939
|
+
const f = 10 ** dp;
|
|
74940
|
+
const r = Math.round(v * f) / f;
|
|
74941
|
+
return r === 0 ? 0 : r;
|
|
74942
|
+
}
|
|
74943
|
+
function ringSignature(ring) {
|
|
74944
|
+
const n = ring.length;
|
|
74945
|
+
if (n < 3) return "";
|
|
74946
|
+
const terms = [];
|
|
74947
|
+
for (let i = 0; i < n; i++) {
|
|
74948
|
+
const a = ring[(i + n - 1) % n];
|
|
74949
|
+
const b = ring[i];
|
|
74950
|
+
const c = ring[(i + 1) % n];
|
|
74951
|
+
const e1 = [b[0] - a[0], b[1] - a[1]];
|
|
74952
|
+
const e2 = [c[0] - b[0], c[1] - b[1]];
|
|
74953
|
+
const len = Math.hypot(e2[0], e2[1]);
|
|
74954
|
+
const turn = Math.atan2(
|
|
74955
|
+
e1[0] * e2[1] - e1[1] * e2[0],
|
|
74956
|
+
e1[0] * e2[0] + e1[1] * e2[1]
|
|
74957
|
+
);
|
|
74958
|
+
terms.push(`${q(len, 2)}:${q(turn, 3)}`);
|
|
74959
|
+
}
|
|
74960
|
+
let best = null;
|
|
74961
|
+
for (let r = 0; r < n; r++) {
|
|
74962
|
+
const cand = terms.slice(r).concat(terms.slice(0, r)).join(",");
|
|
74963
|
+
if (best === null || cand < best) best = cand;
|
|
74964
|
+
}
|
|
74965
|
+
return best ?? "";
|
|
74966
|
+
}
|
|
74967
|
+
function patternSignature(r) {
|
|
74968
|
+
const sil = r.flatPattern.silhouette_2d ?? [];
|
|
74969
|
+
const outer = ringSignature(sil[0] ?? []);
|
|
74970
|
+
const holes = sil.slice(1).map((h) => ringSignature(h)).sort().join("|");
|
|
74971
|
+
const bends = r.bends.map((b) => `${q(b.angle_deg, 2)}/${q(b.radius, 3)}/${q(b.length, 2)}/${b.direction}`).sort().join("|");
|
|
74972
|
+
return `t${q(r.thickness)}|${outer}|H:${holes}|B:${bends}`;
|
|
74973
|
+
}
|
|
74974
|
+
function solidParts(doc, engine) {
|
|
74975
|
+
const scene = engine.evaluate(doc);
|
|
74976
|
+
const visibleRoots = doc.roots.filter((e) => e.visible !== false);
|
|
74977
|
+
const out = [];
|
|
74978
|
+
for (let i = 0; i < scene.parts.length && i < visibleRoots.length; i++) {
|
|
74979
|
+
const rootId = visibleRoots[i].root;
|
|
74980
|
+
const node = doc.nodes[String(rootId)];
|
|
74981
|
+
const mesh = scene.parts[i].mesh;
|
|
74982
|
+
if (!mesh || mesh.positions.length === 0) continue;
|
|
74983
|
+
out.push({ rootId, name: node?.name ?? void 0, mesh });
|
|
74984
|
+
}
|
|
74985
|
+
return out;
|
|
74986
|
+
}
|
|
74987
|
+
function flatPatternFromSolid(input, engine) {
|
|
74988
|
+
const a = input ?? {};
|
|
74989
|
+
const doc = getSession(String(a.document_id ?? ""));
|
|
74990
|
+
const includeDxf = a.include_dxf !== false;
|
|
74991
|
+
const options = {
|
|
74992
|
+
material: typeof a.material === "string" ? a.material : void 0,
|
|
74993
|
+
manualK: typeof a.manual_k === "number" ? a.manual_k : void 0,
|
|
74994
|
+
shopProfile: typeof a.shop_profile === "string" ? a.shop_profile : void 0,
|
|
74995
|
+
volumeTolFrac: typeof a.volume_tolerance === "number" ? a.volume_tolerance : void 0
|
|
74996
|
+
};
|
|
74997
|
+
const all = solidParts(doc, engine);
|
|
74998
|
+
if (all.length === 0) {
|
|
74999
|
+
throw new Error("Document has no solid parts to flatten");
|
|
75000
|
+
}
|
|
75001
|
+
const partId = a.part_id !== void 0 ? String(a.part_id) : void 0;
|
|
75002
|
+
const targets = partId ? all.filter((p) => String(p.rootId) === partId) : all;
|
|
75003
|
+
if (targets.length === 0) {
|
|
75004
|
+
throw new Error(
|
|
75005
|
+
`No part with id "${partId}". Available: ${all.map((c) => `${c.rootId}${c.name ? ` (${c.name})` : ""}`).join(", ")}`
|
|
75006
|
+
);
|
|
75007
|
+
}
|
|
75008
|
+
const groups = /* @__PURE__ */ new Map();
|
|
75009
|
+
const failed = [];
|
|
75010
|
+
for (const part of targets) {
|
|
75011
|
+
let r;
|
|
75012
|
+
try {
|
|
75013
|
+
r = engine.flattenSolidToSheetMetal(part.mesh, options);
|
|
75014
|
+
} catch (e) {
|
|
75015
|
+
failed.push({
|
|
75016
|
+
root_id: part.rootId,
|
|
75017
|
+
...part.name ? { name: part.name } : {},
|
|
75018
|
+
reason: e instanceof Error ? e.message : String(e)
|
|
75019
|
+
});
|
|
75020
|
+
continue;
|
|
75021
|
+
}
|
|
75022
|
+
const sig = patternSignature(r);
|
|
75023
|
+
const existing = groups.get(sig);
|
|
75024
|
+
if (existing) {
|
|
75025
|
+
existing.quantity += 1;
|
|
75026
|
+
existing.parts.push({
|
|
75027
|
+
root_id: part.rootId,
|
|
75028
|
+
...part.name ? { name: part.name } : {}
|
|
75029
|
+
});
|
|
75030
|
+
continue;
|
|
75031
|
+
}
|
|
75032
|
+
const [minX, minY, maxX, maxY] = r.flatPattern.bbox;
|
|
75033
|
+
const creases = r.flatPattern.creases ?? [];
|
|
75034
|
+
groups.set(sig, {
|
|
75035
|
+
pattern_id: `pattern-${groups.size + 1}`,
|
|
75036
|
+
quantity: 1,
|
|
75037
|
+
parts: [{ root_id: part.rootId, ...part.name ? { name: part.name } : {} }],
|
|
75038
|
+
thickness_mm: r.thickness,
|
|
75039
|
+
flat: {
|
|
75040
|
+
bbox: r.flatPattern.bbox,
|
|
75041
|
+
area_mm2: r.flatPattern.area_mm2,
|
|
75042
|
+
width_mm: Math.abs(maxX - minX),
|
|
75043
|
+
height_mm: Math.abs(maxY - minY)
|
|
75044
|
+
},
|
|
75045
|
+
panels: r.panels,
|
|
75046
|
+
bend_table: r.bends.map((b, i) => ({
|
|
75047
|
+
bend: b.bend,
|
|
75048
|
+
angle_deg: b.angle_deg,
|
|
75049
|
+
radius_mm: b.radius,
|
|
75050
|
+
length_mm: b.length,
|
|
75051
|
+
direction: b.direction,
|
|
75052
|
+
k_factor: b.k_factor,
|
|
75053
|
+
allowance_mm: b.angle_deg * Math.PI / 180 * (b.radius + b.k_factor * r.thickness),
|
|
75054
|
+
line: creases[i] ? creases[i].line : []
|
|
75055
|
+
})),
|
|
75056
|
+
verification: {
|
|
75057
|
+
solid_volume_mm3: r.solidVolumeMm3,
|
|
75058
|
+
recovered_volume_mm3: r.recoveredVolumeMm3,
|
|
75059
|
+
error_frac: r.volumeErrorFrac,
|
|
75060
|
+
status: "verified"
|
|
75061
|
+
},
|
|
75062
|
+
violations: r.violations,
|
|
75063
|
+
warnings: r.warnings,
|
|
75064
|
+
...includeDxf ? { dxf: r.dxf } : {}
|
|
75065
|
+
});
|
|
75066
|
+
}
|
|
75067
|
+
const patterns = [...groups.values()];
|
|
75068
|
+
if (patterns.length === 0) {
|
|
75069
|
+
throw new Error(
|
|
75070
|
+
`No part in this document is constant-thickness sheet. ${failed.map((f) => `${f.name ?? f.root_id}: ${f.reason}`).join("; ")}`
|
|
75071
|
+
);
|
|
75072
|
+
}
|
|
75073
|
+
const totalParts = patterns.reduce((s, p) => s + p.quantity, 0);
|
|
75074
|
+
const bends = patterns.reduce((s, p) => s + p.bend_table.length * p.quantity, 0);
|
|
75075
|
+
return {
|
|
75076
|
+
content: [
|
|
75077
|
+
{
|
|
75078
|
+
type: "text",
|
|
75079
|
+
text: JSON.stringify(
|
|
75080
|
+
{
|
|
75081
|
+
success: true,
|
|
75082
|
+
patterns,
|
|
75083
|
+
...failed.length > 0 ? { not_sheet_metal: failed } : {},
|
|
75084
|
+
nest_input: patterns.map((p) => ({
|
|
75085
|
+
name: p.pattern_id,
|
|
75086
|
+
width_mm: p.flat.width_mm,
|
|
75087
|
+
height_mm: p.flat.height_mm,
|
|
75088
|
+
quantity: p.quantity
|
|
75089
|
+
})),
|
|
75090
|
+
summary: `${patterns.length} unique pattern(s) covering ${totalParts} part(s), ${bends} bend(s) total${failed.length > 0 ? `; ${failed.length} part(s) are not sheet metal` : ""}. Every pattern is volume-verified against its solid.`,
|
|
75091
|
+
note: "Each DXF is a fab-ready merged silhouette in millimetres: one closed exterior polyline + hole loops on CUT, DASHED bend centerlines on BEND_UP/BEND_DOWN. DXF carries no bend angles \u2014 use `bend_table` (angle, inside radius, direction, allowance, crease line) when entering them in the fab's UI. Hand `nest_input` to sheet_metal_nest, then sheet_metal_cost, for a quote."
|
|
75092
|
+
},
|
|
75093
|
+
null,
|
|
75094
|
+
2
|
|
75095
|
+
)
|
|
75096
|
+
}
|
|
75097
|
+
]
|
|
75098
|
+
};
|
|
75099
|
+
}
|
|
75100
|
+
var flatPatternFromSolidSchema, toolDefs41;
|
|
75101
|
+
var init_flat_pattern = __esm({
|
|
75102
|
+
"src/tools/flat-pattern.ts"() {
|
|
75103
|
+
"use strict";
|
|
75104
|
+
init_session2();
|
|
75105
|
+
init_tool_def();
|
|
75106
|
+
flatPatternFromSolidSchema = {
|
|
75107
|
+
type: "object",
|
|
75108
|
+
properties: {
|
|
75109
|
+
document_id: {
|
|
75110
|
+
type: "string",
|
|
75111
|
+
description: "CAD session id (open_document / create_cad_loon) holding the solid(s)."
|
|
75112
|
+
},
|
|
75113
|
+
part_id: {
|
|
75114
|
+
type: "string",
|
|
75115
|
+
description: "Root id of a single part to flatten (from `read`). Omit to flatten every solid part in the document and group identical parts into one pattern \xD7 quantity."
|
|
75116
|
+
},
|
|
75117
|
+
material: {
|
|
75118
|
+
type: "string",
|
|
75119
|
+
description: 'Material key for K-factor lookup (e.g. "al-soft", "steel-mild"). Default "al-soft". See sheet_metal_materials.'
|
|
75120
|
+
},
|
|
75121
|
+
manual_k: {
|
|
75122
|
+
type: "number",
|
|
75123
|
+
description: "Override the K-factor for every recovered bend (skips the bend table)."
|
|
75124
|
+
},
|
|
75125
|
+
shop_profile: {
|
|
75126
|
+
type: "string",
|
|
75127
|
+
description: 'Fab-service catalog id (e.g. "sendcutsend") to run manufacturability against. Default: generic shop.'
|
|
75128
|
+
},
|
|
75129
|
+
volume_tolerance: {
|
|
75130
|
+
type: "number",
|
|
75131
|
+
description: "Max relative volume error the round-trip check accepts (default 0.02). Re-extruding the emitted profile by the detected thickness must reproduce the solid's volume; a mismatch fails the part."
|
|
75132
|
+
},
|
|
75133
|
+
include_dxf: {
|
|
75134
|
+
type: "boolean",
|
|
75135
|
+
description: "Include the DXF string per pattern. Default true."
|
|
75136
|
+
}
|
|
75137
|
+
},
|
|
75138
|
+
required: ["document_id"]
|
|
75139
|
+
};
|
|
75140
|
+
toolDefs41 = [
|
|
75141
|
+
{
|
|
75142
|
+
name: "flat_pattern_from_solid",
|
|
75143
|
+
pack: "sheet_metal",
|
|
75144
|
+
description: "Emit the flat pattern (DXF + bend table) for a part that was modelled as an ordinary solid \u2014 extruded sketch, boolean, imported STEP \u2014 with no sheet-metal authoring required. The mechanical counterpart of board_from_solid: it detects the constant-thickness walls and the cylindrical bends between them, returns the cut profile (outer boundary + every interior hole) with the detected thickness, and a bend table (line positions, angles, direction, allowance) for bent parts. Called without part_id it batches the whole document and groups identical parts into one pattern \xD7 quantity (mirror images stay separate). Fails closed: re-extruding the emitted profile by the detected thickness must reproduce the solid's volume, so a part that isn't really constant-thickness sheet is reported as such instead of yielding a wrong outline.",
|
|
75145
|
+
inputSchema: flatPatternFromSolidSchema,
|
|
75146
|
+
handler: (a, c) => flatPatternFromSolid(a, c.engine),
|
|
75147
|
+
behavior: behavior({ geometry: true })
|
|
75148
|
+
}
|
|
75149
|
+
];
|
|
75150
|
+
}
|
|
75151
|
+
});
|
|
75152
|
+
|
|
74820
75153
|
// src/tools/acoustics.ts
|
|
74821
75154
|
import { writeFileSync as writeFileSync5 } from "node:fs";
|
|
74822
75155
|
function lookupMaterial(engine, name) {
|
|
@@ -74985,7 +75318,7 @@ function simulateStrike(input, engine) {
|
|
|
74985
75318
|
}
|
|
74986
75319
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
74987
75320
|
}
|
|
74988
|
-
var cents, MATERIAL_ALIASES, simulateStrikeSchema, round23, round4,
|
|
75321
|
+
var cents, MATERIAL_ALIASES, simulateStrikeSchema, round23, round4, toolDefs42;
|
|
74989
75322
|
var init_acoustics = __esm({
|
|
74990
75323
|
"src/tools/acoustics.ts"() {
|
|
74991
75324
|
"use strict";
|
|
@@ -75059,7 +75392,7 @@ var init_acoustics = __esm({
|
|
|
75059
75392
|
};
|
|
75060
75393
|
round23 = (x) => Math.round(x * 100) / 100;
|
|
75061
75394
|
round4 = (x) => Math.round(x * 1e4) / 1e4;
|
|
75062
|
-
|
|
75395
|
+
toolDefs42 = [
|
|
75063
75396
|
{
|
|
75064
75397
|
name: "simulate_strike",
|
|
75065
75398
|
pack: "sheet_metal",
|
|
@@ -75210,7 +75543,7 @@ function importStep(input, engine) {
|
|
|
75210
75543
|
]
|
|
75211
75544
|
};
|
|
75212
75545
|
}
|
|
75213
|
-
var MAX_STEP_BYTES, importStepSchema,
|
|
75546
|
+
var MAX_STEP_BYTES, importStepSchema, toolDefs43;
|
|
75214
75547
|
var init_import = __esm({
|
|
75215
75548
|
"src/tools/import.ts"() {
|
|
75216
75549
|
"use strict";
|
|
@@ -75242,7 +75575,7 @@ var init_import = __esm({
|
|
|
75242
75575
|
}
|
|
75243
75576
|
}
|
|
75244
75577
|
};
|
|
75245
|
-
|
|
75578
|
+
toolDefs43 = [
|
|
75246
75579
|
{
|
|
75247
75580
|
name: "import_step",
|
|
75248
75581
|
pack: null,
|
|
@@ -75370,7 +75703,7 @@ function importEagle(_input) {
|
|
|
75370
75703
|
"Eagle (.brd) import is not yet supported. Export your board from Eagle as KiCad (File > Export > KiCad .kicad_pcb) and use import_kicad instead."
|
|
75371
75704
|
);
|
|
75372
75705
|
}
|
|
75373
|
-
var MAX_PCB_BYTES, importKicadSchema, importEagleSchema,
|
|
75706
|
+
var MAX_PCB_BYTES, importKicadSchema, importEagleSchema, toolDefs44;
|
|
75374
75707
|
var init_import_pcb = __esm({
|
|
75375
75708
|
"src/tools/import-pcb.ts"() {
|
|
75376
75709
|
"use strict";
|
|
@@ -75411,7 +75744,7 @@ var init_import_pcb = __esm({
|
|
|
75411
75744
|
}
|
|
75412
75745
|
}
|
|
75413
75746
|
};
|
|
75414
|
-
|
|
75747
|
+
toolDefs44 = [
|
|
75415
75748
|
{
|
|
75416
75749
|
name: "import_kicad",
|
|
75417
75750
|
pack: "ecad",
|
|
@@ -75507,7 +75840,7 @@ Compressed URL param: ${encoded.length} bytes`
|
|
|
75507
75840
|
]
|
|
75508
75841
|
};
|
|
75509
75842
|
}
|
|
75510
|
-
var openInBrowserSchema,
|
|
75843
|
+
var openInBrowserSchema, toolDefs45;
|
|
75511
75844
|
var init_share = __esm({
|
|
75512
75845
|
"src/tools/share.ts"() {
|
|
75513
75846
|
"use strict";
|
|
@@ -75531,7 +75864,7 @@ var init_share = __esm({
|
|
|
75531
75864
|
}
|
|
75532
75865
|
}
|
|
75533
75866
|
};
|
|
75534
|
-
|
|
75867
|
+
toolDefs45 = [
|
|
75535
75868
|
{
|
|
75536
75869
|
name: "open_in_browser",
|
|
75537
75870
|
pack: null,
|
|
@@ -75964,7 +76297,7 @@ function batchReset(input) {
|
|
|
75964
76297
|
};
|
|
75965
76298
|
}
|
|
75966
76299
|
}
|
|
75967
|
-
var simulations, MAX_TRAJECTORY, envRecords, batchGroups, INLINE_DOC_DESC, SESSION_DOC_DESC, createRobotEnvSchema, gymStepSchema, gymResetSchema, gymObserveSchema, gymCloseSchema, batchCreateEnvsSchema, batchStepSchema, batchResetSchema,
|
|
76300
|
+
var simulations, MAX_TRAJECTORY, envRecords, batchGroups, INLINE_DOC_DESC, SESSION_DOC_DESC, createRobotEnvSchema, gymStepSchema, gymResetSchema, gymObserveSchema, gymCloseSchema, batchCreateEnvsSchema, batchStepSchema, batchResetSchema, toolDefs46;
|
|
75968
76301
|
var init_gym = __esm({
|
|
75969
76302
|
"src/tools/gym.ts"() {
|
|
75970
76303
|
"use strict";
|
|
@@ -76126,7 +76459,7 @@ var init_gym = __esm({
|
|
|
76126
76459
|
},
|
|
76127
76460
|
required: ["batch_id"]
|
|
76128
76461
|
};
|
|
76129
|
-
|
|
76462
|
+
toolDefs46 = [
|
|
76130
76463
|
{
|
|
76131
76464
|
name: "create_robot_env",
|
|
76132
76465
|
pack: "physics",
|
|
@@ -76484,7 +76817,7 @@ async function renderMolecule(input) {
|
|
|
76484
76817
|
return fail(err7);
|
|
76485
76818
|
}
|
|
76486
76819
|
}
|
|
76487
|
-
var loadStructureSchema, inspectMoleculeSchema, configSchema, minimizeEnergySchema, mdRunSchema, designMaterialSchema, homogenizeMaterialSchema, renderMoleculeSchema, CPK, DEFAULT_RADIUS,
|
|
76820
|
+
var loadStructureSchema, inspectMoleculeSchema, configSchema, minimizeEnergySchema, mdRunSchema, designMaterialSchema, homogenizeMaterialSchema, renderMoleculeSchema, CPK, DEFAULT_RADIUS, toolDefs47;
|
|
76488
76821
|
var init_atoms2 = __esm({
|
|
76489
76822
|
"src/tools/atoms.ts"() {
|
|
76490
76823
|
"use strict";
|
|
@@ -76619,7 +76952,7 @@ var init_atoms2 = __esm({
|
|
|
76619
76952
|
S: 1.05,
|
|
76620
76953
|
P: 1.07
|
|
76621
76954
|
};
|
|
76622
|
-
|
|
76955
|
+
toolDefs47 = [
|
|
76623
76956
|
{
|
|
76624
76957
|
name: "load_structure",
|
|
76625
76958
|
pack: "atoms",
|
|
@@ -77827,7 +78160,7 @@ function errorResult(text) {
|
|
|
77827
78160
|
isError: true
|
|
77828
78161
|
};
|
|
77829
78162
|
}
|
|
77830
|
-
var recordSimulationSchema, SVG_SCALE2, MAX_STEPS, MIN_STEPS, DEFAULT_WIDTH_PX2, MIN_WIDTH_PX, MAX_WIDTH_PX, DEFAULT_FPS, MIN_FPS, MAX_FPS,
|
|
78163
|
+
var recordSimulationSchema, SVG_SCALE2, MAX_STEPS, MIN_STEPS, DEFAULT_WIDTH_PX2, MIN_WIDTH_PX, MAX_WIDTH_PX, DEFAULT_FPS, MIN_FPS, MAX_FPS, toolDefs48;
|
|
77831
78164
|
var init_record2 = __esm({
|
|
77832
78165
|
"src/tools/record.ts"() {
|
|
77833
78166
|
"use strict";
|
|
@@ -77891,7 +78224,7 @@ var init_record2 = __esm({
|
|
|
77891
78224
|
DEFAULT_FPS = 30;
|
|
77892
78225
|
MIN_FPS = 1;
|
|
77893
78226
|
MAX_FPS = 60;
|
|
77894
|
-
|
|
78227
|
+
toolDefs48 = [
|
|
77895
78228
|
{
|
|
77896
78229
|
name: "record_simulation",
|
|
77897
78230
|
pack: "physics",
|
|
@@ -77984,7 +78317,7 @@ ${text}`
|
|
|
77984
78317
|
]
|
|
77985
78318
|
};
|
|
77986
78319
|
}
|
|
77987
|
-
var getChangelogSchema,
|
|
78320
|
+
var getChangelogSchema, toolDefs49;
|
|
77988
78321
|
var init_changelog2 = __esm({
|
|
77989
78322
|
"src/tools/changelog.ts"() {
|
|
77990
78323
|
"use strict";
|
|
@@ -78024,7 +78357,7 @@ var init_changelog2 = __esm({
|
|
|
78024
78357
|
}
|
|
78025
78358
|
}
|
|
78026
78359
|
};
|
|
78027
|
-
|
|
78360
|
+
toolDefs49 = [
|
|
78028
78361
|
{
|
|
78029
78362
|
name: "get_changelog",
|
|
78030
78363
|
pack: null,
|
|
@@ -78173,7 +78506,7 @@ function getSimVersion(input) {
|
|
|
78173
78506
|
]
|
|
78174
78507
|
};
|
|
78175
78508
|
}
|
|
78176
|
-
var getSimReplaySchema, getSimVersionSchema,
|
|
78509
|
+
var getSimReplaySchema, getSimVersionSchema, toolDefs50;
|
|
78177
78510
|
var init_sim_replay = __esm({
|
|
78178
78511
|
"src/tools/sim-replay.ts"() {
|
|
78179
78512
|
"use strict";
|
|
@@ -78201,7 +78534,7 @@ var init_sim_replay = __esm({
|
|
|
78201
78534
|
},
|
|
78202
78535
|
required: ["env_id"]
|
|
78203
78536
|
};
|
|
78204
|
-
|
|
78537
|
+
toolDefs50 = [
|
|
78205
78538
|
{
|
|
78206
78539
|
name: "get_sim_replay",
|
|
78207
78540
|
pack: null,
|
|
@@ -78320,7 +78653,7 @@ async function getOrderFeed(input, store, user) {
|
|
|
78320
78653
|
version: version2
|
|
78321
78654
|
});
|
|
78322
78655
|
}
|
|
78323
|
-
var toUsd4, getOrderFeedSchema,
|
|
78656
|
+
var toUsd4, getOrderFeedSchema, toolDefs51;
|
|
78324
78657
|
var init_order_feed = __esm({
|
|
78325
78658
|
"src/tools/order-feed.ts"() {
|
|
78326
78659
|
"use strict";
|
|
@@ -78339,7 +78672,7 @@ var init_order_feed = __esm({
|
|
|
78339
78672
|
},
|
|
78340
78673
|
required: ["document_id"]
|
|
78341
78674
|
};
|
|
78342
|
-
|
|
78675
|
+
toolDefs51 = [
|
|
78343
78676
|
{
|
|
78344
78677
|
name: "get_order_feed",
|
|
78345
78678
|
pack: "fabricate",
|
|
@@ -79241,7 +79574,7 @@ ${issues.map((i) => i.problem).join("\n")}`
|
|
|
79241
79574
|
note: "Rollout compiled to the document timeline. Preview with render_sequence, ship with export_video."
|
|
79242
79575
|
});
|
|
79243
79576
|
}
|
|
79244
|
-
var MAX_FRAMES, MAX_GEO_SAMPLES, MAX_VERIFY_FRAMES, INLINE_GLB_MAX_BASE64, DEFAULT_WIDTH_PX3, MIN_WIDTH_PX2, MAX_WIDTH_PX2, SVG_SCALE3, KEYFRAMES_DESCRIPTION, animateSchema, renderSequenceSchema, CAMERA_NODE, exportVideoSchema, ffmpegAvailable, timelineFromSimulationSchema,
|
|
79577
|
+
var MAX_FRAMES, MAX_GEO_SAMPLES, MAX_VERIFY_FRAMES, INLINE_GLB_MAX_BASE64, DEFAULT_WIDTH_PX3, MIN_WIDTH_PX2, MAX_WIDTH_PX2, SVG_SCALE3, KEYFRAMES_DESCRIPTION, animateSchema, renderSequenceSchema, CAMERA_NODE, exportVideoSchema, ffmpegAvailable, timelineFromSimulationSchema, toolDefs52;
|
|
79245
79578
|
var init_animate = __esm({
|
|
79246
79579
|
"src/tools/animate.ts"() {
|
|
79247
79580
|
"use strict";
|
|
@@ -79393,7 +79726,7 @@ var init_animate = __esm({
|
|
|
79393
79726
|
},
|
|
79394
79727
|
required: ["env_id", "document_id"]
|
|
79395
79728
|
};
|
|
79396
|
-
|
|
79729
|
+
toolDefs52 = [
|
|
79397
79730
|
{
|
|
79398
79731
|
name: "animate",
|
|
79399
79732
|
pack: null,
|
|
@@ -79455,6 +79788,7 @@ function buildInstructions(kernelPrompt) {
|
|
|
79455
79788
|
"- 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).",
|
|
79456
79789
|
"- Ship with `export_cad` (STL/GLB/STEP) or `open_in_browser` (vcad.io deep link).",
|
|
79457
79790
|
"- Fix in place: when geometry is wrong, prefer `update` on the offending node over deleting parts and starting over.",
|
|
79791
|
+
"- 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.",
|
|
79458
79792
|
"- 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`. All BOM prices are estimates and flagged as such.",
|
|
79459
79793
|
"",
|
|
79460
79794
|
"",
|
|
@@ -80071,6 +80405,7 @@ async function createServer(existingEngine, context = { user: null }) {
|
|
|
80071
80405
|
function slimPreviewForInlineUi(result, docId, toolName, clientHasInlineUi) {
|
|
80072
80406
|
if (!clientHasInlineUi) return;
|
|
80073
80407
|
if (toolName === "sheet_metal_unfold") return;
|
|
80408
|
+
if (toolName === "flat_pattern_from_solid") return;
|
|
80074
80409
|
if (PURE_JSON_RESULT_TOOLS.has(toolName)) return;
|
|
80075
80410
|
const alwaysSlim = toolName === "create_cad_loon";
|
|
80076
80411
|
const totalChars = result.content.reduce(
|
|
@@ -80309,6 +80644,7 @@ var init_server3 = __esm({
|
|
|
80309
80644
|
init_loon_macros();
|
|
80310
80645
|
init_dfm2();
|
|
80311
80646
|
init_sheet_metal2();
|
|
80647
|
+
init_flat_pattern();
|
|
80312
80648
|
init_acoustics();
|
|
80313
80649
|
init_import();
|
|
80314
80650
|
init_import_pcb();
|
|
@@ -80323,8 +80659,8 @@ var init_server3 = __esm({
|
|
|
80323
80659
|
init_order_feed();
|
|
80324
80660
|
init_animate();
|
|
80325
80661
|
PKG_VERSION = (() => {
|
|
80326
|
-
if ("0.9.4-main.
|
|
80327
|
-
return "0.9.4-main.
|
|
80662
|
+
if ("0.9.4-main.41") {
|
|
80663
|
+
return "0.9.4-main.41";
|
|
80328
80664
|
}
|
|
80329
80665
|
try {
|
|
80330
80666
|
const req = createRequire2(import.meta.url);
|
|
@@ -80333,8 +80669,8 @@ var init_server3 = __esm({
|
|
|
80333
80669
|
return "0.0.0";
|
|
80334
80670
|
}
|
|
80335
80671
|
})();
|
|
80336
|
-
BUILD_SHA = "
|
|
80337
|
-
BUILD_TIME = "2026-07-
|
|
80672
|
+
BUILD_SHA = "b00f071e4b839c6448769107ed84182597d763ed";
|
|
80673
|
+
BUILD_TIME = "2026-07-26T14:41:39.682Z";
|
|
80338
80674
|
SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
|
|
80339
80675
|
VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
|
|
80340
80676
|
INSTANCE_ID = randomUUID6().slice(0, 8);
|
|
@@ -80407,11 +80743,12 @@ var init_server3 = __esm({
|
|
|
80407
80743
|
...toolDefs46,
|
|
80408
80744
|
...toolDefs47,
|
|
80409
80745
|
...toolDefs48,
|
|
80746
|
+
...toolDefs49,
|
|
80410
80747
|
...toolDefs20,
|
|
80411
80748
|
...toolDefs19,
|
|
80412
|
-
...toolDefs49,
|
|
80413
80749
|
...toolDefs50,
|
|
80414
|
-
...toolDefs51
|
|
80750
|
+
...toolDefs51,
|
|
80751
|
+
...toolDefs52
|
|
80415
80752
|
];
|
|
80416
80753
|
LIST_TOOL_ORDER = [
|
|
80417
80754
|
// ── Session lifecycle ──────────────────────────────────────
|
|
@@ -80518,6 +80855,7 @@ var init_server3 = __esm({
|
|
|
80518
80855
|
"sheet_metal_suggest_fix",
|
|
80519
80856
|
"sheet_metal_sequence",
|
|
80520
80857
|
"sheet_metal_nest",
|
|
80858
|
+
"flat_pattern_from_solid",
|
|
80521
80859
|
"simulate_strike",
|
|
80522
80860
|
// ── Import + share ─────────────────────────────────────────
|
|
80523
80861
|
"import_step",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vcad/mcp",
|
|
3
|
-
"version": "0.9.4-main.
|
|
3
|
+
"version": "0.9.4-main.41",
|
|
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-07-
|
|
22
|
+
"sha": "b00f071e4b839c6448769107ed84182597d763ed",
|
|
23
|
+
"builtAt": "2026-07-26T14:41:39.682Z"
|
|
24
24
|
}
|
|
25
25
|
}
|
package/vcad_kernel_wasm_bg.wasm
CHANGED
|
Binary file
|