@pascal-app/mcp 0.2.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.
Files changed (249) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +330 -0
  3. package/dist/bin/pascal-mcp.d.ts +3 -0
  4. package/dist/bin/pascal-mcp.d.ts.map +1 -0
  5. package/dist/bin/pascal-mcp.js +91 -0
  6. package/dist/bridge/index.d.ts +3 -0
  7. package/dist/bridge/index.d.ts.map +1 -0
  8. package/dist/bridge/index.js +1 -0
  9. package/dist/bridge/node-shims.d.ts +16 -0
  10. package/dist/bridge/node-shims.d.ts.map +1 -0
  11. package/dist/bridge/node-shims.js +25 -0
  12. package/dist/bridge/scene-bridge.d.ts +158 -0
  13. package/dist/bridge/scene-bridge.d.ts.map +1 -0
  14. package/dist/bridge/scene-bridge.js +482 -0
  15. package/dist/index.d.ts +5 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +4 -0
  18. package/dist/lib/rehydrate-site-children.d.ts +12 -0
  19. package/dist/lib/rehydrate-site-children.d.ts.map +1 -0
  20. package/dist/lib/rehydrate-site-children.js +40 -0
  21. package/dist/lib/safe-fetch.d.ts +19 -0
  22. package/dist/lib/safe-fetch.d.ts.map +1 -0
  23. package/dist/lib/safe-fetch.js +221 -0
  24. package/dist/operations/index.d.ts +2 -0
  25. package/dist/operations/index.d.ts.map +1 -0
  26. package/dist/operations/index.js +1 -0
  27. package/dist/operations/scene-operations.d.ts +67 -0
  28. package/dist/operations/scene-operations.d.ts.map +1 -0
  29. package/dist/operations/scene-operations.js +192 -0
  30. package/dist/prompts/from-brief.d.ts +11 -0
  31. package/dist/prompts/from-brief.d.ts.map +1 -0
  32. package/dist/prompts/from-brief.js +48 -0
  33. package/dist/prompts/index.d.ts +10 -0
  34. package/dist/prompts/index.d.ts.map +1 -0
  35. package/dist/prompts/index.js +14 -0
  36. package/dist/prompts/iterate-on-feedback.d.ts +11 -0
  37. package/dist/prompts/iterate-on-feedback.d.ts.map +1 -0
  38. package/dist/prompts/iterate-on-feedback.js +41 -0
  39. package/dist/prompts/renovation-from-photos.d.ts +24 -0
  40. package/dist/prompts/renovation-from-photos.d.ts.map +1 -0
  41. package/dist/prompts/renovation-from-photos.js +135 -0
  42. package/dist/prompts/scene-guidance.d.ts +2 -0
  43. package/dist/prompts/scene-guidance.d.ts.map +1 -0
  44. package/dist/prompts/scene-guidance.js +24 -0
  45. package/dist/resources/agent-guide.d.ts +5 -0
  46. package/dist/resources/agent-guide.d.ts.map +1 -0
  47. package/dist/resources/agent-guide.js +85 -0
  48. package/dist/resources/catalog-items.d.ts +10 -0
  49. package/dist/resources/catalog-items.d.ts.map +1 -0
  50. package/dist/resources/catalog-items.js +29 -0
  51. package/dist/resources/constraints.d.ts +9 -0
  52. package/dist/resources/constraints.d.ts.map +1 -0
  53. package/dist/resources/constraints.js +69 -0
  54. package/dist/resources/index.d.ts +15 -0
  55. package/dist/resources/index.d.ts.map +1 -0
  56. package/dist/resources/index.js +23 -0
  57. package/dist/resources/scene-current.d.ts +9 -0
  58. package/dist/resources/scene-current.d.ts.map +1 -0
  59. package/dist/resources/scene-current.js +20 -0
  60. package/dist/resources/scene-summary.d.ts +10 -0
  61. package/dist/resources/scene-summary.d.ts.map +1 -0
  62. package/dist/resources/scene-summary.js +196 -0
  63. package/dist/server.d.ts +14 -0
  64. package/dist/server.d.ts.map +1 -0
  65. package/dist/server.js +18 -0
  66. package/dist/storage/index.d.ts +13 -0
  67. package/dist/storage/index.d.ts.map +1 -0
  68. package/dist/storage/index.js +14 -0
  69. package/dist/storage/slug.d.ts +21 -0
  70. package/dist/storage/slug.d.ts.map +1 -0
  71. package/dist/storage/slug.js +62 -0
  72. package/dist/storage/sqlite-driver.d.ts +18 -0
  73. package/dist/storage/sqlite-driver.d.ts.map +1 -0
  74. package/dist/storage/sqlite-driver.js +32 -0
  75. package/dist/storage/sqlite-scene-store.d.ts +51 -0
  76. package/dist/storage/sqlite-scene-store.d.ts.map +1 -0
  77. package/dist/storage/sqlite-scene-store.js +526 -0
  78. package/dist/storage/types.d.ts +136 -0
  79. package/dist/storage/types.d.ts.map +1 -0
  80. package/dist/storage/types.js +28 -0
  81. package/dist/templates/empty-studio.d.ts +8 -0
  82. package/dist/templates/empty-studio.d.ts.map +1 -0
  83. package/dist/templates/empty-studio.js +230 -0
  84. package/dist/templates/garden-house.d.ts +8 -0
  85. package/dist/templates/garden-house.d.ts.map +1 -0
  86. package/dist/templates/garden-house.js +242 -0
  87. package/dist/templates/index.d.ts +23 -0
  88. package/dist/templates/index.d.ts.map +1 -0
  89. package/dist/templates/index.js +20 -0
  90. package/dist/templates/two-bedroom.d.ts +8 -0
  91. package/dist/templates/two-bedroom.d.ts.map +1 -0
  92. package/dist/templates/two-bedroom.js +270 -0
  93. package/dist/tools/apply-patch.d.ts +25 -0
  94. package/dist/tools/apply-patch.d.ts.map +1 -0
  95. package/dist/tools/apply-patch.js +59 -0
  96. package/dist/tools/asset-catalog.d.ts +16 -0
  97. package/dist/tools/asset-catalog.d.ts.map +1 -0
  98. package/dist/tools/asset-catalog.js +308 -0
  99. package/dist/tools/check-collisions.d.ts +15 -0
  100. package/dist/tools/check-collisions.d.ts.map +1 -0
  101. package/dist/tools/check-collisions.js +61 -0
  102. package/dist/tools/construction-tools.d.ts +93 -0
  103. package/dist/tools/construction-tools.d.ts.map +1 -0
  104. package/dist/tools/construction-tools.js +369 -0
  105. package/dist/tools/create-level.d.ts +14 -0
  106. package/dist/tools/create-level.d.ts.map +1 -0
  107. package/dist/tools/create-level.js +48 -0
  108. package/dist/tools/create-wall.d.ts +15 -0
  109. package/dist/tools/create-wall.d.ts.map +1 -0
  110. package/dist/tools/create-wall.js +50 -0
  111. package/dist/tools/cut-opening.d.ts +18 -0
  112. package/dist/tools/cut-opening.d.ts.map +1 -0
  113. package/dist/tools/cut-opening.js +57 -0
  114. package/dist/tools/delete-node.d.ts +12 -0
  115. package/dist/tools/delete-node.d.ts.map +1 -0
  116. package/dist/tools/delete-node.js +37 -0
  117. package/dist/tools/describe-node.d.ts +17 -0
  118. package/dist/tools/describe-node.d.ts.map +1 -0
  119. package/dist/tools/describe-node.js +86 -0
  120. package/dist/tools/duplicate-level.d.ts +12 -0
  121. package/dist/tools/duplicate-level.d.ts.map +1 -0
  122. package/dist/tools/duplicate-level.js +56 -0
  123. package/dist/tools/errors.d.ts +20 -0
  124. package/dist/tools/errors.d.ts.map +1 -0
  125. package/dist/tools/errors.js +25 -0
  126. package/dist/tools/export-glb.d.ts +10 -0
  127. package/dist/tools/export-glb.d.ts.map +1 -0
  128. package/dist/tools/export-glb.js +24 -0
  129. package/dist/tools/export-json.d.ts +11 -0
  130. package/dist/tools/export-json.d.ts.map +1 -0
  131. package/dist/tools/export-json.js +23 -0
  132. package/dist/tools/find-nodes.d.ts +32 -0
  133. package/dist/tools/find-nodes.d.ts.map +1 -0
  134. package/dist/tools/find-nodes.js +105 -0
  135. package/dist/tools/geometry.d.ts +24 -0
  136. package/dist/tools/geometry.d.ts.map +1 -0
  137. package/dist/tools/geometry.js +94 -0
  138. package/dist/tools/get-node.d.ts +11 -0
  139. package/dist/tools/get-node.d.ts.map +1 -0
  140. package/dist/tools/get-node.js +27 -0
  141. package/dist/tools/get-scene.d.ts +11 -0
  142. package/dist/tools/get-scene.d.ts.map +1 -0
  143. package/dist/tools/get-scene.js +26 -0
  144. package/dist/tools/index.d.ts +12 -0
  145. package/dist/tools/index.d.ts.map +1 -0
  146. package/dist/tools/index.js +64 -0
  147. package/dist/tools/live-sync.d.ts +11 -0
  148. package/dist/tools/live-sync.d.ts.map +1 -0
  149. package/dist/tools/live-sync.js +62 -0
  150. package/dist/tools/measure.d.ts +14 -0
  151. package/dist/tools/measure.d.ts.map +1 -0
  152. package/dist/tools/measure.js +137 -0
  153. package/dist/tools/photo-to-scene/index.d.ts +11 -0
  154. package/dist/tools/photo-to-scene/index.d.ts.map +1 -0
  155. package/dist/tools/photo-to-scene/index.js +11 -0
  156. package/dist/tools/photo-to-scene/photo-to-scene.d.ts +26 -0
  157. package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -0
  158. package/dist/tools/photo-to-scene/photo-to-scene.js +323 -0
  159. package/dist/tools/place-item.d.ts +15 -0
  160. package/dist/tools/place-item.d.ts.map +1 -0
  161. package/dist/tools/place-item.js +84 -0
  162. package/dist/tools/redo.d.ts +11 -0
  163. package/dist/tools/redo.d.ts.map +1 -0
  164. package/dist/tools/redo.js +25 -0
  165. package/dist/tools/room-tools.d.ts +97 -0
  166. package/dist/tools/room-tools.d.ts.map +1 -0
  167. package/dist/tools/room-tools.js +510 -0
  168. package/dist/tools/scene-lifecycle/create-project.d.ts +33 -0
  169. package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -0
  170. package/dist/tools/scene-lifecycle/create-project.js +70 -0
  171. package/dist/tools/scene-lifecycle/delete-scene.d.ts +12 -0
  172. package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -0
  173. package/dist/tools/scene-lifecycle/delete-scene.js +42 -0
  174. package/dist/tools/scene-lifecycle/get-project-status.d.ts +31 -0
  175. package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -0
  176. package/dist/tools/scene-lifecycle/get-project-status.js +69 -0
  177. package/dist/tools/scene-lifecycle/index.d.ts +17 -0
  178. package/dist/tools/scene-lifecycle/index.d.ts.map +1 -0
  179. package/dist/tools/scene-lifecycle/index.js +29 -0
  180. package/dist/tools/scene-lifecycle/list-scenes.d.ts +27 -0
  181. package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -0
  182. package/dist/tools/scene-lifecycle/list-scenes.js +49 -0
  183. package/dist/tools/scene-lifecycle/load-scene.d.ts +31 -0
  184. package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -0
  185. package/dist/tools/scene-lifecycle/load-scene.js +55 -0
  186. package/dist/tools/scene-lifecycle/metadata.d.ts +49 -0
  187. package/dist/tools/scene-lifecycle/metadata.d.ts.map +1 -0
  188. package/dist/tools/scene-lifecycle/metadata.js +68 -0
  189. package/dist/tools/scene-lifecycle/rename-scene.d.ts +22 -0
  190. package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -0
  191. package/dist/tools/scene-lifecycle/rename-scene.js +63 -0
  192. package/dist/tools/scene-lifecycle/save-scene.d.ts +42 -0
  193. package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -0
  194. package/dist/tools/scene-lifecycle/save-scene.js +130 -0
  195. package/dist/tools/scene-lifecycle/test-utils.d.ts +39 -0
  196. package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -0
  197. package/dist/tools/scene-lifecycle/test-utils.js +211 -0
  198. package/dist/tools/scene-query.d.ts +57 -0
  199. package/dist/tools/scene-query.d.ts.map +1 -0
  200. package/dist/tools/scene-query.js +645 -0
  201. package/dist/tools/schemas.d.ts +52 -0
  202. package/dist/tools/schemas.d.ts.map +1 -0
  203. package/dist/tools/schemas.js +42 -0
  204. package/dist/tools/set-zone.d.ts +14 -0
  205. package/dist/tools/set-zone.d.ts.map +1 -0
  206. package/dist/tools/set-zone.js +48 -0
  207. package/dist/tools/templates/create-from-template.d.ts +54 -0
  208. package/dist/tools/templates/create-from-template.d.ts.map +1 -0
  209. package/dist/tools/templates/create-from-template.js +145 -0
  210. package/dist/tools/templates/create-house-from-brief.d.ts +35 -0
  211. package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -0
  212. package/dist/tools/templates/create-house-from-brief.js +170 -0
  213. package/dist/tools/templates/index.d.ts +14 -0
  214. package/dist/tools/templates/index.d.ts.map +1 -0
  215. package/dist/tools/templates/index.js +18 -0
  216. package/dist/tools/templates/list-templates.d.ts +18 -0
  217. package/dist/tools/templates/list-templates.d.ts.map +1 -0
  218. package/dist/tools/templates/list-templates.js +36 -0
  219. package/dist/tools/undo.d.ts +11 -0
  220. package/dist/tools/undo.d.ts.map +1 -0
  221. package/dist/tools/undo.js +25 -0
  222. package/dist/tools/validate-scene.d.ts +14 -0
  223. package/dist/tools/validate-scene.d.ts.map +1 -0
  224. package/dist/tools/validate-scene.js +24 -0
  225. package/dist/tools/variants/generate-variants.d.ts +30 -0
  226. package/dist/tools/variants/generate-variants.d.ts.map +1 -0
  227. package/dist/tools/variants/generate-variants.js +160 -0
  228. package/dist/tools/variants/index.d.ts +9 -0
  229. package/dist/tools/variants/index.d.ts.map +1 -0
  230. package/dist/tools/variants/index.js +9 -0
  231. package/dist/tools/variants/mutations.d.ts +18 -0
  232. package/dist/tools/variants/mutations.d.ts.map +1 -0
  233. package/dist/tools/variants/mutations.js +324 -0
  234. package/dist/tools/vision/analyze-floorplan-image.d.ts +33 -0
  235. package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -0
  236. package/dist/tools/vision/analyze-floorplan-image.js +146 -0
  237. package/dist/tools/vision/analyze-room-photo.d.ts +29 -0
  238. package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -0
  239. package/dist/tools/vision/analyze-room-photo.js +130 -0
  240. package/dist/tools/vision/index.d.ts +12 -0
  241. package/dist/tools/vision/index.d.ts.map +1 -0
  242. package/dist/tools/vision/index.js +14 -0
  243. package/dist/transports/http.d.ts +36 -0
  244. package/dist/transports/http.d.ts.map +1 -0
  245. package/dist/transports/http.js +203 -0
  246. package/dist/transports/stdio.d.ts +14 -0
  247. package/dist/transports/stdio.d.ts.map +1 -0
  248. package/dist/transports/stdio.js +16 -0
  249. package/package.json +86 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * 80 m² two-bedroom apartment.
