@pascal-app/mcp 0.2.0 → 0.3.0
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/dist/bin/pascal-mcp.js +0 -0
- package/dist/lib/rehydrate-site-children.d.ts +5 -7
- package/dist/lib/rehydrate-site-children.d.ts.map +1 -1
- package/dist/lib/rehydrate-site-children.js +6 -36
- package/dist/templates/empty-studio.d.ts.map +1 -1
- package/dist/templates/empty-studio.js +0 -7
- package/dist/templates/garden-house.d.ts.map +1 -1
- package/dist/templates/garden-house.js +0 -1
- package/dist/templates/two-bedroom.d.ts.map +1 -1
- package/dist/templates/two-bedroom.js +0 -1
- package/dist/tools/construction-tools.d.ts +1 -1
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +8 -5
- package/dist/tools/find-nodes.d.ts +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.js +1 -1
- package/dist/tools/variants/generate-variants.d.ts.map +1 -1
- package/dist/tools/variants/generate-variants.js +0 -41
- package/package.json +3 -3
package/dist/bin/pascal-mcp.js
CHANGED
|
File without changes
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { SceneGraph } from '@pascal-app/core/clone-scene-graph';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Pure: returns a new graph without mutating the input.
|
|
3
|
+
* Previously re-embedded `SiteNode.children` from flat IDs back to full node
|
|
4
|
+
* objects to match the old schema. Since `SiteNode.children` is now
|
|
5
|
+
* `string[]` (upstream change), `cloneSceneGraph` / `forkSceneGraph` already
|
|
6
|
+
* produce the correct form — this function is a no-op kept for call-site
|
|
7
|
+
* compatibility.
|
|
10
8
|
*/
|
|
11
9
|
export declare function rehydrateSiteChildren(graph: SceneGraph): SceneGraph;
|
|
12
10
|
//# sourceMappingURL=rehydrate-site-children.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rehydrate-site-children.d.ts","sourceRoot":"","sources":["../../src/lib/rehydrate-site-children.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;
|
|
1
|
+
{"version":3,"file":"rehydrate-site-children.d.ts","sourceRoot":"","sources":["../../src/lib/rehydrate-site-children.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AAEpE;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEnE"}
|
|
@@ -1,40 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* `
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Pure: returns a new graph without mutating the input.
|
|
2
|
+
* Previously re-embedded `SiteNode.children` from flat IDs back to full node
|
|
3
|
+
* objects to match the old schema. Since `SiteNode.children` is now
|
|
4
|
+
* `string[]` (upstream change), `cloneSceneGraph` / `forkSceneGraph` already
|
|
5
|
+
* produce the correct form — this function is a no-op kept for call-site
|
|
6
|
+
* compatibility.
|
|
9
7
|
*/
|
|
10
8
|
export function rehydrateSiteChildren(graph) {
|
|
11
|
-
|
|
12
|
-
nodes: { ...graph.nodes },
|
|
13
|
-
rootNodeIds: [...graph.rootNodeIds],
|
|
14
|
-
...(graph.collections ? { collections: graph.collections } : {}),
|
|
15
|
-
};
|
|
16
|
-
for (const [id, node] of Object.entries(out.nodes)) {
|
|
17
|
-
if (node.type !== 'site')
|
|
18
|
-
continue;
|
|
19
|
-
const childrenField = node.children;
|
|
20
|
-
if (!Array.isArray(childrenField))
|
|
21
|
-
continue;
|
|
22
|
-
const rehydrated = [];
|
|
23
|
-
for (const child of childrenField) {
|
|
24
|
-
if (typeof child === 'string') {
|
|
25
|
-
const target = out.nodes[child];
|
|
26
|
-
if (target && (target.type === 'building' || target.type === 'item')) {
|
|
27
|
-
rehydrated.push(target);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
else if (child && typeof child === 'object' && 'id' in child) {
|
|
31
|
-
rehydrated.push(child);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
out.nodes[id] = {
|
|
35
|
-
...node,
|
|
36
|
-
children: rehydrated,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
return out;
|
|
9
|
+
return graph;
|
|
40
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"empty-studio.d.ts","sourceRoot":"","sources":["../../src/templates/empty-studio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;
|
|
1
|
+
{"version":3,"file":"empty-studio.d.ts","sourceRoot":"","sources":["../../src/templates/empty-studio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AAsPpE,eAAO,MAAM,QAAQ,EAAE,UAA4B,CAAA;AAEnD,eAAO,MAAM,QAAQ;;;;CAKX,CAAA"}
|
|
@@ -210,13 +210,6 @@ function buildTemplate() {
|
|
|
210
210
|
for (const node of [n.site, n.building, n.level, ...n.walls, n.zone, n.door, n.window]) {
|
|
211
211
|
nodes[node.id] = node;
|
|
212
212
|
}
|
|
213
|
-
// SiteNode.children is a discriminatedUnion of BuildingNode/ItemNode objects
|
|
214
|
-
// (not string ids) — so the site must embed the full building node. The
|
|
215
|
-
// rest of the tree uses string ids per the BaseNode/LevelNode/WallNode
|
|
216
|
-
// schemas. We mutate the flat-dict copy of the site here so the nested
|
|
217
|
-
// representation round-trips through AnyNode.safeParse.
|
|
218
|
-
const siteInDict = nodes['site_empty'];
|
|
219
|
-
siteInDict.children = [nodes['building_empty']];
|
|
220
213
|
return {
|
|
221
214
|
nodes,
|
|
222
215
|
rootNodeIds: ['site_empty'],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"garden-house.d.ts","sourceRoot":"","sources":["../../src/templates/garden-house.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;
|
|
1
|
+
{"version":3,"file":"garden-house.d.ts","sourceRoot":"","sources":["../../src/templates/garden-house.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AA+QpE,eAAO,MAAM,QAAQ,EAAE,UAA4B,CAAA;AAEnD,eAAO,MAAM,QAAQ;;;;CAKX,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"two-bedroom.d.ts","sourceRoot":"","sources":["../../src/templates/two-bedroom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;
|
|
1
|
+
{"version":3,"file":"two-bedroom.d.ts","sourceRoot":"","sources":["../../src/templates/two-bedroom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AA2SpE,eAAO,MAAM,QAAQ,EAAE,UAA4B,CAAA;AAEnD,eAAO,MAAM,QAAQ;;;;CAKX,CAAA"}
|
|
@@ -41,7 +41,7 @@ export declare const createRoofInput: {
|
|
|
41
41
|
dutch: "dutch";
|
|
42
42
|
mansard: "mansard";
|
|
43
43
|
}>>;
|
|
44
|
-
|
|
44
|
+
pitch: z.ZodDefault<z.ZodNumber>;
|
|
45
45
|
wallHeight: z.ZodDefault<z.ZodNumber>;
|
|
46
46
|
wallThickness: z.ZodDefault<z.ZodNumber>;
|
|
47
47
|
overhang: z.ZodDefault<z.ZodNumber>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"construction-tools.d.ts","sourceRoot":"","sources":["../../src/tools/construction-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;
|
|
1
|
+
{"version":3,"file":"construction-tools.d.ts","sourceRoot":"","sources":["../../src/tools/construction-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAaxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAajC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;CAMlC,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;CAiB3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;CAM5B,CAAA;AAED,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;CAqBzC,CAAA;AAED,eAAO,MAAM,8BAA8B;;;;;;CAM1C,CAAA;AA4GD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAiT1F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CeilingNode, LevelNode, RoofNode, RoofSegmentNode, SlabNode, StairNode, StairSegmentNode, WallNode, } from '@pascal-app/core/schema';
|
|
1
|
+
import { CeilingNode, getActiveRoofHeight, LevelNode, RoofNode, RoofSegmentNode, SlabNode, StairNode, StairSegmentNode, WallNode, } from '@pascal-app/core/schema';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { publishLiveSceneSnapshot } from './live-sync';
|
|
4
4
|
import { NodeIdSchema, Vec2Schema, Vec3Schema } from './schemas';
|
|
@@ -36,7 +36,7 @@ export const createRoofInput = {
|
|
|
36
36
|
width: z.number().positive(),
|
|
37
37
|
depth: z.number().positive(),
|
|
38
38
|
roofType: z.enum(ROOF_TYPES).default('hip'),
|
|
39
|
-
|
|
39
|
+
pitch: z.number().min(0).max(85).default(35),
|
|
40
40
|
wallHeight: z.number().min(0).default(0.35),
|
|
41
41
|
wallThickness: z.number().positive().default(0.16),
|
|
42
42
|
overhang: z.number().min(0).default(0.45),
|
|
@@ -222,7 +222,10 @@ export function registerConstructionTools(server, bridge) {
|
|
|
222
222
|
description: 'Create a roof container with one roof segment. By default creates a dedicated roof level above the reference level so exploded/solo level views can isolate the roof.',
|
|
223
223
|
inputSchema: createRoofInput,
|
|
224
224
|
outputSchema: createRoofOutput,
|
|
225
|
-
}, async ({ levelId, roofLevelId, useDedicatedRoofLevel, roofLevelLabel, roofLevelElevation, roofLevelHeight, center, width, depth, roofType,
|
|
225
|
+
}, async ({ levelId, roofLevelId, useDedicatedRoofLevel, roofLevelLabel, roofLevelElevation, roofLevelHeight, center, width, depth, roofType, pitch, wallHeight, wallThickness, overhang, materialPreset, name, }) => {
|
|
226
|
+
// Peak height is derived from pitch + footprint + type; we still
|
|
227
|
+
// need it to size the auto-generated roof level container below.
|
|
228
|
+
const peakHeight = getActiveRoofHeight({ roofType, pitch, width, depth });
|
|
226
229
|
const referenceLevel = assertNode(bridge, levelId, 'level');
|
|
227
230
|
const patches = [];
|
|
228
231
|
let targetRoofLevelId = levelId;
|
|
@@ -244,7 +247,7 @@ export function registerConstructionTools(server, bridge) {
|
|
|
244
247
|
role: 'roof',
|
|
245
248
|
label: roofLevelLabel,
|
|
246
249
|
referenceLevelId: levelId,
|
|
247
|
-
height: roofLevelHeight ?? Math.max(wallHeight +
|
|
250
|
+
height: roofLevelHeight ?? Math.max(wallHeight + peakHeight, 0.2),
|
|
248
251
|
},
|
|
249
252
|
});
|
|
250
253
|
targetRoofLevelId = roofLevel.id;
|
|
@@ -256,7 +259,7 @@ export function registerConstructionTools(server, bridge) {
|
|
|
256
259
|
width,
|
|
257
260
|
depth,
|
|
258
261
|
wallHeight,
|
|
259
|
-
|
|
262
|
+
pitch,
|
|
260
263
|
wallThickness,
|
|
261
264
|
overhang,
|
|
262
265
|
...(materialPreset ? { materialPreset } : {}),
|
|
@@ -164,7 +164,7 @@ function buildSceneGraphFromVision(vision, defaultWallThickness, defaultWallHeig
|
|
|
164
164
|
// Build the skeleton: site → building → level.
|
|
165
165
|
const building = BuildingNode.parse({});
|
|
166
166
|
const level = LevelNode.parse({ level: 0 });
|
|
167
|
-
const site = SiteNode.parse({ children: [building] });
|
|
167
|
+
const site = SiteNode.parse({ children: [building.id] });
|
|
168
168
|
// Link parent ids so downstream traversal works.
|
|
169
169
|
const siteId = site.id;
|
|
170
170
|
const buildingId = building.id;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-variants.d.ts","sourceRoot":"","sources":["../../../src/tools/variants/generate-variants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAcvD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;CAYjC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;CAWlC,CAAA;
|
|
1
|
+
{"version":3,"file":"generate-variants.d.ts","sourceRoot":"","sources":["../../../src/tools/variants/generate-variants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAcvD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;CAYjC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;CAWlC,CAAA;AAcD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA0FzF"}
|
|
@@ -35,45 +35,6 @@ export const generateVariantsOutput = {
|
|
|
35
35
|
graph: z.any().optional(),
|
|
36
36
|
})),
|
|
37
37
|
};
|
|
38
|
-
/**
|
|
39
|
-
* `forkSceneGraph` normalises `SiteNode.children` to string IDs, but the
|
|
40
|
-
* `SiteNode` schema declares that field as an array of full `BuildingNode` /
|
|
41
|
-
* `ItemNode` objects (see CROSS_CUTTING §2). To keep variants validating
|
|
42
|
-
* against `AnyNode`, re-embed the site children from the flat dict.
|
|
43
|
-
*
|
|
44
|
-
* Pure: returns a new graph without mutating the input.
|
|
45
|
-
*/
|
|
46
|
-
function rehydrateSiteChildren(graph) {
|
|
47
|
-
const out = {
|
|
48
|
-
nodes: { ...graph.nodes },
|
|
49
|
-
rootNodeIds: [...graph.rootNodeIds],
|
|
50
|
-
...(graph.collections ? { collections: graph.collections } : {}),
|
|
51
|
-
};
|
|
52
|
-
for (const [id, node] of Object.entries(out.nodes)) {
|
|
53
|
-
if (node.type !== 'site')
|
|
54
|
-
continue;
|
|
55
|
-
const childrenField = node.children;
|
|
56
|
-
if (!Array.isArray(childrenField))
|
|
57
|
-
continue;
|
|
58
|
-
const rehydrated = [];
|
|
59
|
-
for (const child of childrenField) {
|
|
60
|
-
if (typeof child === 'string') {
|
|
61
|
-
const target = out.nodes[child];
|
|
62
|
-
if (target && (target.type === 'building' || target.type === 'item')) {
|
|
63
|
-
rehydrated.push(target);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
else if (child && typeof child === 'object' && 'id' in child) {
|
|
67
|
-
rehydrated.push(child);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
out.nodes[id] = {
|
|
71
|
-
...node,
|
|
72
|
-
children: rehydrated,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
return out;
|
|
76
|
-
}
|
|
77
38
|
/**
|
|
78
39
|
* Count how many nodes in a graph fail `AnyNode` validation. Used to keep the
|
|
79
40
|
* tool from returning silently corrupt variants.
|
|
@@ -120,8 +81,6 @@ export function registerGenerateVariants(server, bridge) {
|
|
|
120
81
|
for (const kind of mutations) {
|
|
121
82
|
forked = applyMutation(forked, rng, kind);
|
|
122
83
|
}
|
|
123
|
-
// Re-embed site children so variants match the SiteNode schema.
|
|
124
|
-
forked = rehydrateSiteChildren(forked);
|
|
125
84
|
const invalidCount = countInvalidNodes(forked);
|
|
126
85
|
if (invalidCount > 0) {
|
|
127
86
|
throwMcpError(ErrorCode.InternalError, `variant_invalid: variant ${i} produced ${invalidCount} invalid node(s)`, { index: i });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pascal-app/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Model Context Protocol server for Pascal 3D editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,14 +54,14 @@
|
|
|
54
54
|
"prepublishOnly": "bun run build && bun test"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@pascal-app/core": "^0.
|
|
57
|
+
"@pascal-app/core": "^0.8.0"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
61
61
|
"zod": "^4.3.5"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@pascal-app/core": "^0.
|
|
64
|
+
"@pascal-app/core": "^0.8.0",
|
|
65
65
|
"@pascal/typescript-config": "*",
|
|
66
66
|
"@types/node": "^25.5.0",
|
|
67
67
|
"typescript": "5.9.3"
|