@pascal-app/mcp 1.0.0-beta.6 → 1.0.1

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 (193) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1 -1
  4. package/dist/bin/pascal-mcp.d.ts +1 -1
  5. package/dist/bin/pascal-mcp.js +7 -7
  6. package/dist/bridge/index.d.ts +2 -2
  7. package/dist/bridge/index.js +1 -1
  8. package/dist/bridge/scene-bridge.d.ts +2 -2
  9. package/dist/bridge/scene-bridge.d.ts.map +1 -1
  10. package/dist/bridge/scene-bridge.js +3 -3
  11. package/dist/index.d.ts +4 -4
  12. package/dist/index.js +4 -4
  13. package/dist/operations/index.d.ts +1 -1
  14. package/dist/operations/index.js +1 -1
  15. package/dist/operations/scene-operations.d.ts +2 -2
  16. package/dist/prompts/from-brief.d.ts +1 -1
  17. package/dist/prompts/from-brief.d.ts.map +1 -1
  18. package/dist/prompts/from-brief.js +2 -1
  19. package/dist/prompts/index.d.ts +1 -1
  20. package/dist/prompts/index.js +3 -3
  21. package/dist/prompts/iterate-on-feedback.d.ts +1 -1
  22. package/dist/prompts/iterate-on-feedback.js +1 -1
  23. package/dist/prompts/renovation-from-photos.d.ts +1 -1
  24. package/dist/resources/agent-guide.d.ts +1 -1
  25. package/dist/resources/agent-guide.d.ts.map +1 -1
  26. package/dist/resources/agent-guide.js +1 -0
  27. package/dist/resources/catalog-items.d.ts +1 -1
  28. package/dist/resources/catalog-items.js +1 -1
  29. package/dist/resources/constraints.d.ts +1 -1
  30. package/dist/resources/index.d.ts +1 -1
  31. package/dist/resources/index.js +5 -5
  32. package/dist/resources/scene-current.d.ts +1 -1
  33. package/dist/resources/scene-summary.d.ts +1 -1
  34. package/dist/server.d.ts +14 -3
  35. package/dist/server.d.ts.map +1 -1
  36. package/dist/server.js +60 -6
  37. package/dist/storage/index.d.ts +4 -4
  38. package/dist/storage/index.js +4 -4
  39. package/dist/storage/sqlite-scene-store.d.ts +1 -1
  40. package/dist/storage/sqlite-scene-store.js +3 -3
  41. package/dist/templates/index.js +3 -3
  42. package/dist/tools/annotations.d.ts +28 -0
  43. package/dist/tools/annotations.d.ts.map +1 -0
  44. package/dist/tools/annotations.js +27 -0
  45. package/dist/tools/apply-patch.d.ts +8 -1
  46. package/dist/tools/apply-patch.d.ts.map +1 -1
  47. package/dist/tools/apply-patch.js +9 -5
  48. package/dist/tools/check-collisions.d.ts +60 -1
  49. package/dist/tools/check-collisions.d.ts.map +1 -1
  50. package/dist/tools/check-collisions.js +242 -21
  51. package/dist/tools/construction-tools.d.ts +24 -2
  52. package/dist/tools/construction-tools.d.ts.map +1 -1
  53. package/dist/tools/construction-tools.js +36 -10
  54. package/dist/tools/create-level.d.ts +8 -1
  55. package/dist/tools/create-level.d.ts.map +1 -1
  56. package/dist/tools/create-level.js +9 -6
  57. package/dist/tools/create-unit.d.ts +27 -0
  58. package/dist/tools/create-unit.d.ts.map +1 -0
  59. package/dist/tools/create-unit.js +36 -0
  60. package/dist/tools/create-wall.d.ts +8 -1
  61. package/dist/tools/create-wall.d.ts.map +1 -1
  62. package/dist/tools/create-wall.js +9 -6
  63. package/dist/tools/cut-opening.d.ts +8 -1
  64. package/dist/tools/cut-opening.d.ts.map +1 -1
  65. package/dist/tools/cut-opening.js +10 -7
  66. package/dist/tools/delete-node.d.ts +8 -1
  67. package/dist/tools/delete-node.d.ts.map +1 -1
  68. package/dist/tools/delete-node.js +8 -5
  69. package/dist/tools/describe-node.d.ts +1 -1
  70. package/dist/tools/describe-node.d.ts.map +1 -1
  71. package/dist/tools/describe-node.js +5 -3
  72. package/dist/tools/door-clearance.d.ts +19 -3
  73. package/dist/tools/door-clearance.d.ts.map +1 -1
  74. package/dist/tools/door-clearance.js +102 -8
  75. package/dist/tools/duplicate-level.d.ts +8 -1
  76. package/dist/tools/duplicate-level.d.ts.map +1 -1
  77. package/dist/tools/duplicate-level.js +8 -4
  78. package/dist/tools/export-glb.d.ts +1 -1
  79. package/dist/tools/export-glb.d.ts.map +1 -1
  80. package/dist/tools/export-glb.js +4 -2
  81. package/dist/tools/export-json.d.ts +1 -1
  82. package/dist/tools/export-json.d.ts.map +1 -1
  83. package/dist/tools/export-json.js +2 -0
  84. package/dist/tools/find-nodes.d.ts +1 -1
  85. package/dist/tools/find-nodes.d.ts.map +1 -1
  86. package/dist/tools/find-nodes.js +3 -1
  87. package/dist/tools/get-node.d.ts +1 -1
  88. package/dist/tools/get-node.d.ts.map +1 -1
  89. package/dist/tools/get-node.js +4 -2
  90. package/dist/tools/get-scene.d.ts +1 -1
  91. package/dist/tools/get-scene.d.ts.map +1 -1
  92. package/dist/tools/get-scene.js +2 -0
  93. package/dist/tools/index.d.ts +1 -1
  94. package/dist/tools/index.d.ts.map +1 -1
  95. package/dist/tools/index.js +32 -26
  96. package/dist/tools/layout-clearance.d.ts +4 -2
  97. package/dist/tools/layout-clearance.d.ts.map +1 -1
  98. package/dist/tools/layout-clearance.js +7 -3
  99. package/dist/tools/list-units.d.ts +38 -0
  100. package/dist/tools/list-units.d.ts.map +1 -0
  101. package/dist/tools/list-units.js +61 -0
  102. package/dist/tools/live-sync.d.ts +34 -4
  103. package/dist/tools/live-sync.d.ts.map +1 -1
  104. package/dist/tools/live-sync.js +38 -6
  105. package/dist/tools/measure.d.ts +2 -1
  106. package/dist/tools/measure.d.ts.map +1 -1
  107. package/dist/tools/measure.js +6 -2
  108. package/dist/tools/normalize-schema-dialect.d.ts +3 -0
  109. package/dist/tools/normalize-schema-dialect.d.ts.map +1 -0
  110. package/dist/tools/normalize-schema-dialect.js +28 -0
  111. package/dist/tools/photo-to-scene/index.d.ts +2 -2
  112. package/dist/tools/photo-to-scene/index.js +2 -2
  113. package/dist/tools/photo-to-scene/photo-to-scene.d.ts +1 -1
  114. package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
  115. package/dist/tools/photo-to-scene/photo-to-scene.js +5 -3
  116. package/dist/tools/place-item.d.ts +8 -1
  117. package/dist/tools/place-item.d.ts.map +1 -1
  118. package/dist/tools/place-item.js +11 -7
  119. package/dist/tools/redo.d.ts +8 -1
  120. package/dist/tools/redo.d.ts.map +1 -1
  121. package/dist/tools/redo.js +6 -4
  122. package/dist/tools/room-tools.d.ts +29 -1
  123. package/dist/tools/room-tools.d.ts.map +1 -1
  124. package/dist/tools/room-tools.js +27 -12
  125. package/dist/tools/scene-lifecycle/create-project.d.ts +1 -1
  126. package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -1
  127. package/dist/tools/scene-lifecycle/create-project.js +4 -2
  128. package/dist/tools/scene-lifecycle/delete-scene.d.ts +1 -1
  129. package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
  130. package/dist/tools/scene-lifecycle/delete-scene.js +4 -2
  131. package/dist/tools/scene-lifecycle/get-project-status.d.ts +1 -1
  132. package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -1
  133. package/dist/tools/scene-lifecycle/get-project-status.js +4 -2
  134. package/dist/tools/scene-lifecycle/index.d.ts +8 -8
  135. package/dist/tools/scene-lifecycle/index.js +14 -14
  136. package/dist/tools/scene-lifecycle/list-scenes.d.ts +1 -1
  137. package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -1
  138. package/dist/tools/scene-lifecycle/list-scenes.js +3 -1
  139. package/dist/tools/scene-lifecycle/load-scene.d.ts +1 -1
  140. package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -1
  141. package/dist/tools/scene-lifecycle/load-scene.js +4 -2
  142. package/dist/tools/scene-lifecycle/metadata.d.ts +3 -3
  143. package/dist/tools/scene-lifecycle/rename-scene.d.ts +1 -1
  144. package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -1
  145. package/dist/tools/scene-lifecycle/rename-scene.js +4 -2
  146. package/dist/tools/scene-lifecycle/save-scene.d.ts +1 -1
  147. package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
  148. package/dist/tools/scene-lifecycle/save-scene.js +6 -4
  149. package/dist/tools/scene-lifecycle/test-utils.d.ts +7 -3
  150. package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -1
  151. package/dist/tools/scene-lifecycle/test-utils.js +28 -4
  152. package/dist/tools/scene-query.d.ts +1 -1
  153. package/dist/tools/scene-query.d.ts.map +1 -1
  154. package/dist/tools/scene-query.js +9 -3
  155. package/dist/tools/set-unit-members.d.ts +20 -0
  156. package/dist/tools/set-unit-members.d.ts.map +1 -0
  157. package/dist/tools/set-unit-members.js +43 -0
  158. package/dist/tools/set-zone.d.ts +8 -1
  159. package/dist/tools/set-zone.d.ts.map +1 -1
  160. package/dist/tools/set-zone.js +8 -5
  161. package/dist/tools/templates/create-from-template.d.ts +1 -1
  162. package/dist/tools/templates/create-from-template.d.ts.map +1 -1
  163. package/dist/tools/templates/create-from-template.js +7 -5
  164. package/dist/tools/templates/create-house-from-brief.d.ts +1 -1
  165. package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -1
  166. package/dist/tools/templates/create-house-from-brief.js +7 -5
  167. package/dist/tools/templates/index.d.ts +4 -4
  168. package/dist/tools/templates/index.js +6 -6
  169. package/dist/tools/templates/list-templates.d.ts.map +1 -1
  170. package/dist/tools/templates/list-templates.js +3 -1
  171. package/dist/tools/undo.d.ts +8 -1
  172. package/dist/tools/undo.d.ts.map +1 -1
  173. package/dist/tools/undo.js +6 -4
  174. package/dist/tools/unit-members.d.ts +4 -0
  175. package/dist/tools/unit-members.d.ts.map +1 -0
  176. package/dist/tools/unit-members.js +24 -0
  177. package/dist/tools/validate-scene.d.ts +1 -1
  178. package/dist/tools/validate-scene.d.ts.map +1 -1
  179. package/dist/tools/validate-scene.js +2 -0
  180. package/dist/tools/variants/generate-variants.d.ts +1 -1
  181. package/dist/tools/variants/generate-variants.d.ts.map +1 -1
  182. package/dist/tools/variants/generate-variants.js +4 -2
  183. package/dist/tools/variants/index.d.ts +3 -3
  184. package/dist/tools/variants/index.js +3 -3
  185. package/dist/tools/vision/analyze-floorplan-image.d.ts +1 -1
  186. package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -1
  187. package/dist/tools/vision/analyze-floorplan-image.js +3 -1
  188. package/dist/tools/vision/analyze-room-photo.d.ts +1 -1
  189. package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -1
  190. package/dist/tools/vision/analyze-room-photo.js +3 -1
  191. package/dist/tools/vision/index.d.ts +3 -3
  192. package/dist/tools/vision/index.js +4 -4
  193. package/package.json +8 -7