3
+ *
4
+ * Footprint: 10 m × 8 m = 80 m², centered near the origin.
5
+ * Contents: 9 walls (4 perimeter + 5 interior), 4 zones
6
+ * (living/kitchen, bedroom1, bedroom2, bath), 4 doors (front + 3 interior),
7
+ * 5 windows (2 on the living/kitchen, 1 per bedroom, 1 on the bath).
8
+ * Interior partitions split the north half into two bedrooms and a bath.
9
+ *
10
+ * Coordinate system: `[x, z]` on the XZ plane, with `x` running east/west
11
+ * and `z` running north/south (positive z points south).
12
+ */
13
+ // Perimeter extents: 10 m × 8 m.
14
+ const X_MIN = -5;
15
+ const X_MAX = 5;
16
+ const Z_MIN = -4;
17
+ const Z_MAX = 4;
18
+ // Interior split lines.
19
+ const CORRIDOR_Z = 0; // horizontal wall separating north half (bedrooms+bath) from south (living)
20
+ const BED_X = -1; // vertical wall between bedroom 1 (west) and bath (east of it)
21
+ const BATH_X = 2; // vertical wall between bath (middle) and bedroom 2 (east)
22
+ const WALL_THICKNESS = 0.1;
23
+ const WALL_HEIGHT = 2.5;
24
+ function wall(id, start, end, children = []) {
25
+ return {
26
+ object: 'node',
27
+ id,
28
+ type: 'wall',
29
+ parentId: 'level_0',
30
+ visible: true,
31
+ metadata: {},
32
+ children,
33
+ thickness: WALL_THICKNESS,
34
+ height: WALL_HEIGHT,
35
+ start,
36
+ end,
37
+ frontSide: 'unknown',
38
+ backSide: 'unknown',
39
+ };
40
+ }
41
+ function door(id, parentWallId) {
42
+ return {
43
+ object: 'node',
44
+ id,
45
+ type: 'door',
46
+ parentId: parentWallId,
47
+ visible: true,
48
+ metadata: {},
49
+ wallId: parentWallId,
50
+ position: [0, 1.05, 0],
51
+ rotation: [0, 0, 0],
52
+ width: 0.8,
53
+ height: 2.1,
54
+ frameThickness: 0.05,
55
+ frameDepth: 0.07,
56
+ threshold: true,
57
+ thresholdHeight: 0.02,
58
+ hingesSide: 'left',
59
+ swingDirection: 'inward',
60
+ segments: [
61
+ {
62
+ type: 'panel',
63
+ heightRatio: 0.5,
64
+ columnRatios: [1],
65
+ dividerThickness: 0.03,
66
+ panelDepth: 0.01,
67
+ panelInset: 0.04,
68
+ },
69
+ {
70
+ type: 'panel',
71
+ heightRatio: 0.5,
72
+ columnRatios: [1],
73
+ dividerThickness: 0.03,
74
+ panelDepth: 0.01,
75
+ panelInset: 0.04,
76
+ },
77
+ ],
78
+ handle: true,
79
+ handleHeight: 1.05,
80
+ handleSide: 'right',
81
+ contentPadding: [0.04, 0.04],
82
+ doorCloser: false,
83
+ panicBar: false,
84
+ panicBarHeight: 1.0,
85
+ };
86
+ }
87
+ function makeWindow(id, parentWallId, width = 1.2) {
88
+ return {
89
+ object: 'node',
90
+ id,
91
+ type: 'window',
92
+ parentId: parentWallId,
93
+ visible: true,
94
+ metadata: {},
95
+ wallId: parentWallId,
96
+ position: [0, 1.2, 0],
97
+ rotation: [0, 0, 0],
98
+ width,
99
+ height: 1.2,
100
+ frameThickness: 0.05,
101
+ frameDepth: 0.07,
102
+ columnRatios: [1],
103
+ rowRatios: [1],
104
+ columnDividerThickness: 0.03,
105
+ rowDividerThickness: 0.03,
106
+ sill: true,
107
+ sillDepth: 0.08,
108
+ sillThickness: 0.03,
109
+ };
110
+ }
111
+ function buildTemplate() {
112
+ const nodes = {};
113
+ // Root nodes
114
+ nodes.site_2br = {
115
+ object: 'node',
116
+ id: 'site_2br',
117
+ type: 'site',
118
+ parentId: null,
119
+ visible: true,
120
+ metadata: {},
121
+ polygon: {
122
+ type: 'polygon',
123
+ points: [
124
+ [-15, -15],
125
+ [15, -15],
126
+ [15, 15],
127
+ [-15, 15],
128
+ ],
129
+ },
130
+ children: ['building_2br'],
131
+ };
132
+ nodes.building_2br = {
133
+ object: 'node',
134
+ id: 'building_2br',
135
+ type: 'building',
136
+ parentId: 'site_2br',
137
+ visible: true,
138
+ metadata: {},
139
+ position: [0, 0, 0],
140
+ rotation: [0, 0, 0],
141
+ children: ['level_0'],
142
+ };
143
+ // Openings — declared up front so walls can list them as children.
144
+ nodes.door_front = door('door_front', 'wall_s');
145
+ nodes.door_bed1 = door('door_bed1', 'wall_corr_1');
146
+ nodes.door_bath = door('door_bath', 'wall_corr_2');
147
+ nodes.door_bed2 = door('door_bed2', 'wall_corr_3');
148
+ nodes.window_living_a = makeWindow('window_living_a', 'wall_s', 1.5);
149
+ nodes.window_living_b = makeWindow('window_living_b', 'wall_e', 1.2);
150
+ nodes.window_bed1 = makeWindow('window_bed1', 'wall_n', 1.2);
151
+ nodes.window_bath = makeWindow('window_bath', 'wall_n', 0.6);
152
+ nodes.window_bed2 = makeWindow('window_bed2', 'wall_n', 1.2);
153
+ // Perimeter walls (N, E, S, W) — 4 walls.
154
+ // Interior partitions — 5 walls (the east/west corridor wall is split into
155
+ // three segments by the two vertical partitions so doors have a clear host).
156
+ nodes.wall_n = wall('wall_n', [X_MIN, Z_MIN], [X_MAX, Z_MIN], ['window_bed1', 'window_bath', 'window_bed2']);
157
+ nodes.wall_e = wall('wall_e', [X_MAX, Z_MIN], [X_MAX, Z_MAX], ['window_living_b']);
158
+ nodes.wall_s = wall('wall_s', [X_MAX, Z_MAX], [X_MIN, Z_MAX], ['door_front', 'window_living_a']);
159
+ nodes.wall_w = wall('wall_w', [X_MIN, Z_MAX], [X_MIN, Z_MIN]);
160
+ // Corridor wall is broken into 3 segments so each has its own interior door.
161
+ // Segment 1: from west to BED_X (bedroom-1 wall)
162
+ nodes.wall_corr_1 = wall('wall_corr_1', [X_MIN, CORRIDOR_Z], [BED_X, CORRIDOR_Z], ['door_bed1']);
163
+ // Segment 2: from BED_X to BATH_X (bath wall)
164
+ nodes.wall_corr_2 = wall('wall_corr_2', [BED_X, CORRIDOR_Z], [BATH_X, CORRIDOR_Z], ['door_bath']);
165
+ // Segment 3: from BATH_X to east (bedroom-2 wall)
166
+ nodes.wall_corr_3 = wall('wall_corr_3', [BATH_X, CORRIDOR_Z], [X_MAX, CORRIDOR_Z], ['door_bed2']);
167
+ // Two vertical partitions between the three north rooms.
168
+ nodes.wall_part_1 = wall('wall_part_1', [BED_X, Z_MIN], [BED_X, CORRIDOR_Z]);
169
+ nodes.wall_part_2 = wall('wall_part_2', [BATH_X, Z_MIN], [BATH_X, CORRIDOR_Z]);
170
+ // Zones: one per room.
171
+ nodes.zone_living = {
172
+ object: 'node',
173
+ id: 'zone_living',
174
+ type: 'zone',
175
+ parentId: 'level_0',
176
+ visible: true,
177
+ metadata: {},
178
+ name: 'Living / Kitchen',
179
+ color: '#60a5fa',
180
+ polygon: [
181
+ [X_MIN, CORRIDOR_Z],
182
+ [X_MAX, CORRIDOR_Z],
183
+ [X_MAX, Z_MAX],
184
+ [X_MIN, Z_MAX],
185
+ ],
186
+ };
187
+ nodes.zone_bed1 = {
188
+ object: 'node',
189
+ id: 'zone_bed1',
190
+ type: 'zone',
191
+ parentId: 'level_0',
192
+ visible: true,
193
+ metadata: {},
194
+ name: 'Bedroom 1',
195
+ color: '#f472b6',
196
+ polygon: [
197
+ [X_MIN, Z_MIN],
198
+ [BED_X, Z_MIN],
199
+ [BED_X, CORRIDOR_Z],
200
+ [X_MIN, CORRIDOR_Z],
201
+ ],
202
+ };
203
+ nodes.zone_bath = {
204
+ object: 'node',
205
+ id: 'zone_bath',
206
+ type: 'zone',
207
+ parentId: 'level_0',
208
+ visible: true,
209
+ metadata: {},
210
+ name: 'Bath',
211
+ color: '#a7f3d0',
212
+ polygon: [
213
+ [BED_X, Z_MIN],
214
+ [BATH_X, Z_MIN],
215
+ [BATH_X, CORRIDOR_Z],
216
+ [BED_X, CORRIDOR_Z],
217
+ ],
218
+ };
219
+ nodes.zone_bed2 = {
220
+ object: 'node',
221
+ id: 'zone_bed2',
222
+ type: 'zone',
223
+ parentId: 'level_0',
224
+ visible: true,
225
+ metadata: {},
226
+ name: 'Bedroom 2',
227
+ color: '#fcd34d',
228
+ polygon: [
229
+ [BATH_X, Z_MIN],
230
+ [X_MAX, Z_MIN],
231
+ [X_MAX, CORRIDOR_Z],
232
+ [BATH_X, CORRIDOR_Z],
233
+ ],
234
+ };
235
+ nodes.level_0 = {
236
+ object: 'node',
237
+ id: 'level_0',
238
+ type: 'level',
239
+ parentId: 'building_2br',
240
+ visible: true,
241
+ metadata: {},
242
+ level: 0,
243
+ children: [
244
+ 'wall_n',
245
+ 'wall_e',
246
+ 'wall_s',
247
+ 'wall_w',
248
+ 'wall_corr_1',
249
+ 'wall_corr_2',
250
+ 'wall_corr_3',
251
+ 'wall_part_1',
252
+ 'wall_part_2',
253
+ 'zone_living',
254
+ 'zone_bed1',
255
+ 'zone_bath',
256
+ 'zone_bed2',
257
+ ],
258
+ };
259
+ nodes.site_2br.children = [nodes.building_2br];
260
+ return {
261
+ nodes: nodes,
262
+ rootNodeIds: ['site_2br'],
263
+ };
264
+ }
265
+ export const template = buildTemplate();
266
+ export const metadata = {
267
+ id: 'two-bedroom',
268
+ name: 'Two-bedroom apartment',
269
+ description: '80 m² two-bedroom flat: 9 walls, 4 zones (living/kitchen, 2 bedrooms, bath), 4 doors and 5 windows.',
270
+ };
@@ -0,0 +1,25 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod';
3
+ import type { SceneOperations } from '../operations';
4
+ export declare const applyPatchInput: {
5
+ patches: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
6
+ op: z.ZodLiteral<"create">;
7
+ node: z.ZodRecord<z.ZodString, z.ZodUnknown>;
8
+ parentId: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strip>, z.ZodObject<{
10
+ op: z.ZodLiteral<"update">;
11
+ id: z.ZodString;
12
+ data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ op: z.ZodLiteral<"delete">;
15
+ id: z.ZodString;
16
+ cascade: z.ZodOptional<z.ZodBoolean>;
17
+ }, z.core.$strip>], "op">>;
18
+ };
19
+ export declare const applyPatchOutput: {
20
+ appliedOps: z.ZodNumber;
21
+ deletedIds: z.ZodArray<z.ZodString>;
22
+ createdIds: z.ZodArray<z.ZodString>;
23
+ };
24
+ export declare function registerApplyPatch(server: McpServer, bridge: SceneOperations): void;
25
+ //# sourceMappingURL=apply-patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-patch.d.ts","sourceRoot":"","sources":["../../src/tools/apply-patch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;CAE3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;CAI5B,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAmDnF"}
@@ -0,0 +1,59 @@
1
+ import { z } from 'zod';
2
+ import { ErrorCode, throwMcpError } from './errors';
3
+ import { publishLiveSceneSnapshot } from './live-sync';
4
+ import { PatchSchema } from './schemas';
5
+ export const applyPatchInput = {
6
+ patches: z.array(PatchSchema),
7
+ };
8
+ export const applyPatchOutput = {
9
+ appliedOps: z.number(),
10
+ deletedIds: z.array(z.string()),
11
+ createdIds: z.array(z.string()),
12
+ };
13
+ export function registerApplyPatch(server, bridge) {
14
+ server.registerTool('apply_patch', {
15
+ title: 'Apply patch',
16
+ description: 'Apply a batch of create/update/delete operations atomically. All patches are validated before any are applied; the entire batch forms a single undo step.',
17
+ inputSchema: applyPatchInput,
18
+ outputSchema: applyPatchOutput,
19
+ }, async ({ patches }) => {
20
+ const bridgePatches = patches.map((p) => {
21
+ if (p.op === 'create') {
22
+ return {
23
+ op: 'create',
24
+ node: p.node,
25
+ ...(p.parentId !== undefined ? { parentId: p.parentId } : {}),
26
+ };
27
+ }
28
+ if (p.op === 'update') {
29
+ return {
30
+ op: 'update',
31
+ id: p.id,
32
+ data: p.data,
33
+ };
34
+ }
35
+ return {
36
+ op: 'delete',
37
+ id: p.id,
38
+ ...(p.cascade !== undefined ? { cascade: p.cascade } : {}),
39
+ };
40
+ });
41
+ try {
42
+ const result = bridge.applyPatch(bridgePatches);
43
+ await publishLiveSceneSnapshot(bridge, 'apply_patch');
44
+ const payload = {
45
+ appliedOps: result.appliedOps,
46
+ deletedIds: result.deletedIds,
47
+ createdIds: result.createdIds,
48
+ };
49
+ return {
50
+ content: [{ type: 'text', text: JSON.stringify(payload) }],
51
+ structuredContent: payload,
52
+ };
53
+ }
54
+ catch (err) {
55
+ const msg = err instanceof Error ? err.message : String(err);
56
+ throwMcpError(ErrorCode.InvalidParams, msg);
57
+ }
58
+ });
59
+ }
@@ -0,0 +1,16 @@
1
+ import type { AssetInput } from '@pascal-app/core/schema';
2
+ /**
3
+ * Small built-in catalog for standalone/headless MCP use.
4
+ *
5
+ * The editor has a much larger UI catalog, but depending on `@pascal-app/editor`
6
+ * from the MCP package would pull browser/React code into the headless server.
7
+ * These entries mirror the stable IDs and asset paths used by the editor for
8
+ * common AI-generated residential layouts.
9
+ */
10
+ export declare const MCP_CATALOG_ITEMS: AssetInput[];
11
+ export declare function findCatalogItem(id: string): AssetInput | undefined;
12
+ export declare function searchCatalogItems(args: {
13
+ query: string;
14
+ category?: string | undefined;
15
+ }): AssetInput[];
16
+ //# sourceMappingURL=asset-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-catalog.d.ts","sourceRoot":"","sources":["../../src/tools/asset-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,UAAU,EA6RzC,CAAA;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAElE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,GAAG,UAAU,EAAE,CAUf"}
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Small built-in catalog for standalone/headless MCP use.
3
+ *
4
+ * The editor has a much larger UI catalog, but depending on `@pascal-app/editor`
5
+ * from the MCP package would pull browser/React code into the headless server.
6
+ * These entries mirror the stable IDs and asset paths used by the editor for
7
+ * common AI-generated residential layouts.
8
+ */
9
+ export const MCP_CATALOG_ITEMS = [
10
+ {
11
+ id: 'double-bed',
12
+ category: 'furniture',
13
+ tags: ['floor', 'bedroom'],
14
+ name: 'Double Bed',
15
+ thumbnail: '/items/double-bed/thumbnail.webp',
16
+ src: '/items/double-bed/model.glb',
17
+ dimensions: [2, 0.8, 2.5],
18
+ offset: [0, 0, -0.03],
19
+ rotation: [0, 0, 0],
20
+ scale: [1, 1, 1],
21
+ },
22
+ {
23
+ id: 'single-bed',
24
+ category: 'furniture',
25
+ tags: ['floor', 'bedroom'],
26
+ name: 'Single Bed',
27
+ thumbnail: '/items/single-bed/thumbnail.webp',
28
+ src: '/items/single-bed/model.glb',
29
+ dimensions: [1.5, 0.7, 2.5],
30
+ offset: [0, 0, 0],
31
+ rotation: [0, 0, 0],
32
+ scale: [1, 1, 1],
33
+ },
34
+ {
35
+ id: 'bedside-table',
36
+ category: 'furniture',
37
+ tags: ['floor', 'bedroom'],
38
+ name: 'Bedside Table',
39
+ thumbnail: '/items/bedside-table/thumbnail.webp',
40
+ src: '/items/bedside-table/model.glb',
41
+ dimensions: [0.5, 0.5, 0.5],
42
+ offset: [0, 0, -0.01],
43
+ rotation: [0, 0, 0],
44
+ scale: [1, 1, 1],
45
+ surface: { height: 0.5 },
46
+ },
47
+ {
48
+ id: 'dresser',
49
+ category: 'furniture',
50
+ tags: ['floor', 'storage', 'bedroom'],
51
+ name: 'Dresser',
52
+ thumbnail: '/items/dresser/thumbnail.webp',
53
+ src: '/items/dresser/model.glb',
54
+ dimensions: [1.5, 0.8, 1],
55
+ offset: [0, 0, 0],
56
+ rotation: [0, 0, 0],
57
+ scale: [1, 1, 1],
58
+ surface: { height: 0.8 },
59
+ },
60
+ {
61
+ id: 'closet',
62
+ category: 'furniture',
63
+ tags: ['floor', 'storage', 'bedroom'],
64
+ name: 'Closet',
65
+ thumbnail: '/items/closet/thumbnail.webp',
66
+ src: '/items/closet/model.glb',
67
+ dimensions: [2, 2.5, 1],
68
+ offset: [0, 0, -0.01],
69
+ rotation: [0, 0, 0],
70
+ scale: [1, 1, 1],
71
+ },
72
+ {
73
+ id: 'sofa',
74
+ category: 'furniture',
75
+ tags: ['floor', 'seating', 'living'],
76
+ name: 'Sofa',
77
+ thumbnail: '/items/sofa/thumbnail.webp',
78
+ src: '/items/sofa/model.glb',
79
+ dimensions: [2.5, 0.8, 1.5],
80
+ offset: [0, 0, 0.04],
81
+ rotation: [0, 0, 0],
82
+ scale: [1, 1, 1],
83
+ },
84
+ {
85
+ id: 'livingroom-chair',
86
+ category: 'furniture',
87
+ tags: ['floor', 'seating', 'living'],
88
+ name: 'Livingroom Chair',
89
+ thumbnail: '/items/livingroom-chair/thumbnail.webp',
90
+ src: '/items/livingroom-chair/model.glb',
91
+ dimensions: [1.5, 0.8, 1.5],
92
+ offset: [0.01, 0, 0],
93
+ rotation: [0, 0, 0],
94
+ scale: [1, 1, 1],
95
+ },
96
+ {
97
+ id: 'coffee-table',
98
+ category: 'furniture',
99
+ tags: ['floor', 'table', 'living'],
100
+ name: 'Coffee Table',
101
+ thumbnail: '/items/coffee-table/thumbnail.webp',
102
+ src: '/items/coffee-table/model.glb',
103
+ dimensions: [2, 0.4, 1.5],
104
+ offset: [0, 0, 0],
105
+ rotation: [0, 0, 0],
106
+ scale: [1, 1, 1],
107
+ surface: { height: 0.3 },
108
+ },
109
+ {
110
+ id: 'tv-stand',
111
+ category: 'furniture',
112
+ tags: ['floor', 'storage', 'living'],
113
+ name: 'TV Stand',
114
+ thumbnail: '/items/tv-stand/thumbnail.webp',
115
+ src: '/items/tv-stand/model.glb',
116
+ dimensions: [2, 0.4, 0.5],
117
+ offset: [0, 0.21, 0],
118
+ rotation: [0, 0, 0],
119
+ scale: [1, 1, 1],
120
+ surface: { height: 0.36 },
121
+ },
122
+ {
123
+ id: 'shelf',
124
+ category: 'furniture',
125
+ tags: ['wall', 'storage'],
126
+ name: 'Shelf',
127
+ thumbnail: '/items/shelf/thumbnail.webp',
128
+ src: '/items/shelf/model.glb',
129
+ dimensions: [1, 0.5, 0.7],
130
+ offset: [0, 0.1, 0.01],
131
+ rotation: [0, 0, 0],
132
+ scale: [1, 1, 1],
133
+ attachTo: 'wall-side',
134
+ surface: { height: 0.12 },
135
+ },
136
+ {
137
+ id: 'dining-table',
138
+ category: 'furniture',
139
+ tags: ['floor', 'table', 'dining'],
140
+ name: 'Dining Table',
141
+ thumbnail: '/items/dining-table/thumbnail.webp',
142
+ src: '/items/dining-table/model.glb',
143
+ dimensions: [2.5, 0.8, 1],
144
+ offset: [0, 0, -0.01],
145
+ rotation: [0, 0, 0],
146
+ scale: [1, 1, 1],
147
+ surface: { height: 0.8 },
148
+ },
149
+ {
150
+ id: 'dining-chair',
151
+ category: 'furniture',
152
+ tags: ['floor', 'seating', 'dining'],
153
+ name: 'Dining Chair',
154
+ thumbnail: '/items/dining-chair/thumbnail.webp',
155
+ src: '/items/dining-chair/model.glb',
156
+ dimensions: [0.5, 1, 0.5],
157
+ offset: [0, 0, 0],
158
+ rotation: [0, 0, 0],
159
+ scale: [1, 1, 1],
160
+ },
161
+ {
162
+ id: 'kitchen',
163
+ category: 'kitchen',
164
+ tags: ['floor', 'large', 'kitchen'],
165
+ name: 'Kitchen',
166
+ thumbnail: '/items/kitchen/thumbnail.webp',
167
+ src: '/items/kitchen/model.glb',
168
+ dimensions: [2.5, 1.1, 1],
169
+ offset: [0, 0, 0],
170
+ rotation: [0, 0, 0],
171
+ scale: [1, 1, 1],
172
+ },
173
+ {
174
+ id: 'kitchen-counter',
175
+ category: 'kitchen',
176
+ tags: ['floor', 'large', 'storage', 'kitchen'],
177
+ name: 'Kitchen Counter',
178
+ thumbnail: '/items/kitchen-counter/thumbnail.webp',
179
+ src: '/items/kitchen-counter/model.glb',
180
+ dimensions: [2, 0.8, 1],
181
+ offset: [0, 0, 0],
182
+ rotation: [0, 0, 0],
183
+ scale: [1, 1, 1],
184
+ surface: { height: 0.75 },
185
+ },
186
+ {
187
+ id: 'stove',
188
+ category: 'kitchen',
189
+ tags: ['floor', 'large', 'kitchen'],
190
+ name: 'Stove',
191
+ thumbnail: '/items/stove/thumbnail.webp',
192
+ src: '/items/stove/model.glb',
193
+ dimensions: [1, 1, 1],
194
+ offset: [0, 0, -0.05],
195
+ rotation: [0, 0, 0],
196
+ scale: [1, 1, 1],
197
+ },
198
+ {
199
+ id: 'fridge',
200
+ category: 'kitchen',
201
+ tags: ['floor', 'large', 'kitchen'],
202
+ name: 'Fridge',
203
+ thumbnail: '/items/fridge/thumbnail.webp',
204
+ src: '/items/fridge/model.glb',
205
+ dimensions: [1, 2, 1],
206
+ offset: [0.01, 0, -0.05],
207
+ rotation: [0, 0, 0],
208
+ scale: [1, 1, 1],
209
+ },
210
+ {
211
+ id: 'toilet',
212
+ category: 'bathroom',
213
+ tags: ['floor', 'large', 'bathroom'],
214
+ name: 'Toilet',
215
+ thumbnail: '/items/toilet/thumbnail.webp',
216
+ src: '/items/toilet/model.glb',
217
+ dimensions: [1, 0.9, 1],
218
+ offset: [0, 0, -0.23],
219
+ rotation: [0, 0, 0],
220
+ scale: [1, 1, 1],
221
+ },
222
+ {
223
+ id: 'bathroom-sink',
224
+ category: 'bathroom',
225
+ tags: ['floor', 'large', 'bathroom'],
226
+ name: 'Bathroom Sink',
227
+ thumbnail: '/items/bathroom-sink/thumbnail.webp',
228
+ src: '/items/bathroom-sink/model.glb',
229
+ dimensions: [2, 1, 1.5],
230
+ offset: [0.11, 0, 0.02],
231
+ rotation: [0, 0, 0],
232
+ scale: [1, 1, 1],
233
+ },
234
+ {
235
+ id: 'shower-square',
236
+ category: 'bathroom',
237
+ tags: ['floor', 'large', 'bathroom'],
238
+ name: 'Squared Shower',
239
+ thumbnail: '/items/shower-square/thumbnail.webp',
240
+ src: '/items/shower-square/model.glb',
241
+ dimensions: [1, 2, 1],
242
+ offset: [0.41, 0, -0.42],
243
+ rotation: [0, 0, 0],
244
+ scale: [1, 1, 1],
245
+ },
246
+ {
247
+ id: 'bathtub',
248
+ category: 'bathroom',
249
+ tags: ['floor', 'large', 'bathroom'],
250
+ name: 'Bathtub',
251
+ thumbnail: '/items/bathtub/thumbnail.webp',
252
+ src: '/items/bathtub/model.glb',
253
+ dimensions: [2.5, 0.8, 1.5],
254
+ offset: [0, 0, 0.01],
255
+ rotation: [0, 0, 0],
256
+ scale: [1, 1, 1],
257
+ },
258
+ {
259
+ id: 'washing-machine',
260
+ category: 'bathroom',
261
+ tags: ['floor', 'large', 'electronics', 'laundry'],
262
+ name: 'Washing Machine',
263
+ thumbnail: '/items/washing-machine/thumbnail.webp',
264
+ src: '/items/washing-machine/model.glb',
265
+ dimensions: [1, 1, 1],
266
+ offset: [0, 0, 0],
267
+ rotation: [0, 0, 0],
268
+ scale: [1, 1, 1],
269
+ },
270
+ {
271
+ id: 'drying-rack',
272
+ category: 'bathroom',
273
+ tags: ['floor', 'laundry'],
274
+ name: 'Drying Rack',
275
+ thumbnail: '/items/drying-rack/thumbnail.webp',
276
+ src: '/items/drying-rack/model.glb',
277
+ dimensions: [2, 1.1, 1],
278
+ offset: [0, 0, 0],
279
+ rotation: [0, 0, 0],
280
+ scale: [1, 1, 1],
281
+ },
282
+ {
283
+ id: 'coat-rack',
284
+ category: 'furniture',
285
+ tags: ['floor', 'storage', 'entry'],
286
+ name: 'Coat Rack',
287
+ thumbnail: '/items/coat-rack/thumbnail.webp',
288
+ src: '/items/coat-rack/model.glb',
289
+ dimensions: [0.5, 1.8, 0.5],
290
+ offset: [0, 0, 0],
291
+ rotation: [0, 0, 0],
292
+ scale: [1, 1, 1],
293
+ },
294
+ ];
295
+ export function findCatalogItem(id) {
296
+ return MCP_CATALOG_ITEMS.find((item) => item.id === id);
297
+ }
298
+ export function searchCatalogItems(args) {
299
+ const terms = args.query.trim().toLowerCase().split(/\s+/).filter(Boolean);
300
+ return MCP_CATALOG_ITEMS.filter((item) => {
301
+ if (args.category && item.category !== args.category)
302
+ return false;
303
+ const haystack = [item.id, item.name, item.category, ...(item.tags ?? [])]
304
+ .join(' ')
305
+ .toLowerCase();
306
+ return terms.every((term) => haystack.includes(term));
307
+ });
308
+ }