@pascal-app/mcp 1.0.3 → 1.0.5
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/CHANGELOG.md +76 -0
- package/README.md +181 -56
- package/dist/bin/pascal-mcp.js +9 -3
- package/dist/bridge/agent-session.d.ts +18 -0
- package/dist/bridge/agent-session.d.ts.map +1 -0
- package/dist/bridge/agent-session.js +15 -0
- package/dist/bridge/index.d.ts +1 -1
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.d.ts +42 -6
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +232 -45
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/safe-fetch.d.ts +22 -4
- package/dist/lib/safe-fetch.d.ts.map +1 -1
- package/dist/lib/safe-fetch.js +233 -134
- package/dist/operations/scene-operations.d.ts +41 -3
- package/dist/operations/scene-operations.d.ts.map +1 -1
- package/dist/operations/scene-operations.js +42 -1
- package/dist/prompts/from-brief.d.ts +1 -1
- package/dist/prompts/from-brief.d.ts.map +1 -1
- package/dist/prompts/from-brief.js +3 -3
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.js +3 -3
- package/dist/prompts/renovation-from-photos.d.ts +1 -1
- package/dist/prompts/renovation-from-photos.d.ts.map +1 -1
- package/dist/prompts/renovation-from-photos.js +2 -2
- package/dist/prompts/scene-guidance.d.ts.map +1 -1
- package/dist/prompts/scene-guidance.js +13 -6
- package/dist/resources/agent-guide.d.ts +1 -1
- package/dist/resources/agent-guide.d.ts.map +1 -1
- package/dist/resources/agent-guide.js +62 -33
- package/dist/resources/catalog-items.d.ts +5 -6
- package/dist/resources/catalog-items.d.ts.map +1 -1
- package/dist/resources/catalog-items.js +7 -9
- package/dist/resources/constraints.d.ts +1 -1
- package/dist/resources/constraints.d.ts.map +1 -1
- package/dist/resources/constraints.js +1 -1
- package/dist/resources/design-schema.d.ts +9 -0
- package/dist/resources/design-schema.d.ts.map +1 -0
- package/dist/resources/design-schema.js +21 -0
- package/dist/resources/index.d.ts +4 -2
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +5 -2
- package/dist/resources/scene-current.d.ts +1 -1
- package/dist/resources/scene-current.d.ts.map +1 -1
- package/dist/resources/scene-summary.d.ts +1 -1
- package/dist/resources/scene-summary.d.ts.map +1 -1
- package/dist/server.d.ts +25 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +71 -25
- package/dist/storage/disk-artifact-store.d.ts +9 -0
- package/dist/storage/disk-artifact-store.d.ts.map +1 -0
- package/dist/storage/disk-artifact-store.js +46 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +1 -0
- package/dist/storage/sqlite-scene-store.d.ts +3 -3
- package/dist/storage/sqlite-scene-store.d.ts.map +1 -1
- package/dist/storage/sqlite-scene-store.js +4 -3
- package/dist/storage/types.d.ts +36 -7
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +12 -0
- package/dist/templates/empty-studio.d.ts +3 -3
- package/dist/templates/empty-studio.d.ts.map +1 -1
- package/dist/templates/garden-house.d.ts +3 -3
- package/dist/templates/garden-house.d.ts.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/two-bedroom.d.ts +3 -3
- package/dist/templates/two-bedroom.d.ts.map +1 -1
- package/dist/tools/add-column.d.ts +5 -0
- package/dist/tools/add-column.d.ts.map +1 -0
- package/dist/tools/add-column.js +59 -0
- package/dist/tools/add-object.d.ts +76 -0
- package/dist/tools/add-object.d.ts.map +1 -0
- package/dist/tools/add-object.js +187 -0
- package/dist/tools/annotations.d.ts.map +1 -1
- package/dist/tools/apply-patch.d.ts +9 -2
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +36 -5
- package/dist/tools/asset-catalog.d.ts +9 -5
- package/dist/tools/asset-catalog.d.ts.map +1 -1
- package/dist/tools/asset-catalog.js +33 -12
- package/dist/tools/author-scene.d.ts +10 -0
- package/dist/tools/author-scene.d.ts.map +1 -0
- package/dist/tools/author-scene.js +140 -0
- package/dist/tools/check-collisions.d.ts +7 -7
- package/dist/tools/check-collisions.d.ts.map +1 -1
- package/dist/tools/check-collisions.js +7 -8
- package/dist/tools/clear-scene.d.ts +9 -0
- package/dist/tools/clear-scene.d.ts.map +1 -0
- package/dist/tools/clear-scene.js +59 -0
- package/dist/tools/collections.d.ts +4 -0
- package/dist/tools/collections.d.ts.map +1 -0
- package/dist/tools/collections.js +53 -0
- package/dist/tools/construction-tools.d.ts +12 -88
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +122 -381
- package/dist/tools/create-unit.d.ts +5 -3
- package/dist/tools/create-unit.d.ts.map +1 -1
- package/dist/tools/create-unit.js +2 -2
- package/dist/tools/errors.d.ts +15 -4
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +14 -4
- package/dist/tools/export-glb.d.ts +1 -1
- package/dist/tools/export-glb.d.ts.map +1 -1
- package/dist/tools/export-glb.js +2 -2
- package/dist/tools/export-json.d.ts +1 -1
- package/dist/tools/export-json.d.ts.map +1 -1
- package/dist/tools/export-json.js +2 -2
- package/dist/tools/geometry-script-worker.d.ts +2 -0
- package/dist/tools/geometry-script-worker.d.ts.map +1 -0
- package/dist/tools/geometry-script-worker.js +21 -0
- package/dist/tools/get-scene.d.ts +2 -1
- package/dist/tools/get-scene.d.ts.map +1 -1
- package/dist/tools/get-scene.js +5 -3
- package/dist/tools/honest-patch-guard.d.ts +2 -0
- package/dist/tools/honest-patch-guard.d.ts.map +1 -0
- package/dist/tools/honest-patch-guard.js +32 -0
- package/dist/tools/hosted-services.d.ts +4 -0
- package/dist/tools/hosted-services.d.ts.map +1 -0
- package/dist/tools/hosted-services.js +40 -0
- package/dist/tools/index.d.ts +12 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +18 -32
- package/dist/tools/level-height-guard.d.ts +2 -0
- package/dist/tools/level-height-guard.d.ts.map +1 -0
- package/dist/tools/level-height-guard.js +11 -0
- package/dist/tools/list-units.d.ts +2 -2
- package/dist/tools/list-units.d.ts.map +1 -1
- package/dist/tools/list-units.js +2 -2
- package/dist/tools/live-sync.d.ts +25 -6
- package/dist/tools/live-sync.d.ts.map +1 -1
- package/dist/tools/live-sync.js +48 -27
- package/dist/tools/local-geometry-scripts.d.ts +8 -0
- package/dist/tools/local-geometry-scripts.d.ts.map +1 -0
- package/dist/tools/local-geometry-scripts.js +67 -0
- package/dist/tools/measure.d.ts +7 -1
- package/dist/tools/measure.d.ts.map +1 -1
- package/dist/tools/measure.js +38 -70
- package/dist/tools/measurement.d.ts +1 -36
- package/dist/tools/measurement.d.ts.map +1 -1
- package/dist/tools/measurement.js +2 -94
- package/dist/tools/node-world-point.d.ts +37 -0
- package/dist/tools/node-world-point.d.ts.map +1 -0
- package/dist/tools/node-world-point.js +457 -0
- package/dist/tools/normalize-schema-dialect.d.ts +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.js +22 -3
- package/dist/tools/patch-guards.d.ts +60 -0
- package/dist/tools/patch-guards.d.ts.map +1 -0
- package/dist/tools/patch-guards.js +256 -0
- package/dist/tools/photo-to-scene/index.d.ts +1 -1
- package/dist/tools/photo-to-scene/index.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts +3 -3
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.js +10 -9
- package/dist/tools/project-files.d.ts +4 -0
- package/dist/tools/project-files.d.ts.map +1 -0
- package/dist/tools/project-files.js +30 -0
- package/dist/tools/redo.d.ts +4 -2
- package/dist/tools/redo.d.ts.map +1 -1
- package/dist/tools/redo.js +4 -4
- package/dist/tools/retired-tools.d.ts +10 -0
- package/dist/tools/retired-tools.d.ts.map +1 -0
- package/dist/tools/retired-tools.js +22 -0
- package/dist/tools/roof-level-guard.d.ts +2 -0
- package/dist/tools/roof-level-guard.d.ts.map +1 -0
- package/dist/tools/roof-level-guard.js +22 -0
- package/dist/tools/room-tools.d.ts +36 -98
- package/dist/tools/room-tools.d.ts.map +1 -1
- package/dist/tools/room-tools.js +130 -565
- package/dist/tools/scene-lifecycle/create-project.d.ts +1 -1
- package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/create-project.js +31 -6
- package/dist/tools/scene-lifecycle/delete-scene.d.ts +3 -1
- package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.js +10 -9
- package/dist/tools/scene-lifecycle/get-project-status.d.ts +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.js +6 -6
- package/dist/tools/scene-lifecycle/index.d.ts +1 -1
- package/dist/tools/scene-lifecycle/index.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.js +4 -4
- package/dist/tools/scene-lifecycle/load-scene.d.ts +2 -2
- package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/load-scene.js +5 -5
- package/dist/tools/scene-lifecycle/metadata.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.js +6 -6
- package/dist/tools/scene-lifecycle/save-scene.d.ts +6 -3
- package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/save-scene.js +124 -16
- package/dist/tools/scene-lifecycle/test-utils.d.ts +3 -3
- package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/test-utils.js +2 -1
- package/dist/tools/set-unit-members.d.ts +4 -2
- package/dist/tools/set-unit-members.d.ts.map +1 -1
- package/dist/tools/set-unit-members.js +6 -6
- package/dist/tools/set-zone.d.ts +4 -2
- package/dist/tools/set-zone.d.ts.map +1 -1
- package/dist/tools/set-zone.js +30 -18
- package/dist/tools/shared-tools.d.ts +40 -0
- package/dist/tools/shared-tools.d.ts.map +1 -0
- package/dist/tools/shared-tools.js +574 -0
- package/dist/tools/structure-tools.d.ts +57 -0
- package/dist/tools/structure-tools.d.ts.map +1 -0
- package/dist/tools/structure-tools.js +57 -0
- package/dist/tools/templates/create-from-template.d.ts +2 -2
- package/dist/tools/templates/create-from-template.d.ts.map +1 -1
- package/dist/tools/templates/create-from-template.js +6 -6
- package/dist/tools/templates/create-house-from-brief.d.ts +1 -1
- package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -1
- package/dist/tools/templates/create-house-from-brief.js +6 -6
- package/dist/tools/templates/index.d.ts +1 -1
- package/dist/tools/templates/index.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.d.ts +1 -1
- package/dist/tools/templates/list-templates.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.js +2 -2
- package/dist/tools/undo.d.ts +4 -2
- package/dist/tools/undo.d.ts.map +1 -1
- package/dist/tools/undo.js +4 -4
- package/dist/tools/unit-members.d.ts.map +1 -1
- package/dist/tools/unit-members.js +6 -6
- package/dist/tools/variants/generate-variants.d.ts +6 -6
- package/dist/tools/variants/generate-variants.d.ts.map +1 -1
- package/dist/tools/variants/generate-variants.js +6 -6
- package/dist/tools/variants/index.d.ts +1 -1
- package/dist/tools/variants/index.d.ts.map +1 -1
- package/dist/tools/variants/mutations.js +1 -1
- package/dist/tools/view-scene.d.ts +44 -0
- package/dist/tools/view-scene.d.ts.map +1 -0
- package/dist/tools/view-scene.js +75 -0
- package/dist/tools/vision/analyze-floorplan-image.d.ts +1 -1
- package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -1
- package/dist/tools/vision/analyze-floorplan-image.js +7 -7
- package/dist/tools/vision/analyze-room-photo.d.ts +1 -1
- package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -1
- package/dist/tools/vision/analyze-room-photo.js +7 -7
- package/dist/tools/vision/index.d.ts +1 -1
- package/dist/tools/vision/index.d.ts.map +1 -1
- package/dist/transports/http.d.ts +8 -2
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +9 -3
- package/dist/transports/stdio.d.ts +15 -9
- package/dist/transports/stdio.d.ts.map +1 -1
- package/dist/transports/stdio.js +18 -11
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +17 -3
- package/examples/coordinate-conventions-demo.md +12 -13
- package/examples/embed-in-agent.ts +6 -7
- package/examples/generate-apartment.md +13 -15
- package/examples/photo-to-scene.md +3 -4
- package/examples/renovate-from-photos.md +6 -9
- package/package.json +19 -9
- package/dist/tools/create-level.d.ts +0 -21
- package/dist/tools/create-level.d.ts.map +0 -1
- package/dist/tools/create-level.js +0 -63
- package/dist/tools/create-wall.d.ts +0 -22
- package/dist/tools/create-wall.d.ts.map +0 -1
- package/dist/tools/create-wall.js +0 -57
- package/dist/tools/cut-opening.d.ts +0 -25
- package/dist/tools/cut-opening.d.ts.map +0 -1
- package/dist/tools/cut-opening.js +0 -61
- package/dist/tools/delete-node.d.ts +0 -19
- package/dist/tools/delete-node.d.ts.map +0 -1
- package/dist/tools/delete-node.js +0 -40
- package/dist/tools/describe-node.d.ts +0 -17
- package/dist/tools/describe-node.d.ts.map +0 -1
- package/dist/tools/describe-node.js +0 -97
- package/dist/tools/door-clearance.d.ts +0 -135
- package/dist/tools/door-clearance.d.ts.map +0 -1
- package/dist/tools/door-clearance.js +0 -334
- package/dist/tools/duplicate-level.d.ts +0 -19
- package/dist/tools/duplicate-level.d.ts.map +0 -1
- package/dist/tools/duplicate-level.js +0 -60
- package/dist/tools/find-nodes.d.ts +0 -32
- package/dist/tools/find-nodes.d.ts.map +0 -1
- package/dist/tools/find-nodes.js +0 -107
- package/dist/tools/geometry.d.ts +0 -24
- package/dist/tools/geometry.d.ts.map +0 -1
- package/dist/tools/geometry.js +0 -94
- package/dist/tools/get-node.d.ts +0 -11
- package/dist/tools/get-node.d.ts.map +0 -1
- package/dist/tools/get-node.js +0 -29
- package/dist/tools/layout-clearance.d.ts +0 -105
- package/dist/tools/layout-clearance.d.ts.map +0 -1
- package/dist/tools/layout-clearance.js +0 -190
- package/dist/tools/place-item.d.ts +0 -22
- package/dist/tools/place-item.d.ts.map +0 -1
- package/dist/tools/place-item.js +0 -89
- package/dist/tools/scene-query.d.ts +0 -62
- package/dist/tools/scene-query.d.ts.map +0 -1
- package/dist/tools/scene-query.js +0 -670
- package/dist/tools/validate-scene.d.ts +0 -19
- package/dist/tools/validate-scene.d.ts.map +0 -1
- package/dist/tools/validate-scene.js +0 -28
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createZone, generateId } from '@pascal-app/core';
|
|
2
|
+
import { roofLevelRefusal, unknownMaterialPresetRefusal } from '@pascal-app/core/agent-operations';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { ADDITIVE_TOOL_ANNOTATIONS
|
|
4
|
+
import { ADDITIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
5
|
+
import { refusalResult } from './errors.js';
|
|
5
6
|
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
6
7
|
import { measurement } from './measurement.js';
|
|
7
|
-
import { NodeIdSchema, Vec2Schema
|
|
8
|
-
const ROOF_TYPES = [
|
|
9
|
-
'hip',
|
|
10
|
-
'gable',
|
|
11
|
-
'shed',
|
|
12
|
-
'gambrel',
|
|
13
|
-
'dutch',
|
|
14
|
-
'mansard',
|
|
15
|
-
'flat',
|
|
16
|
-
'conical',
|
|
17
|
-
];
|
|
18
|
-
const RAILING_MODES = ['none', 'left', 'right', 'both'];
|
|
8
|
+
import { NodeIdSchema, Vec2Schema } from './schemas.js';
|
|
19
9
|
export const createStoryShellInput = {
|
|
20
10
|
levelId: NodeIdSchema,
|
|
21
11
|
footprint: z.array(Vec2Schema).min(3),
|
|
@@ -27,9 +17,17 @@ export const createStoryShellInput = {
|
|
|
27
17
|
positive: true,
|
|
28
18
|
description: 'Wall thickness.',
|
|
29
19
|
}).default(0.16),
|
|
30
|
-
createSlab: z
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
createSlab: z
|
|
21
|
+
.boolean()
|
|
22
|
+
.default(true)
|
|
23
|
+
.describe('Floor intent for the rooms inside the shell. False records hasFloor: false.'),
|
|
24
|
+
createCeiling: z
|
|
25
|
+
.boolean()
|
|
26
|
+
.default(true)
|
|
27
|
+
.describe('Ceiling intent for the rooms inside the shell. False records hasCeiling: false.'),
|
|
28
|
+
slabElevation: measurement('length', 'm', {
|
|
29
|
+
description: "Walking surface of the derived plate, stored as the room's floor elevation.",
|
|
30
|
+
}).default(0.1),
|
|
33
31
|
ceilingHeight: measurement('length', 'm', {
|
|
34
32
|
positive: true,
|
|
35
33
|
description: 'Ceiling height.',
|
|
@@ -42,86 +40,15 @@ export const createStoryShellInput = {
|
|
|
42
40
|
export const createStoryShellOutput = {
|
|
43
41
|
levelId: z.string(),
|
|
44
42
|
wallIds: z.array(z.string()),
|
|
43
|
+
/** Zones the reconciler derived for the enclosed faces. */
|
|
44
|
+
zoneIds: z.array(z.string()),
|
|
45
|
+
/** Derived floor plate. `null` when floors were declined or nothing reconciled. */
|
|
45
46
|
slabId: z.string().nullable(),
|
|
47
|
+
/** Derived ceiling. `null` when ceilings were declined or nothing reconciled. */
|
|
46
48
|
ceilingId: z.string().nullable(),
|
|
47
49
|
createdIds: z.array(z.string()),
|
|
48
50
|
...liveSyncOutput,
|
|
49
51
|
};
|
|
50
|
-
export const createRoofInput = {
|
|
51
|
-
levelId: NodeIdSchema,
|
|
52
|
-
roofLevelId: NodeIdSchema.optional(),
|
|
53
|
-
useDedicatedRoofLevel: z.boolean().default(true),
|
|
54
|
-
roofLevelLabel: z.string().default('Roof'),
|
|
55
|
-
// A level ordinal (story index), not a length — kept numeric.
|
|
56
|
-
roofLevelElevation: z.number().optional(),
|
|
57
|
-
roofLevelHeight: measurement('length', 'm', {
|
|
58
|
-
positive: true,
|
|
59
|
-
description: 'Roof level height.',
|
|
60
|
-
}).optional(),
|
|
61
|
-
center: Vec3Schema.optional(),
|
|
62
|
-
width: measurement('length', 'm', { positive: true, description: 'Roof width.' }),
|
|
63
|
-
depth: measurement('length', 'm', { positive: true, description: 'Roof depth.' }),
|
|
64
|
-
roofType: z.enum(ROOF_TYPES).default('hip'),
|
|
65
|
-
pitch: measurement('angle', 'deg', { min: 0, max: 85, description: 'Roof pitch.' }).default(35),
|
|
66
|
-
wallHeight: measurement('length', 'm', { min: 0, description: 'Knee-wall height.' }).default(0.35),
|
|
67
|
-
wallThickness: measurement('length', 'm', {
|
|
68
|
-
positive: true,
|
|
69
|
-
description: 'Wall thickness.',
|
|
70
|
-
}).default(0.16),
|
|
71
|
-
overhang: measurement('length', 'm', { min: 0, description: 'Eave overhang.' }).default(0.45),
|
|
72
|
-
materialPreset: z.string().optional(),
|
|
73
|
-
name: z.string().optional(),
|
|
74
|
-
};
|
|
75
|
-
export const createRoofOutput = {
|
|
76
|
-
referenceLevelId: z.string(),
|
|
77
|
-
roofLevelId: z.string(),
|
|
78
|
-
createdRoofLevelId: z.string().nullable(),
|
|
79
|
-
roofId: z.string(),
|
|
80
|
-
roofSegmentId: z.string(),
|
|
81
|
-
...liveSyncOutput,
|
|
82
|
-
};
|
|
83
|
-
export const createStairBetweenLevelsInput = {
|
|
84
|
-
fromLevelId: NodeIdSchema,
|
|
85
|
-
toLevelId: NodeIdSchema,
|
|
86
|
-
position: Vec3Schema,
|
|
87
|
-
rotation: measurement('angle', 'rad', { description: 'Y-axis rotation.' }).default(0),
|
|
88
|
-
width: measurement('length', 'm', { positive: true, description: 'Stair width.' }).default(1),
|
|
89
|
-
runLength: measurement('length', 'm', {
|
|
90
|
-
positive: true,
|
|
91
|
-
description: 'Horizontal run length.',
|
|
92
|
-
}).default(3),
|
|
93
|
-
totalRise: measurement('length', 'm', {
|
|
94
|
-
positive: true,
|
|
95
|
-
description: 'Total vertical rise.',
|
|
96
|
-
}).optional(),
|
|
97
|
-
stepCount: z.number().int().positive().default(14),
|
|
98
|
-
railingMode: z.enum(RAILING_MODES).default('both'),
|
|
99
|
-
destinationSlabId: NodeIdSchema.optional(),
|
|
100
|
-
sourceCeilingId: NodeIdSchema.optional(),
|
|
101
|
-
createDestinationSlabOpening: z.boolean().default(true),
|
|
102
|
-
createSourceCeilingOpening: z.boolean().default(true),
|
|
103
|
-
openingWidth: measurement('length', 'm', {
|
|
104
|
-
positive: true,
|
|
105
|
-
description: 'Floor opening width.',
|
|
106
|
-
}).optional(),
|
|
107
|
-
openingLength: measurement('length', 'm', {
|
|
108
|
-
positive: true,
|
|
109
|
-
description: 'Floor opening length.',
|
|
110
|
-
}).optional(),
|
|
111
|
-
openingOffset: measurement('length', 'm', { min: 0, description: 'Opening offset.' }).default(0),
|
|
112
|
-
openingCenter: Vec2Schema.optional(),
|
|
113
|
-
openingRotation: measurement('angle', 'rad', { description: 'Opening rotation.' }).optional(),
|
|
114
|
-
materialPreset: z.string().optional(),
|
|
115
|
-
name: z.string().optional(),
|
|
116
|
-
};
|
|
117
|
-
export const createStairBetweenLevelsOutput = {
|
|
118
|
-
stairId: z.string(),
|
|
119
|
-
stairSegmentId: z.string(),
|
|
120
|
-
destinationSlabId: z.string().nullable(),
|
|
121
|
-
sourceCeilingId: z.string().nullable(),
|
|
122
|
-
openingPolygon: z.array(Vec2Schema),
|
|
123
|
-
...liveSyncOutput,
|
|
124
|
-
};
|
|
125
52
|
function textResult(payload) {
|
|
126
53
|
return {
|
|
127
54
|
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
@@ -136,310 +63,124 @@ function assertNode(bridge, id, type) {
|
|
|
136
63
|
throw new Error(`Node ${id} is a ${node.type}, expected ${type}`);
|
|
137
64
|
return node;
|
|
138
65
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
66
|
+
/** Room zones that appeared on the level while this tool call ran. */
|
|
67
|
+
function newRoomZoneIds(bridge, levelId, before) {
|
|
68
|
+
return Object.values(bridge.getNodes())
|
|
69
|
+
.filter((node) => node.type === 'zone' &&
|
|
70
|
+
node.parentId === levelId &&
|
|
71
|
+
node.spaceRole === 'room' &&
|
|
72
|
+
!before.has(node.id))
|
|
73
|
+
.map((node) => node.id)
|
|
74
|
+
.sort();
|
|
145
75
|
}
|
|
146
|
-
function
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
'
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
.filter((node) => node.type === 'level')
|
|
157
|
-
.map((level) => level.level);
|
|
158
|
-
const referenceIndex = referenceLevel.type === 'level' ? referenceLevel.level : 0;
|
|
159
|
-
const candidate = referenceIndex + 1;
|
|
160
|
-
return existing.includes(candidate) ? Math.max(candidate, ...existing) + 1 : candidate;
|
|
161
|
-
}
|
|
162
|
-
function nodesOnLevel(bridge, levelId) {
|
|
163
|
-
return Object.values(bridge.getNodes()).filter((node) => node.id !== levelId && bridge.resolveLevelId(node.id) === levelId);
|
|
164
|
-
}
|
|
165
|
-
function firstNodeOnLevel(bridge, levelId, type) {
|
|
166
|
-
return nodesOnLevel(bridge, levelId).find((node) => node.type === type) ?? null;
|
|
167
|
-
}
|
|
168
|
-
function rotatePoint(x, z, rotation) {
|
|
169
|
-
const cos = Math.cos(rotation);
|
|
170
|
-
const sin = Math.sin(rotation);
|
|
171
|
-
return [x * cos + z * sin, -x * sin + z * cos];
|
|
172
|
-
}
|
|
173
|
-
function rectangularOpening(args) {
|
|
174
|
-
const width = args.width + args.offset * 2;
|
|
175
|
-
const length = args.length + args.offset * 2;
|
|
176
|
-
const center = args.center ?? [
|
|
177
|
-
args.position[0],
|
|
178
|
-
args.position[2] + args.length / 2,
|
|
179
|
-
];
|
|
180
|
-
const rotation = args.openingRotation ?? args.rotation;
|
|
181
|
-
const halfW = width / 2;
|
|
182
|
-
const halfL = length / 2;
|
|
183
|
-
const local = [
|
|
184
|
-
[-halfW, -halfL],
|
|
185
|
-
[halfW, -halfL],
|
|
186
|
-
[halfW, halfL],
|
|
187
|
-
[-halfW, halfL],
|
|
188
|
-
];
|
|
189
|
-
return local.map(([x, z]) => {
|
|
190
|
-
const [rx, rz] = rotatePoint(x, z, rotation);
|
|
191
|
-
return [center[0] + rx, center[1] + rz];
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
function withHole(surface, hole) {
|
|
195
|
-
return {
|
|
196
|
-
holes: [...(surface.holes ?? []), hole],
|
|
197
|
-
holeMetadata: [...(surface.holeMetadata ?? []), { source: 'manual' }],
|
|
198
|
-
};
|
|
76
|
+
function derivedShellSurfaces(bridge, levelId, zoneIds) {
|
|
77
|
+
const children = Object.values(bridge.getNodes()).filter((node) => node.parentId === levelId);
|
|
78
|
+
const plate = children
|
|
79
|
+
.filter((node) => node.type === 'slab')
|
|
80
|
+
.sort((a, b) => Number(a.plateRole === 'base') - Number(b.plateRole === 'base'))
|
|
81
|
+
.find((node) => node.type === 'slab' &&
|
|
82
|
+
node.boundary === 'auto' &&
|
|
83
|
+
(node.zoneIds ?? []).some((id) => zoneIds.includes(id)));
|
|
84
|
+
const ceiling = children.find((node) => node.type === 'ceiling' && node.boundary === 'auto' && zoneIds.includes(node.zoneId ?? ''));
|
|
85
|
+
return { slabId: plate?.id ?? null, ceilingId: ceiling?.id ?? null };
|
|
199
86
|
}
|
|
200
87
|
export function registerConstructionTools(server, bridge) {
|
|
201
88
|
server.registerTool('create_story_shell', {
|
|
202
89
|
title: 'Create story shell',
|
|
203
|
-
description: 'Create one level-owned building shell from a footprint: perimeter walls
|
|
204
|
-
inputSchema: createStoryShellInput,
|
|
205
|
-
outputSchema: createStoryShellOutput,
|
|
90
|
+
description: 'Create one level-owned building shell from a footprint: the perimeter walls. The floor plate and the ceiling are DERIVED from the rooms the walls enclose — never author a slab or a ceiling here, and never pass boundary/autoFromWalls; createSlab / createCeiling / slabElevation are recorded as room intent instead. Use once per story; do not make first-floor walls span multiple stories.',
|
|
91
|
+
inputSchema: z.object(createStoryShellInput),
|
|
92
|
+
outputSchema: z.object(createStoryShellOutput),
|
|
206
93
|
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
207
94
|
}, async ({ levelId, footprint, wallHeight, wallThickness, createSlab, createCeiling, slabElevation, ceilingHeight, namePrefix, wallMaterialPreset, slabMaterialPreset, ceilingMaterialPreset, }) => {
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
95
|
+
const preset = unknownMaterialPresetRefusal({
|
|
96
|
+
wallMaterialPreset,
|
|
97
|
+
slabMaterialPreset,
|
|
98
|
+
ceilingMaterialPreset,
|
|
99
|
+
});
|
|
100
|
+
if (preset)
|
|
101
|
+
throw new Error(preset);
|
|
102
|
+
assertNode(bridge, levelId, 'level');
|
|
103
|
+
const onRoofLevel = roofLevelRefusal(bridge.getNodes(), levelId, 'a story shell');
|
|
104
|
+
if (onRoofLevel)
|
|
105
|
+
return refusalResult(onRoofLevel);
|
|
212
106
|
const points = footprint;
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
107
|
+
const before = new Set(Object.keys(bridge.getNodes()));
|
|
108
|
+
const plan = createZone(bridge.getNodes(), {
|
|
109
|
+
levelId,
|
|
110
|
+
polygon: points,
|
|
111
|
+
name: namePrefix ?? 'Room',
|
|
112
|
+
enclose: true,
|
|
113
|
+
mintId: generateId,
|
|
114
|
+
wall: {
|
|
220
115
|
thickness: wallThickness,
|
|
221
116
|
...(wallHeight !== undefined ? { height: wallHeight } : {}),
|
|
222
|
-
frontSide: 'exterior',
|
|
223
|
-
backSide: 'interior',
|
|
224
|
-
...(wallMaterialPreset ? { materialPreset: wallMaterialPreset } : {}),
|
|
225
|
-
metadata: { role: 'exterior', storyShell: true },
|
|
226
|
-
});
|
|
227
|
-
wallIds.push(wall.id);
|
|
228
|
-
patches.push({ op: 'create', node: wall, parentId: levelId });
|
|
229
|
-
}
|
|
230
|
-
let slabId = null;
|
|
231
|
-
if (createSlab) {
|
|
232
|
-
const slab = SlabNode.parse({
|
|
233
|
-
name: namePrefix ? `${namePrefix} Slab` : undefined,
|
|
234
|
-
polygon: points,
|
|
235
|
-
elevation: slabElevation,
|
|
236
|
-
// Grounded solid: underside on the level plane, so the created
|
|
237
|
-
// story slab occupies [0, slabElevation] like the legacy
|
|
238
|
-
// extrude-from-zero model.
|
|
239
|
-
thickness: Math.max(slabElevation, 0),
|
|
240
|
-
recessed: slabElevation < 0,
|
|
241
|
-
...(slabMaterialPreset ? { materialPreset: slabMaterialPreset } : {}),
|
|
242
|
-
metadata: { role: 'story-slab' },
|
|
243
|
-
});
|
|
244
|
-
slabId = slab.id;
|
|
245
|
-
patches.push({ op: 'create', node: slab, parentId: levelId });
|
|
246
|
-
}
|
|
247
|
-
let ceilingId = null;
|
|
248
|
-
if (createCeiling) {
|
|
249
|
-
// Height-less unless the caller pinned one: a new story ceiling
|
|
250
|
-
// follows the level top automatically.
|
|
251
|
-
const explicitCeilingHeight = ceilingHeight ?? wallHeight;
|
|
252
|
-
const ceiling = CeilingNode.parse({
|
|
253
|
-
name: namePrefix ? `${namePrefix} Ceiling` : undefined,
|
|
254
|
-
polygon: points,
|
|
255
|
-
...(explicitCeilingHeight !== undefined ? { height: explicitCeilingHeight } : {}),
|
|
256
|
-
...(ceilingMaterialPreset ? { materialPreset: ceilingMaterialPreset } : {}),
|
|
257
|
-
metadata: { role: 'story-ceiling' },
|
|
258
|
-
});
|
|
259
|
-
ceilingId = ceiling.id;
|
|
260
|
-
patches.push({ op: 'create', node: ceiling, parentId: levelId });
|
|
261
|
-
}
|
|
262
|
-
const result = bridge.applyPatch(patches);
|
|
263
|
-
const persistence = await publishLiveSceneSnapshot(bridge, 'create_story_shell');
|
|
264
|
-
return textResult({
|
|
265
|
-
levelId,
|
|
266
|
-
wallIds,
|
|
267
|
-
slabId,
|
|
268
|
-
ceilingId,
|
|
269
|
-
createdIds: result.createdIds,
|
|
270
|
-
...persistencePayload(persistence),
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
server.registerTool('create_roof', {
|
|
274
|
-
title: 'Create roof',
|
|
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.',
|
|
276
|
-
inputSchema: createRoofInput,
|
|
277
|
-
outputSchema: createRoofOutput,
|
|
278
|
-
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
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;
|
|
282
|
-
// Peak height is derived from pitch + footprint + type; we still
|
|
283
|
-
// need it to size the auto-generated roof level container below.
|
|
284
|
-
const peakHeight = getActiveRoofHeight({
|
|
285
|
-
roofType,
|
|
286
|
-
pitch,
|
|
287
|
-
width: effectiveWidth,
|
|
288
|
-
depth: effectiveDepth,
|
|
289
|
-
});
|
|
290
|
-
const referenceLevel = assertNode(bridge, levelId, 'level');
|
|
291
|
-
const patches = [];
|
|
292
|
-
let targetRoofLevelId = levelId;
|
|
293
|
-
let createdRoofLevelId = null;
|
|
294
|
-
if (roofLevelId !== undefined) {
|
|
295
|
-
const roofLevel = assertNode(bridge, roofLevelId, 'level');
|
|
296
|
-
if (!isRoofLevel(roofLevel)) {
|
|
297
|
-
throw new Error(`roofLevelId ${roofLevelId} must reference a dedicated roof level with metadata.role = "roof"; omit roofLevelId to create one automatically`);
|
|
298
|
-
}
|
|
299
|
-
targetRoofLevelId = roofLevelId;
|
|
300
|
-
}
|
|
301
|
-
else if (useDedicatedRoofLevel && !isRoofLevel(referenceLevel)) {
|
|
302
|
-
const buildingId = getBuildingIdForLevel(bridge, levelId);
|
|
303
|
-
const roofLevel = LevelNode.parse({
|
|
304
|
-
name: roofLevelLabel,
|
|
305
|
-
level: roofLevelElevation ?? nextLevelIndex(bridge, buildingId, referenceLevel),
|
|
306
|
-
height: roofLevelHeight ?? Math.max(wallHeight + peakHeight, 0.2),
|
|
307
|
-
children: [],
|
|
308
|
-
metadata: {
|
|
309
|
-
role: 'roof',
|
|
310
|
-
label: roofLevelLabel,
|
|
311
|
-
referenceLevelId: levelId,
|
|
312
|
-
},
|
|
313
|
-
});
|
|
314
|
-
targetRoofLevelId = roofLevel.id;
|
|
315
|
-
createdRoofLevelId = roofLevel.id;
|
|
316
|
-
patches.push({ op: 'create', node: roofLevel, parentId: buildingId });
|
|
317
|
-
}
|
|
318
|
-
const segment = RoofSegmentNode.parse({
|
|
319
|
-
roofType,
|
|
320
|
-
width: effectiveWidth,
|
|
321
|
-
depth: effectiveDepth,
|
|
322
|
-
wallHeight,
|
|
323
|
-
pitch,
|
|
324
|
-
wallThickness,
|
|
325
|
-
overhang,
|
|
326
|
-
...(materialPreset ? { materialPreset } : {}),
|
|
327
|
-
});
|
|
328
|
-
const roof = RoofNode.parse({
|
|
329
|
-
name: name ?? 'Roof',
|
|
330
|
-
position: center ?? [0, 0, 0],
|
|
331
|
-
children: [segment.id],
|
|
332
|
-
...(materialPreset ? { materialPreset } : {}),
|
|
333
|
-
metadata: {
|
|
334
|
-
referenceLevelId: levelId,
|
|
335
|
-
roofLevelId: targetRoofLevelId,
|
|
336
|
-
},
|
|
337
|
-
});
|
|
338
|
-
bridge.applyPatch([
|
|
339
|
-
...patches,
|
|
340
|
-
{ op: 'create', node: roof, parentId: targetRoofLevelId },
|
|
341
|
-
{ op: 'create', node: segment, parentId: roof.id },
|
|
342
|
-
]);
|
|
343
|
-
const persistence = await publishLiveSceneSnapshot(bridge, 'create_roof');
|
|
344
|
-
return textResult({
|
|
345
|
-
referenceLevelId: levelId,
|
|
346
|
-
roofLevelId: targetRoofLevelId,
|
|
347
|
-
createdRoofLevelId,
|
|
348
|
-
roofId: roof.id,
|
|
349
|
-
roofSegmentId: segment.id,
|
|
350
|
-
...persistencePayload(persistence),
|
|
351
|
-
});
|
|
352
|
-
});
|
|
353
|
-
server.registerTool('create_stair_between_levels', {
|
|
354
|
-
title: 'Create stair between levels',
|
|
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.',
|
|
356
|
-
inputSchema: createStairBetweenLevelsInput,
|
|
357
|
-
outputSchema: createStairBetweenLevelsOutput,
|
|
358
|
-
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
359
|
-
}, async ({ fromLevelId, toLevelId, position, rotation, width, runLength, totalRise, stepCount, railingMode, destinationSlabId, sourceCeilingId, createDestinationSlabOpening, createSourceCeilingOpening, openingWidth, openingLength, openingOffset, openingCenter, openingRotation, materialPreset, name, }) => {
|
|
360
|
-
const fromLevel = assertNode(bridge, fromLevelId, 'level');
|
|
361
|
-
const toLevel = assertNode(bridge, toLevelId, 'level');
|
|
362
|
-
if (isRoofLevel(fromLevel) || isRoofLevel(toLevel)) {
|
|
363
|
-
throw new Error('Roof support levels are not occupied stories; create a separate occupied attic/story level if a stair-accessible attic is required');
|
|
364
|
-
}
|
|
365
|
-
const stairDraft = StairNode.parse({
|
|
366
|
-
name: name ?? 'Stair',
|
|
367
|
-
position: position,
|
|
368
|
-
rotation,
|
|
369
|
-
stairType: 'straight',
|
|
370
|
-
fromLevelId,
|
|
371
|
-
toLevelId,
|
|
372
|
-
slabOpeningMode: 'none',
|
|
373
|
-
openingOffset,
|
|
374
|
-
width,
|
|
375
|
-
...(totalRise !== undefined ? { totalRise } : {}),
|
|
376
|
-
stepCount,
|
|
377
|
-
railingMode,
|
|
378
|
-
children: [],
|
|
379
|
-
...(materialPreset ? { materialPreset } : {}),
|
|
380
|
-
metadata: {
|
|
381
|
-
openingManaged: 'manual-rectangular',
|
|
382
117
|
},
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
...fromLevel,
|
|
388
|
-
children: [...fromLevel.children, stairDraft.id],
|
|
118
|
+
intent: {
|
|
119
|
+
floor: { elevation: slabElevation },
|
|
120
|
+
hasFloor: createSlab,
|
|
121
|
+
hasCeiling: createCeiling,
|
|
389
122
|
},
|
|
390
|
-
[stairDraft.id]: stairDraft,
|
|
391
|
-
};
|
|
392
|
-
const resolvedTotalRise = resolveStairTotalRise(stairDraft, riseNodes);
|
|
393
|
-
const segment = StairSegmentNode.parse({
|
|
394
|
-
segmentType: 'stair',
|
|
395
|
-
width,
|
|
396
|
-
length: runLength,
|
|
397
|
-
height: resolvedTotalRise,
|
|
398
|
-
stepCount,
|
|
399
|
-
...(materialPreset ? { materialPreset } : {}),
|
|
400
123
|
});
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
124
|
+
const wallIds = plan.changes.flatMap((change) => change.op === 'create' && change.node.type === 'wall' ? [change.node.id] : []);
|
|
125
|
+
bridge.runAsSingleHistoryStep(() => {
|
|
126
|
+
bridge.applyPatch(plan.changes.map((change) => change.op === 'create'
|
|
127
|
+
? {
|
|
128
|
+
...change,
|
|
129
|
+
parentId: change.node.parentId,
|
|
130
|
+
node: change.node.type === 'wall'
|
|
131
|
+
? {
|
|
132
|
+
...change.node,
|
|
133
|
+
...(namePrefix
|
|
134
|
+
? { name: `${namePrefix} Wall ${wallIds.indexOf(change.node.id) + 1}` }
|
|
135
|
+
: {}),
|
|
136
|
+
...(wallMaterialPreset ? { materialPreset: wallMaterialPreset } : {}),
|
|
137
|
+
metadata: { role: 'exterior', storyShell: true },
|
|
138
|
+
}
|
|
139
|
+
: change.node,
|
|
140
|
+
}
|
|
141
|
+
: change));
|
|
142
|
+
bridge.deriveStructure([levelId]);
|
|
410
143
|
});
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
144
|
+
const zoneIds = newRoomZoneIds(bridge, levelId, before);
|
|
145
|
+
// Finishes and an explicit ceiling height stay editable on derived
|
|
146
|
+
// construction, so they are applied to whatever the reconciler built.
|
|
147
|
+
const derived = derivedShellSurfaces(bridge, levelId, zoneIds);
|
|
148
|
+
const explicitCeilingHeight = ceilingHeight ?? wallHeight;
|
|
149
|
+
const finishes = [
|
|
150
|
+
...(derived.slabId && slabMaterialPreset
|
|
151
|
+
? [
|
|
152
|
+
{
|
|
153
|
+
op: 'update',
|
|
154
|
+
id: derived.slabId,
|
|
155
|
+
data: {
|
|
156
|
+
...(slabMaterialPreset ? { materialPreset: slabMaterialPreset } : {}),
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
]
|
|
160
|
+
: []),
|
|
161
|
+
...(derived.ceilingId && (ceilingMaterialPreset || explicitCeilingHeight !== undefined)
|
|
162
|
+
? [
|
|
163
|
+
{
|
|
164
|
+
op: 'update',
|
|
165
|
+
id: derived.ceilingId,
|
|
166
|
+
data: {
|
|
167
|
+
...(ceilingMaterialPreset ? { materialPreset: ceilingMaterialPreset } : {}),
|
|
168
|
+
...(explicitCeilingHeight !== undefined ? { height: explicitCeilingHeight } : {}),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
]
|
|
172
|
+
: []),
|
|
414
173
|
];
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
if (createDestinationSlabOpening && destinationSlab?.type === 'slab') {
|
|
419
|
-
patches.push({
|
|
420
|
-
op: 'update',
|
|
421
|
-
id: destinationSlab.id,
|
|
422
|
-
data: withHole(destinationSlab, openingPolygon),
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
const sourceCeiling = sourceCeilingId !== undefined
|
|
426
|
-
? assertNode(bridge, sourceCeilingId, 'ceiling')
|
|
427
|
-
: firstNodeOnLevel(bridge, fromLevelId, 'ceiling');
|
|
428
|
-
if (createSourceCeilingOpening && sourceCeiling?.type === 'ceiling') {
|
|
429
|
-
patches.push({
|
|
430
|
-
op: 'update',
|
|
431
|
-
id: sourceCeiling.id,
|
|
432
|
-
data: withHole(sourceCeiling, openingPolygon),
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
bridge.applyPatch(patches);
|
|
436
|
-
const persistence = await publishLiveSceneSnapshot(bridge, 'create_stair_between_levels');
|
|
174
|
+
if (finishes.length > 0)
|
|
175
|
+
bridge.applyPatch(finishes);
|
|
176
|
+
const persistence = await publishLiveSceneSnapshot(bridge, 'create_story_shell');
|
|
437
177
|
return textResult({
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
178
|
+
levelId,
|
|
179
|
+
wallIds,
|
|
180
|
+
zoneIds,
|
|
181
|
+
slabId: derived.slabId,
|
|
182
|
+
ceilingId: derived.ceilingId,
|
|
183
|
+
createdIds: Object.keys(bridge.getNodes()).filter((id) => !before.has(id)),
|
|
443
184
|
...persistencePayload(persistence),
|
|
444
185
|
});
|
|
445
186
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../operations/index.js';
|
|
4
4
|
export declare const createUnitInput: {
|
|
@@ -6,18 +6,20 @@ export declare const createUnitInput: {
|
|
|
6
6
|
name: z.ZodString;
|
|
7
7
|
kind: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
|
|
8
8
|
apartment: "apartment";
|
|
9
|
-
"hotel-room": "hotel-room";
|
|
10
9
|
commercial: "commercial";
|
|
11
10
|
common: "common";
|
|
11
|
+
"hotel-room": "hotel-room";
|
|
12
12
|
}>>>;
|
|
13
13
|
color: z.ZodOptional<z.ZodString>;
|
|
14
14
|
memberZoneIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
15
15
|
};
|
|
16
16
|
export declare const createUnitOutput: {
|
|
17
|
+
project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
18
|
+
unsaved: z.ZodOptional<z.ZodString>;
|
|
17
19
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
18
20
|
status: z.ZodEnum<{
|
|
19
|
-
unbound: "unbound";
|
|
20
21
|
events_unsupported: "events_unsupported";
|
|
22
|
+
unbound: "unbound";
|
|
21
23
|
}>;
|
|
22
24
|
warning: z.ZodString;
|
|
23
25
|
}, z.core.$strip>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-unit.d.ts","sourceRoot":"","sources":["../../src/tools/create-unit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"create-unit.d.ts","sourceRoot":"","sources":["../../src/tools/create-unit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,eAAO,MAAM,eAAe;IAC1B,UAAU;IACV,IAAI;IACJ,IAAI;;;;;;IACJ,KAAK;IACL,aAAa;CACd,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;CAG5B,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAuBnF"}
|
|
@@ -19,8 +19,8 @@ export function registerCreateUnit(server, bridge) {
|
|
|
19
19
|
server.registerTool('create_unit', {
|
|
20
20
|
title: 'Create unit',
|
|
21
21
|
description: 'Create a named unit in a building, optionally referencing zones across its levels.',
|
|
22
|
-
inputSchema: createUnitInput,
|
|
23
|
-
outputSchema: createUnitOutput,
|
|
22
|
+
inputSchema: z.object(createUnitInput),
|
|
23
|
+
outputSchema: z.object(createUnitOutput),
|
|
24
24
|
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
25
25
|
}, async ({ buildingId, name, kind, color, memberZoneIds }) => {
|
|
26
26
|
const members = validateUnitMembers(bridge, buildingId, memberZoneIds ?? []);
|
package/dist/tools/errors.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server';
|
|
2
2
|
/**
|
|
3
|
-
* Throw a structured MCP error. The SDK translates `
|
|
3
|
+
* Throw a structured MCP error. The SDK translates `ProtocolError` into a
|
|
4
4
|
* JSON-RPC error response automatically.
|
|
5
5
|
*/
|
|
6
|
-
export declare function throwMcpError(code:
|
|
6
|
+
export declare function throwMcpError(code: ProtocolErrorCode, message: string, data?: unknown): never;
|
|
7
7
|
/**
|
|
8
8
|
* Return a non-throwing tool error payload — used for structured failures that
|
|
9
9
|
* we want the client to see inline in `content` rather than as a protocol
|
|
@@ -16,5 +16,16 @@ export declare function toolError(message: string, data?: Record<string, unknown
|
|
|
16
16
|
}[];
|
|
17
17
|
isError: true;
|
|
18
18
|
};
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* A core operation's refusal (`AgentRefusal`) as the same `{ error, code, ...details }` answer the
|
|
21
|
+
* hosted chat returns; anything else is a real failure and is rethrown.
|
|
22
|
+
*/
|
|
23
|
+
export declare function refusalResult(error: unknown): {
|
|
24
|
+
content: {
|
|
25
|
+
type: 'text';
|
|
26
|
+
text: string;
|
|
27
|
+
}[];
|
|
28
|
+
isError: true;
|
|
29
|
+
};
|
|
30
|
+
export { ProtocolError, ProtocolErrorCode };
|
|
20
31
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/tools/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/tools/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAG/E;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,CAE7F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B;IACD,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACzC,OAAO,EAAE,IAAI,CAAA;CACd,CAUA;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO;aAlBjC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE;aAChC,IAAI;EAoBd;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,CAAA"}
|