@@ -1,7 +1,8 @@
1
1
  import { z } from 'zod';
2
- import { ErrorCode, throwMcpError } from './errors';
3
- import { publishLiveSceneSnapshot } from './live-sync';
4
- import { PatchSchema } from './schemas';
2
+ import { DESTRUCTIVE_TOOL_ANNOTATIONS } from './annotations.js';
3
+ import { ErrorCode, throwMcpError } from './errors.js';
4
+ import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
5
+ import { PatchSchema } from './schemas.js';
5
6
  export const applyPatchInput = {
6
7
  patches: z.array(PatchSchema),
7
8
  };
@@ -9,13 +10,15 @@ export const applyPatchOutput = {
9
10
  appliedOps: z.number(),
10
11
  deletedIds: z.array(z.string()),
11
12
  createdIds: z.array(z.string()),
13
+ ...liveSyncOutput,
12
14
  };
13
15
  export function registerApplyPatch(server, bridge) {
14
16
  server.registerTool('apply_patch', {
15
17
  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.',
18
+ 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. Batch-first is the default: prefer one apply_patch call containing all create/update/delete ops for a build step, in stable order so later ops can reference ids created by earlier ops. A single call is atomic (all or nothing) and pays the snapshot and save cost once; do not loop one-op calls.',
17
19
  inputSchema: applyPatchInput,
18
20
  outputSchema: applyPatchOutput,
21
+ annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
19
22
  }, async ({ patches }) => {
20
23
  const bridgePatches = patches.map((p) => {
21
24
  if (p.op === 'create') {
@@ -40,11 +43,12 @@ export function registerApplyPatch(server, bridge) {
40
43
  });
41
44
  try {
42
45
  const result = bridge.applyPatch(bridgePatches);
43
- await publishLiveSceneSnapshot(bridge, 'apply_patch');
46
+ const persistence = await publishLiveSceneSnapshot(bridge, 'apply_patch');
44
47
  const payload = {
45
48
  appliedOps: result.appliedOps,
46
49
  deletedIds: result.deletedIds,
47
50
  createdIds: result.createdIds,
51
+ ...persistencePayload(persistence),
48
52
  };
49
53
  return {
50
54
  content: [{ type: 'text', text: JSON.stringify(payload) }],
@@ -1,14 +1,73 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { z } from 'zod';
3
- import type { SceneOperations } from '../operations';
3
+ import type { SceneOperations } from '../operations/index.js';
4
4
  export declare const checkCollisionsInput: {
5
5
  levelId: z.ZodOptional<z.ZodString>;
6
+ minimumClearance: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
7
+ floorOnly: z.ZodDefault<z.ZodBoolean>;
8
+ candidate: z.ZodOptional<z.ZodObject<{
9
+ id: z.ZodDefault<z.ZodString>;
10
+ name: z.ZodDefault<z.ZodString>;
11
+ levelId: z.ZodString;
12
+ position: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>, z.ZodTransform<[number, number, number], number[]>>;
13
+ dimensions: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>, z.ZodTransform<[number, number, number], number[]>>;
14
+ rotationY: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
15
+ source: z.ZodOptional<z.ZodObject<{
16
+ assetId: z.ZodOptional<z.ZodString>;
17
+ uri: z.ZodOptional<z.ZodString>;
18
+ }, z.core.$strip>>;
19
+ }, z.core.$strip>>;
6
20
  };
7
21
  export declare const checkCollisionsOutput: {
22
+ status: z.ZodEnum<{
23
+ checked: "checked";
24
+ partial: "partial";
25
+ insufficient_evidence: "insufficient_evidence";
26
+ }>;
27
+ units: z.ZodLiteral<"meters">;
28
+ method: z.ZodLiteral<"rotation-aware-plan-aabb">;
29
+ assessmentGraphHash: z.ZodString;
30
+ minimumClearanceMeters: z.ZodNumber;
31
+ floorOnly: z.ZodBoolean;
32
+ candidateItemId: z.ZodNullable<z.ZodString>;
33
+ checkedItems: z.ZodArray<z.ZodObject<{
34
+ id: z.ZodString;
35
+ name: z.ZodString;
36
+ levelId: z.ZodNullable<z.ZodString>;
37
+ positionMeters: z.ZodArray<z.ZodNumber>;
38
+ rotationYRadians: z.ZodNumber;
39
+ source: z.ZodObject<{
40
+ assetId: z.ZodString;
41
+ uri: z.ZodString;
42
+ catalog: z.ZodString;
43
+ }, z.core.$strip>;
44
+ sourceDimensionsMeters: z.ZodArray<z.ZodNumber>;
45
+ effectiveDimensionsMeters: z.ZodArray<z.ZodNumber>;
46
+ footprintBoundsMeters: z.ZodObject<{
47
+ minX: z.ZodNumber;
48
+ maxX: z.ZodNumber;
49
+ minZ: z.ZodNumber;
50
+ maxZ: z.ZodNumber;
51
+ }, z.core.$strip>;
52
+ }, z.core.$strip>>;
53
+ skippedItems: z.ZodArray<z.ZodObject<{
54
+ id: z.ZodString;
55
+ name: z.ZodString;
56
+ reason: z.ZodString;
57
+ }, z.core.$strip>>;
58
+ unsupportedChecks: z.ZodArray<z.ZodObject<{
59
+ check: z.ZodString;
60
+ reason: z.ZodString;
61
+ }, z.core.$strip>>;
8
62
  collisions: z.ZodArray<z.ZodObject<{
9
63
  aId: z.ZodString;
10
64
  bId: z.ZodString;
11
65
  kind: z.ZodString;
66
+ violation: z.ZodEnum<{
67
+ overlap: "overlap";
68
+ clearance: "clearance";
69
+ }>;
70
+ minimumClearanceMeters: z.ZodNumber;
12
71
  }, z.core.$strip>>;
13
72
  };
14
73
  export declare function registerCheckCollisions(server: McpServer, bridge: SceneOperations): void;
@@ -1 +1 @@
1
- {"version":3,"file":"check-collisions.d.ts","sourceRoot":"","sources":["../../src/tools/check-collisions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAIpD,eAAO,MAAM,oBAAoB;;CAEhC,CAAA;AAED,eAAO,MAAM,qBAAqB;;;;;;CAQjC,CAAA;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA4CxF"}
1
+ {"version":3,"file":"check-collisions.d.ts","sourceRoot":"","sources":["../../src/tools/check-collisions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AA8BpD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;CA+BhC,CAAA;AAED,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDjC,CAAA;AA6BD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAyKxF"}
@@ -1,46 +1,267 @@
1
+ import { ItemNode } from '@pascal-app/core/schema';
1
2
  import { z } from 'zod';
2
- import { findItemItemCollisions } from './layout-clearance';
3
- import { NodeIdSchema } from './schemas';
3
+ import { READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
4
+ import { inspectItemPlanFootprint, resolveNodeLevelId } from './door-clearance.js';
5
+ import { ErrorCode, throwMcpError } from './errors.js';
6
+ import { findItemItemCollisions } from './layout-clearance.js';
7
+ import { measurement } from './measurement.js';
8
+ import { computeGraphHash } from './scene-lifecycle/metadata.js';
9
+ import { NodeIdSchema } from './schemas.js';
10
+ const candidatePosition = measurement('length', 'm', {
11
+ description: 'Candidate position coordinate.',
12
+ });
13
+ const candidateDimension = measurement('length', 'm', {
14
+ positive: true,
15
+ description: 'Candidate declared size.',
16
+ });
17
+ const vector3 = (component) => z
18
+ .array(component)
19
+ .length(3)
20
+ .transform((values, ctx) => {
21
+ const [x, y, zValue] = values;
22
+ if (x === undefined || y === undefined || zValue === undefined) {
23
+ ctx.addIssue({ code: 'custom', message: 'Expected exactly three values.' });
24
+ return z.NEVER;
25
+ }
26
+ return [x, y, zValue];
27
+ });
28
+ const outputVector3 = z.array(z.number()).length(3);
4
29
  export const checkCollisionsInput = {
5
30
  levelId: NodeIdSchema.optional(),
31
+ minimumClearance: measurement('length', 'm', {
32
+ min: 0,
33
+ description: 'Minimum free plan-space required between item footprints.',
34
+ }).default(0),
35
+ floorOnly: z
36
+ .boolean()
37
+ .default(false)
38
+ .describe('When true, wall-, wall-side-, and ceiling-attached items are excluded.'),
39
+ candidate: z
40
+ .object({
41
+ id: z.string().min(1).max(120).default('candidate'),
42
+ name: z.string().min(1).max(200).default('Candidate item'),
43
+ levelId: NodeIdSchema,
44
+ position: vector3(candidatePosition),
45
+ dimensions: vector3(candidateDimension),
46
+ rotationY: measurement('angle', 'rad', {
47
+ description: 'Candidate yaw around the vertical axis.',
48
+ }).default(0),
49
+ source: z
50
+ .object({
51
+ assetId: z.string().min(1).optional(),
52
+ uri: z.string().min(1).optional(),
53
+ })
54
+ .optional(),
55
+ })
56
+ .optional()
57
+ .describe('Read-only prospective furniture item. It is checked against the target level but never added to the scene.'),
6
58
  };
7
59
  export const checkCollisionsOutput = {
60
+ status: z.enum(['checked', 'partial', 'insufficient_evidence']),
61
+ units: z.literal('meters'),
62
+ method: z.literal('rotation-aware-plan-aabb'),
63
+ assessmentGraphHash: z.string(),
64
+ minimumClearanceMeters: z.number(),
65
+ floorOnly: z.boolean(),
66
+ candidateItemId: z.string().nullable(),
67
+ checkedItems: z.array(z.object({
68
+ id: z.string(),
69
+ name: z.string(),
70
+ levelId: z.string().nullable(),
71
+ positionMeters: outputVector3,
72
+ rotationYRadians: z.number(),
73
+ source: z.object({
74
+ assetId: z.string(),
75
+ uri: z.string(),
76
+ catalog: z.string(),
77
+ }),
78
+ sourceDimensionsMeters: outputVector3,
79
+ effectiveDimensionsMeters: outputVector3,
80
+ footprintBoundsMeters: z.object({
81
+ minX: z.number(),
82
+ maxX: z.number(),
83
+ minZ: z.number(),
84
+ maxZ: z.number(),
85
+ }),
86
+ })),
87
+ skippedItems: z.array(z.object({
88
+ id: z.string(),
89
+ name: z.string(),
90
+ reason: z.string(),
91
+ })),
92
+ unsupportedChecks: z.array(z.object({
93
+ check: z.string(),
94
+ reason: z.string(),
95
+ })),
8
96
  collisions: z.array(z.object({
9
97
  aId: z.string(),
10
98
  bId: z.string(),
11
99
  kind: z.string(),
100
+ violation: z.enum(['overlap', 'clearance']),
101
+ minimumClearanceMeters: z.number(),
12
102
  })),
13
103
  };
104
+ const unsupportedChecks = [
105
+ {
106
+ check: 'vertical_clearance',
107
+ reason: 'This check uses the X/Z plan footprint only and does not prove height clearance.',
108
+ },
109
+ {
110
+ check: 'room_boundary_clearance',
111
+ reason: 'The tool compares items with other items and does not prove containment in a room.',
112
+ },
113
+ {
114
+ check: 'door_swing_envelope',
115
+ reason: 'Door swing geometry is not evaluated by check_collisions.',
116
+ },
117
+ {
118
+ check: 'delivery_path',
119
+ reason: 'No route, turning-radius, stair, or opening traversal is evaluated.',
120
+ },
121
+ {
122
+ check: 'mesh_geometry',
123
+ reason: 'Asset meshes are not loaded; the check uses declared rectangular dimensions.',
124
+ },
125
+ {
126
+ check: 'hosted_item_world_transform',
127
+ reason: 'Items positioned in a non-level parent frame are skipped instead of approximated.',
128
+ },
129
+ ];
14
130
  export function registerCheckCollisions(server, bridge) {
15
131
  server.registerTool('check_collisions', {
16
132
  title: 'Check collisions',
17
- description: 'Detect overlapping item footprints via a rotation-aware plan AABB test. Optionally scoped to a single level (items parented to that level).',
133
+ description: 'Assess declared item footprints with a rotation-aware plan AABB test. Supports an explicit minimum clearance and reports units, source dimensions, skipped evidence, and unsupported checks. Optionally scope to one level or floor-standing items.',
18
134
  inputSchema: checkCollisionsInput,
19
135
  outputSchema: checkCollisionsOutput,
20
- }, async ({ levelId }) => {
21
- const nodes = Object.values(bridge.getNodes());
22
- let scoped = nodes;
23
- if (levelId) {
24
- const levelItems = new Set(bridge
25
- .findNodes({ type: 'item', levelId: levelId })
26
- .map((n) => n.id));
27
- scoped = nodes.filter((n) => n.type !== 'item' || levelItems.has(n.id));
136
+ annotations: READ_ONLY_TOOL_ANNOTATIONS,
137
+ }, async ({ levelId, minimumClearance, floorOnly, candidate }) => {
138
+ const sceneNodes = Object.values(bridge.getNodes());
139
+ if (candidate && levelId && candidate.levelId !== levelId) {
140
+ throwMcpError(ErrorCode.InvalidParams, 'candidate.levelId must match levelId when both are provided');
141
+ }
142
+ const scopeLevelId = candidate?.levelId ?? levelId;
143
+ if (scopeLevelId) {
144
+ const target = sceneNodes.find((node) => node.id === scopeLevelId);
145
+ if (target?.type !== 'level') {
146
+ throwMcpError(ErrorCode.InvalidParams, `Level not found: ${scopeLevelId}`);
147
+ }
28
148
  }
29
- // gap: 0 keeps this tool's contract — it reports *actual* overlap.
30
- // findItemItemCollisions defaults to DEFAULT_ITEM_GAP (8cm), which is the
31
- // breathing room furnish_room wants when placing new items; applied here
32
- // it would report items merely standing close together as colliding.
149
+ if (candidate) {
150
+ if (sceneNodes.some((node) => node.id === candidate.id)) {
151
+ throwMcpError(ErrorCode.InvalidParams, `Candidate id already exists: ${candidate.id}`);
152
+ }
153
+ }
154
+ const candidateNode = candidate
155
+ ? ItemNode.parse({
156
+ object: 'node',
157
+ type: 'item',
158
+ parentId: candidate.levelId,
159
+ visible: true,
160
+ metadata: {},
161
+ name: candidate.name,
162
+ position: candidate.position,
163
+ rotation: [0, candidate.rotationY, 0],
164
+ scale: [1, 1, 1],
165
+ children: [],
166
+ asset: {
167
+ id: candidate.source?.assetId ?? 'supplied-dimensions',
168
+ name: candidate.name,
169
+ category: 'furniture',
170
+ thumbnail: '',
171
+ source: 'library',
172
+ src: 'asset://supplied-dimensions',
173
+ dimensions: candidate.dimensions,
174
+ offset: [0, 0, 0],
175
+ rotation: [0, 0, 0],
176
+ scale: [1, 1, 1],
177
+ },
178
+ })
179
+ : null;
180
+ const nodes = candidateNode ? [...sceneNodes, candidateNode] : sceneNodes;
181
+ const byId = new Map(nodes.map((node) => [node.id, node]));
182
+ const scoped = nodes.filter((node) => {
183
+ if (node.type !== 'item' || !scopeLevelId)
184
+ return true;
185
+ return resolveNodeLevelId(node.id, byId) === scopeLevelId;
186
+ });
187
+ const checkedItems = [];
188
+ const skippedItems = [];
189
+ for (const node of scoped) {
190
+ if (node.type !== 'item')
191
+ continue;
192
+ const resolvedLevelId = node === candidateNode ? candidate.levelId : bridge.resolveLevelId(node.id);
193
+ if (!resolvedLevelId) {
194
+ skippedItems.push({
195
+ id: node.id,
196
+ name: node.name ?? node.asset.name ?? node.id,
197
+ reason: 'unresolved_level',
198
+ });
199
+ continue;
200
+ }
201
+ const immediateParent = node === candidateNode ? byId.get(candidate.levelId) : bridge.getAncestry(node.id)[1];
202
+ if (immediateParent && immediateParent.type !== 'level') {
203
+ skippedItems.push({
204
+ id: node.id,
205
+ name: node.name ?? node.asset.name ?? node.id,
206
+ reason: floorOnly ? 'unsupported_attachment' : 'parent_local_coordinates',
207
+ });
208
+ continue;
209
+ }
210
+ const inspected = inspectItemPlanFootprint(node, { floorOnly });
211
+ const name = node.name ?? node.asset.name ?? node.id;
212
+ if (!inspected.ok) {
213
+ skippedItems.push({ id: node.id, name, reason: inspected.reason });
214
+ continue;
215
+ }
216
+ checkedItems.push({
217
+ id: node === candidateNode ? candidate.id : node.id,
218
+ name,
219
+ levelId: resolvedLevelId,
220
+ positionMeters: node.position,
221
+ rotationYRadians: inspected.rotationY,
222
+ source: {
223
+ assetId: node === candidateNode
224
+ ? (candidate.source?.assetId ?? 'supplied-dimensions')
225
+ : node.asset.id,
226
+ uri: node === candidateNode
227
+ ? (candidate.source?.uri ?? 'supplied://dimensions')
228
+ : node.asset.src,
229
+ catalog: node === candidateNode ? 'supplied' : (node.asset.source ?? 'unknown'),
230
+ },
231
+ sourceDimensionsMeters: inspected.sourceDimensions,
232
+ effectiveDimensionsMeters: inspected.effectiveDimensions,
233
+ footprintBoundsMeters: inspected.aabb,
234
+ });
235
+ }
236
+ const checkedItemIds = new Set(checkedItems.map((item) => (item.id === candidate?.id ? candidateNode.id : item.id)));
33
237
  const found = findItemItemCollisions({
34
- nodes: scoped,
35
- levelId: levelId,
36
- gap: 0,
238
+ nodes: scoped.filter((node) => (node.type === 'item' ? checkedItemIds.has(node.id) : true)),
239
+ gap: minimumClearance,
37
240
  });
38
241
  const collisions = found.map((c) => ({
39
- aId: c.aId,
40
- bId: c.bId,
242
+ aId: c.aId === candidateNode?.id ? candidate.id : c.aId,
243
+ bId: c.bId === candidateNode?.id ? candidate.id : c.bId,
41
244
  kind: c.kind,
245
+ violation: c.violation,
246
+ minimumClearanceMeters: c.minimumClearanceMeters,
42
247
  }));
43
- const payload = { collisions };
248
+ const payload = {
249
+ status: checkedItems.length === 0 && skippedItems.length > 0
250
+ ? 'insufficient_evidence'
251
+ : skippedItems.length > 0
252
+ ? 'partial'
253
+ : 'checked',
254
+ units: 'meters',
255
+ method: 'rotation-aware-plan-aabb',
256
+ assessmentGraphHash: computeGraphHash(bridge.exportJSON()),
257
+ minimumClearanceMeters: minimumClearance,
258
+ floorOnly,
259
+ candidateItemId: candidate?.id ?? null,
260
+ checkedItems,
261
+ skippedItems,
262
+ unsupportedChecks: [...unsupportedChecks],
263
+ collisions,
264
+ };
44
265
  return {
45
266
  content: [{ type: 'text', text: JSON.stringify(payload) }],
46
267
  structuredContent: payload,
@@ -1,6 +1,6 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { z } from 'zod';
3
- import type { SceneOperations } from '../operations';
3
+ import type { SceneOperations } from '../operations/index.js';
4
4
  export declare const createStoryShellInput: {
5
5
  levelId: z.ZodString;
6
6
  footprint: z.ZodArray<z.ZodArray<z.ZodNumber>>;
@@ -16,6 +16,13 @@ export declare const createStoryShellInput: {
16
16
  ceilingMaterialPreset: z.ZodOptional<z.ZodString>;
17
17
  };
18
18
  export declare const createStoryShellOutput: {
19
+ persistence: z.ZodOptional<z.ZodObject<{
20
+ status: z.ZodEnum<{
21
+ unbound: "unbound";
22
+ events_unsupported: "events_unsupported";
23
+ }>;
24
+ warning: z.ZodString;
25
+ }, z.core.$strip>>;
19
26
  levelId: z.ZodString;
20
27
  wallIds: z.ZodArray<z.ZodString>;
21
28
  slabId: z.ZodNullable<z.ZodString>;
@@ -33,13 +40,14 @@ export declare const createRoofInput: {
33
40
  width: z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>;
34
41
  depth: z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>;
35
42
  roofType: z.ZodDefault<z.ZodEnum<{
43
+ gable: "gable";
36
44
  flat: "flat";
37
45
  hip: "hip";
38
- gable: "gable";
39
46
  shed: "shed";
40
47
  gambrel: "gambrel";
41
48
  dutch: "dutch";
42
49
  mansard: "mansard";
50
+ conical: "conical";
43
51
  }>>;
44
52
  pitch: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
45
53
  wallHeight: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
@@ -49,6 +57,13 @@ export declare const createRoofInput: {
49
57
  name: z.ZodOptional<z.ZodString>;
50
58
  };
51
59
  export declare const createRoofOutput: {
60
+ persistence: z.ZodOptional<z.ZodObject<{
61
+ status: z.ZodEnum<{
62
+ unbound: "unbound";
63
+ events_unsupported: "events_unsupported";
64
+ }>;
65
+ warning: z.ZodString;
66
+ }, z.core.$strip>>;
52
67
  referenceLevelId: z.ZodString;
53
68
  roofLevelId: z.ZodString;
54
69
  createdRoofLevelId: z.ZodNullable<z.ZodString>;
@@ -83,6 +98,13 @@ export declare const createStairBetweenLevelsInput: {
83
98
  name: z.ZodOptional<z.ZodString>;
84
99
  };
85
100
  export declare const createStairBetweenLevelsOutput: {
101
+ persistence: z.ZodOptional<z.ZodObject<{
102
+ status: z.ZodEnum<{
103
+ unbound: "unbound";
104
+ events_unsupported: "events_unsupported";
105
+ }>;
106
+ warning: z.ZodString;
107
+ }, z.core.$strip>>;
86
108
  stairId: z.ZodString;
87
109
  stairSegmentId: z.ZodString;
88
110
  destinationSlabId: z.ZodNullable<z.ZodString>;
@@ -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;AAcxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAQpD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAsBjC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;CAMlC,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;CA0B3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;CAM5B,CAAA;AAED,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCzC,CAAA;AAED,eAAO,MAAM,8BAA8B;;;;;;CAM1C,CAAA;AA4GD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAmU1F"}
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;AAcxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAkBpD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAsBjC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;CAOlC,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAO5B,CAAA;AAED,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCzC,CAAA;AAED,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;CAO1C,CAAA;AA4GD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAgV1F"}
@@ -1,10 +1,20 @@
1
1
  import { resolveStairTotalRise } from '@pascal-app/core';
2
2
  import { CeilingNode, getActiveRoofHeight, LevelNode, RoofNode, RoofSegmentNode, SlabNode, StairNode, StairSegmentNode, WallNode, } from '@pascal-app/core/schema';
3
3
  import { z } from 'zod';
4
- import { publishLiveSceneSnapshot } from './live-sync';
5
- import { measurement } from './measurement';
6
- import { NodeIdSchema, Vec2Schema, Vec3Schema } from './schemas';
7
- const ROOF_TYPES = ['hip', 'gable', 'shed', 'gambrel', 'dutch', 'mansard', 'flat'];
4
+ import { ADDITIVE_TOOL_ANNOTATIONS, DESTRUCTIVE_TOOL_ANNOTATIONS } from './annotations.js';
5
+ import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
6
+ import { measurement } from './measurement.js';
7
+ import { NodeIdSchema, Vec2Schema, Vec3Schema } from './schemas.js';
8
+ const ROOF_TYPES = [
9
+ 'hip',
10
+ 'gable',
11
+ 'shed',
12
+ 'gambrel',
13
+ 'dutch',
14
+ 'mansard',
15
+ 'flat',
16
+ 'conical',
17
+ ];
8
18
  const RAILING_MODES = ['none', 'left', 'right', 'both'];
9
19
  export const createStoryShellInput = {
10
20
  levelId: NodeIdSchema,
@@ -35,6 +45,7 @@ export const createStoryShellOutput = {
35
45
  slabId: z.string().nullable(),
36
46
  ceilingId: z.string().nullable(),
37
47
  createdIds: z.array(z.string()),
48
+ ...liveSyncOutput,
38
49
  };
39
50
  export const createRoofInput = {
40
51
  levelId: NodeIdSchema,
@@ -67,6 +78,7 @@ export const createRoofOutput = {
67
78
  createdRoofLevelId: z.string().nullable(),
68
79
  roofId: z.string(),
69
80
  roofSegmentId: z.string(),
81
+ ...liveSyncOutput,
70
82
  };
71
83
  export const createStairBetweenLevelsInput = {
72
84
  fromLevelId: NodeIdSchema,
@@ -108,6 +120,7 @@ export const createStairBetweenLevelsOutput = {
108
120
  destinationSlabId: z.string().nullable(),
109
121
  sourceCeilingId: z.string().nullable(),
110
122
  openingPolygon: z.array(Vec2Schema),
123
+ ...liveSyncOutput,
111
124
  };
112
125
  function textResult(payload) {
113
126
  return {
@@ -190,6 +203,7 @@ export function registerConstructionTools(server, bridge) {
190
203
  description: 'Create one level-owned building shell from a footprint: perimeter walls plus optional slab and ceiling. Use once per story; do not make first-floor walls span multiple stories.',
191
204
  inputSchema: createStoryShellInput,
192
205
  outputSchema: createStoryShellOutput,
206
+ annotations: ADDITIVE_TOOL_ANNOTATIONS,
193
207
  }, async ({ levelId, footprint, wallHeight, wallThickness, createSlab, createCeiling, slabElevation, ceilingHeight, namePrefix, wallMaterialPreset, slabMaterialPreset, ceilingMaterialPreset, }) => {
194
208
  const level = assertNode(bridge, levelId, 'level');
195
209
  if (isRoofLevel(level)) {
@@ -246,13 +260,14 @@ export function registerConstructionTools(server, bridge) {
246
260
  patches.push({ op: 'create', node: ceiling, parentId: levelId });
247
261
  }
248
262
  const result = bridge.applyPatch(patches);
249
- await publishLiveSceneSnapshot(bridge, 'create_story_shell');
263
+ const persistence = await publishLiveSceneSnapshot(bridge, 'create_story_shell');
250
264
  return textResult({
251
265
  levelId,
252
266
  wallIds,
253
267
  slabId,
254
268
  ceilingId,
255
269
  createdIds: result.createdIds,
270
+ ...persistencePayload(persistence),
256
271
  });
257
272
  });
258
273
  server.registerTool('create_roof', {
@@ -260,10 +275,18 @@ export function registerConstructionTools(server, bridge) {
260
275
  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.',
261
276
  inputSchema: createRoofInput,
262
277
  outputSchema: createRoofOutput,
278
+ annotations: ADDITIVE_TOOL_ANNOTATIONS,
263
279
  }, async ({ levelId, roofLevelId, useDedicatedRoofLevel, roofLevelLabel, roofLevelElevation, roofLevelHeight, center, width, depth, roofType, pitch, wallHeight, wallThickness, overhang, materialPreset, name, }) => {
280
+ const effectiveWidth = roofType === 'conical' ? Math.max(width, depth) : width;
281
+ const effectiveDepth = roofType === 'conical' ? effectiveWidth : depth;
264
282
  // Peak height is derived from pitch + footprint + type; we still
265
283
  // need it to size the auto-generated roof level container below.
266
- const peakHeight = getActiveRoofHeight({ roofType, pitch, width, depth });
284
+ const peakHeight = getActiveRoofHeight({
285
+ roofType,
286
+ pitch,
287
+ width: effectiveWidth,
288
+ depth: effectiveDepth,
289
+ });
267
290
  const referenceLevel = assertNode(bridge, levelId, 'level');
268
291
  const patches = [];
269
292
  let targetRoofLevelId = levelId;
@@ -294,8 +317,8 @@ export function registerConstructionTools(server, bridge) {
294
317
  }
295
318
  const segment = RoofSegmentNode.parse({
296
319
  roofType,
297
- width,
298
- depth,
320
+ width: effectiveWidth,
321
+ depth: effectiveDepth,
299
322
  wallHeight,
300
323
  pitch,
301
324
  wallThickness,
@@ -317,13 +340,14 @@ export function registerConstructionTools(server, bridge) {
317
340
  { op: 'create', node: roof, parentId: targetRoofLevelId },
318
341
  { op: 'create', node: segment, parentId: roof.id },
319
342
  ]);
320
- await publishLiveSceneSnapshot(bridge, 'create_roof');
343
+ const persistence = await publishLiveSceneSnapshot(bridge, 'create_roof');
321
344
  return textResult({
322
345
  referenceLevelId: levelId,
323
346
  roofLevelId: targetRoofLevelId,
324
347
  createdRoofLevelId,
325
348
  roofId: roof.id,
326
349
  roofSegmentId: segment.id,
350
+ ...persistencePayload(persistence),
327
351
  });
328
352
  });
329
353
  server.registerTool('create_stair_between_levels', {
@@ -331,6 +355,7 @@ export function registerConstructionTools(server, bridge) {
331
355
  description: 'Create a straight stair and a single rectangular manual opening in the destination slab/source ceiling. This disables stair auto-opening mode to avoid duplicate or irregular holes.',
332
356
  inputSchema: createStairBetweenLevelsInput,
333
357
  outputSchema: createStairBetweenLevelsOutput,
358
+ annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
334
359
  }, async ({ fromLevelId, toLevelId, position, rotation, width, runLength, totalRise, stepCount, railingMode, destinationSlabId, sourceCeilingId, createDestinationSlabOpening, createSourceCeilingOpening, openingWidth, openingLength, openingOffset, openingCenter, openingRotation, materialPreset, name, }) => {
335
360
  const fromLevel = assertNode(bridge, fromLevelId, 'level');
336
361
  const toLevel = assertNode(bridge, toLevelId, 'level');
@@ -408,13 +433,14 @@ export function registerConstructionTools(server, bridge) {
408
433
  });
409
434
  }
410
435
  bridge.applyPatch(patches);
411
- await publishLiveSceneSnapshot(bridge, 'create_stair_between_levels');
436
+ const persistence = await publishLiveSceneSnapshot(bridge, 'create_stair_between_levels');
412
437
  return textResult({
413
438
  stairId: stair.id,
414
439
  stairSegmentId: segment.id,
415
440
  destinationSlabId: destinationSlab?.id ?? null,
416
441
  sourceCeilingId: sourceCeiling?.id ?? null,
417
442
  openingPolygon,
443
+ ...persistencePayload(persistence),
418
444
  });
419
445
  });
420
446
  }
@@ -1,6 +1,6 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { z } from 'zod';
3
- import type { SceneOperations } from '../operations';
3
+ import type { SceneOperations } from '../operations/index.js';
4
4
  export declare const createLevelInput: {
5
5
  buildingId: z.ZodString;
6
6
  elevation: z.ZodOptional<z.ZodNumber>;
@@ -8,6 +8,13 @@ export declare const createLevelInput: {
8
8
  label: z.ZodOptional<z.ZodString>;
9
9
  };
10
10
  export declare const createLevelOutput: {
11
+ persistence: z.ZodOptional<z.ZodObject<{
12
+ status: z.ZodEnum<{
13
+ unbound: "unbound";
14
+ events_unsupported: "events_unsupported";
15
+ }>;
16
+ warning: z.ZodString;
17
+ }, z.core.$strip>>;
11
18
  levelId: z.ZodString;
12
19
  };
13
20
  export declare function registerCreateLevel(server: McpServer, bridge: SceneOperations): void;
@@ -1 +1 @@
1
- {"version":3,"file":"create-level.d.ts","sourceRoot":"","sources":["../../src/tools/create-level.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAIxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,eAAO,MAAM,gBAAgB;;;;;CAW5B,CAAA;AAED,eAAO,MAAM,iBAAiB;;CAE7B,CAAA;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA+CpF"}
1
+ {"version":3,"file":"create-level.d.ts","sourceRoot":"","sources":["../../src/tools/create-level.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAIxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,gBAAgB;;;;;CAW5B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;CAG7B,CAAA;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAgDpF"}