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