@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.
- package/CHANGELOG.md +39 -0
- package/README.md +330 -0
- package/dist/bin/pascal-mcp.d.ts +3 -0
- package/dist/bin/pascal-mcp.d.ts.map +1 -0
- package/dist/bin/pascal-mcp.js +91 -0
- package/dist/bridge/index.d.ts +3 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +1 -0
- package/dist/bridge/node-shims.d.ts +16 -0
- package/dist/bridge/node-shims.d.ts.map +1 -0
- package/dist/bridge/node-shims.js +25 -0
- package/dist/bridge/scene-bridge.d.ts +158 -0
- package/dist/bridge/scene-bridge.d.ts.map +1 -0
- package/dist/bridge/scene-bridge.js +482 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/lib/rehydrate-site-children.d.ts +12 -0
- package/dist/lib/rehydrate-site-children.d.ts.map +1 -0
- package/dist/lib/rehydrate-site-children.js +40 -0
- package/dist/lib/safe-fetch.d.ts +19 -0
- package/dist/lib/safe-fetch.d.ts.map +1 -0
- package/dist/lib/safe-fetch.js +221 -0
- package/dist/operations/index.d.ts +2 -0
- package/dist/operations/index.d.ts.map +1 -0
- package/dist/operations/index.js +1 -0
- package/dist/operations/scene-operations.d.ts +67 -0
- package/dist/operations/scene-operations.d.ts.map +1 -0
- package/dist/operations/scene-operations.js +192 -0
- package/dist/prompts/from-brief.d.ts +11 -0
- package/dist/prompts/from-brief.d.ts.map +1 -0
- package/dist/prompts/from-brief.js +48 -0
- package/dist/prompts/index.d.ts +10 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +14 -0
- package/dist/prompts/iterate-on-feedback.d.ts +11 -0
- package/dist/prompts/iterate-on-feedback.d.ts.map +1 -0
- package/dist/prompts/iterate-on-feedback.js +41 -0
- package/dist/prompts/renovation-from-photos.d.ts +24 -0
- package/dist/prompts/renovation-from-photos.d.ts.map +1 -0
- package/dist/prompts/renovation-from-photos.js +135 -0
- package/dist/prompts/scene-guidance.d.ts +2 -0
- package/dist/prompts/scene-guidance.d.ts.map +1 -0
- package/dist/prompts/scene-guidance.js +24 -0
- package/dist/resources/agent-guide.d.ts +5 -0
- package/dist/resources/agent-guide.d.ts.map +1 -0
- package/dist/resources/agent-guide.js +85 -0
- package/dist/resources/catalog-items.d.ts +10 -0
- package/dist/resources/catalog-items.d.ts.map +1 -0
- package/dist/resources/catalog-items.js +29 -0
- package/dist/resources/constraints.d.ts +9 -0
- package/dist/resources/constraints.d.ts.map +1 -0
- package/dist/resources/constraints.js +69 -0
- package/dist/resources/index.d.ts +15 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +23 -0
- package/dist/resources/scene-current.d.ts +9 -0
- package/dist/resources/scene-current.d.ts.map +1 -0
- package/dist/resources/scene-current.js +20 -0
- package/dist/resources/scene-summary.d.ts +10 -0
- package/dist/resources/scene-summary.d.ts.map +1 -0
- package/dist/resources/scene-summary.js +196 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +18 -0
- package/dist/storage/index.d.ts +13 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +14 -0
- package/dist/storage/slug.d.ts +21 -0
- package/dist/storage/slug.d.ts.map +1 -0
- package/dist/storage/slug.js +62 -0
- package/dist/storage/sqlite-driver.d.ts +18 -0
- package/dist/storage/sqlite-driver.d.ts.map +1 -0
- package/dist/storage/sqlite-driver.js +32 -0
- package/dist/storage/sqlite-scene-store.d.ts +51 -0
- package/dist/storage/sqlite-scene-store.d.ts.map +1 -0
- package/dist/storage/sqlite-scene-store.js +526 -0
- package/dist/storage/types.d.ts +136 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +28 -0
- package/dist/templates/empty-studio.d.ts +8 -0
- package/dist/templates/empty-studio.d.ts.map +1 -0
- package/dist/templates/empty-studio.js +230 -0
- package/dist/templates/garden-house.d.ts +8 -0
- package/dist/templates/garden-house.d.ts.map +1 -0
- package/dist/templates/garden-house.js +242 -0
- package/dist/templates/index.d.ts +23 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +20 -0
- package/dist/templates/two-bedroom.d.ts +8 -0
- package/dist/templates/two-bedroom.d.ts.map +1 -0
- package/dist/templates/two-bedroom.js +270 -0
- package/dist/tools/apply-patch.d.ts +25 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +59 -0
- package/dist/tools/asset-catalog.d.ts +16 -0
- package/dist/tools/asset-catalog.d.ts.map +1 -0
- package/dist/tools/asset-catalog.js +308 -0
- package/dist/tools/check-collisions.d.ts +15 -0
- package/dist/tools/check-collisions.d.ts.map +1 -0
- package/dist/tools/check-collisions.js +61 -0
- package/dist/tools/construction-tools.d.ts +93 -0
- package/dist/tools/construction-tools.d.ts.map +1 -0
- package/dist/tools/construction-tools.js +369 -0
- package/dist/tools/create-level.d.ts +14 -0
- package/dist/tools/create-level.d.ts.map +1 -0
- package/dist/tools/create-level.js +48 -0
- package/dist/tools/create-wall.d.ts +15 -0
- package/dist/tools/create-wall.d.ts.map +1 -0
- package/dist/tools/create-wall.js +50 -0
- package/dist/tools/cut-opening.d.ts +18 -0
- package/dist/tools/cut-opening.d.ts.map +1 -0
- package/dist/tools/cut-opening.js +57 -0
- package/dist/tools/delete-node.d.ts +12 -0
- package/dist/tools/delete-node.d.ts.map +1 -0
- package/dist/tools/delete-node.js +37 -0
- package/dist/tools/describe-node.d.ts +17 -0
- package/dist/tools/describe-node.d.ts.map +1 -0
- package/dist/tools/describe-node.js +86 -0
- package/dist/tools/duplicate-level.d.ts +12 -0
- package/dist/tools/duplicate-level.d.ts.map +1 -0
- package/dist/tools/duplicate-level.js +56 -0
- package/dist/tools/errors.d.ts +20 -0
- package/dist/tools/errors.d.ts.map +1 -0
- package/dist/tools/errors.js +25 -0
- package/dist/tools/export-glb.d.ts +10 -0
- package/dist/tools/export-glb.d.ts.map +1 -0
- package/dist/tools/export-glb.js +24 -0
- package/dist/tools/export-json.d.ts +11 -0
- package/dist/tools/export-json.d.ts.map +1 -0
- package/dist/tools/export-json.js +23 -0
- package/dist/tools/find-nodes.d.ts +32 -0
- package/dist/tools/find-nodes.d.ts.map +1 -0
- package/dist/tools/find-nodes.js +105 -0
- package/dist/tools/geometry.d.ts +24 -0
- package/dist/tools/geometry.d.ts.map +1 -0
- package/dist/tools/geometry.js +94 -0
- package/dist/tools/get-node.d.ts +11 -0
- package/dist/tools/get-node.d.ts.map +1 -0
- package/dist/tools/get-node.js +27 -0
- package/dist/tools/get-scene.d.ts +11 -0
- package/dist/tools/get-scene.d.ts.map +1 -0
- package/dist/tools/get-scene.js +26 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +64 -0
- package/dist/tools/live-sync.d.ts +11 -0
- package/dist/tools/live-sync.d.ts.map +1 -0
- package/dist/tools/live-sync.js +62 -0
- package/dist/tools/measure.d.ts +14 -0
- package/dist/tools/measure.d.ts.map +1 -0
- package/dist/tools/measure.js +137 -0
- package/dist/tools/photo-to-scene/index.d.ts +11 -0
- package/dist/tools/photo-to-scene/index.d.ts.map +1 -0
- package/dist/tools/photo-to-scene/index.js +11 -0
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts +26 -0
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -0
- package/dist/tools/photo-to-scene/photo-to-scene.js +323 -0
- package/dist/tools/place-item.d.ts +15 -0
- package/dist/tools/place-item.d.ts.map +1 -0
- package/dist/tools/place-item.js +84 -0
- package/dist/tools/redo.d.ts +11 -0
- package/dist/tools/redo.d.ts.map +1 -0
- package/dist/tools/redo.js +25 -0
- package/dist/tools/room-tools.d.ts +97 -0
- package/dist/tools/room-tools.d.ts.map +1 -0
- package/dist/tools/room-tools.js +510 -0
- package/dist/tools/scene-lifecycle/create-project.d.ts +33 -0
- package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/create-project.js +70 -0
- package/dist/tools/scene-lifecycle/delete-scene.d.ts +12 -0
- package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/delete-scene.js +42 -0
- package/dist/tools/scene-lifecycle/get-project-status.d.ts +31 -0
- package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/get-project-status.js +69 -0
- package/dist/tools/scene-lifecycle/index.d.ts +17 -0
- package/dist/tools/scene-lifecycle/index.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/index.js +29 -0
- package/dist/tools/scene-lifecycle/list-scenes.d.ts +27 -0
- package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/list-scenes.js +49 -0
- package/dist/tools/scene-lifecycle/load-scene.d.ts +31 -0
- package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/load-scene.js +55 -0
- package/dist/tools/scene-lifecycle/metadata.d.ts +49 -0
- package/dist/tools/scene-lifecycle/metadata.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/metadata.js +68 -0
- package/dist/tools/scene-lifecycle/rename-scene.d.ts +22 -0
- package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/rename-scene.js +63 -0
- package/dist/tools/scene-lifecycle/save-scene.d.ts +42 -0
- package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/save-scene.js +130 -0
- package/dist/tools/scene-lifecycle/test-utils.d.ts +39 -0
- package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -0
- package/dist/tools/scene-lifecycle/test-utils.js +211 -0
- package/dist/tools/scene-query.d.ts +57 -0
- package/dist/tools/scene-query.d.ts.map +1 -0
- package/dist/tools/scene-query.js +645 -0
- package/dist/tools/schemas.d.ts +52 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +42 -0
- package/dist/tools/set-zone.d.ts +14 -0
- package/dist/tools/set-zone.d.ts.map +1 -0
- package/dist/tools/set-zone.js +48 -0
- package/dist/tools/templates/create-from-template.d.ts +54 -0
- package/dist/tools/templates/create-from-template.d.ts.map +1 -0
- package/dist/tools/templates/create-from-template.js +145 -0
- package/dist/tools/templates/create-house-from-brief.d.ts +35 -0
- package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -0
- package/dist/tools/templates/create-house-from-brief.js +170 -0
- package/dist/tools/templates/index.d.ts +14 -0
- package/dist/tools/templates/index.d.ts.map +1 -0
- package/dist/tools/templates/index.js +18 -0
- package/dist/tools/templates/list-templates.d.ts +18 -0
- package/dist/tools/templates/list-templates.d.ts.map +1 -0
- package/dist/tools/templates/list-templates.js +36 -0
- package/dist/tools/undo.d.ts +11 -0
- package/dist/tools/undo.d.ts.map +1 -0
- package/dist/tools/undo.js +25 -0
- package/dist/tools/validate-scene.d.ts +14 -0
- package/dist/tools/validate-scene.d.ts.map +1 -0
- package/dist/tools/validate-scene.js +24 -0
- package/dist/tools/variants/generate-variants.d.ts +30 -0
- package/dist/tools/variants/generate-variants.d.ts.map +1 -0
- package/dist/tools/variants/generate-variants.js +160 -0
- package/dist/tools/variants/index.d.ts +9 -0
- package/dist/tools/variants/index.d.ts.map +1 -0
- package/dist/tools/variants/index.js +9 -0
- package/dist/tools/variants/mutations.d.ts +18 -0
- package/dist/tools/variants/mutations.d.ts.map +1 -0
- package/dist/tools/variants/mutations.js +324 -0
- package/dist/tools/vision/analyze-floorplan-image.d.ts +33 -0
- package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -0
- package/dist/tools/vision/analyze-floorplan-image.js +146 -0
- package/dist/tools/vision/analyze-room-photo.d.ts +29 -0
- package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -0
- package/dist/tools/vision/analyze-room-photo.js +130 -0
- package/dist/tools/vision/index.d.ts +12 -0
- package/dist/tools/vision/index.d.ts.map +1 -0
- package/dist/tools/vision/index.js +14 -0
- package/dist/transports/http.d.ts +36 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +203 -0
- package/dist/transports/stdio.d.ts +14 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +16 -0
- package/package.json +86 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { AnyNode, BuildingNode, LevelNode, SiteNode, WallNode, ZoneNode, } from '@pascal-app/core/schema';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { appendLiveSceneEvent } from '../live-sync';
|
|
5
|
+
/**
|
|
6
|
+
* Input shape for the `photo_to_scene` orchestrator. `image` matches the
|
|
7
|
+
* contract documented on `analyze_floorplan_image` — base64 or http(s) URL.
|
|
8
|
+
*/
|
|
9
|
+
export const photoToSceneInput = {
|
|
10
|
+
image: z.string().describe('Base64 or https URL of the floor-plan photo'),
|
|
11
|
+
scaleHint: z.string().optional().describe('e.g. "1 cm = 1 m" or "approx 80 m²"'),
|
|
12
|
+
name: z.string().default('Scene from photo'),
|
|
13
|
+
save: z.boolean().default(true),
|
|
14
|
+
defaultWallThickness: z.number().default(0.2),
|
|
15
|
+
defaultWallHeight: z.number().default(2.6),
|
|
16
|
+
};
|
|
17
|
+
export const photoToSceneOutput = {
|
|
18
|
+
sceneId: z.string().optional(),
|
|
19
|
+
url: z.string().optional(),
|
|
20
|
+
walls: z.number(),
|
|
21
|
+
rooms: z.number(),
|
|
22
|
+
confidence: z.number(),
|
|
23
|
+
notes: z.string().optional(),
|
|
24
|
+
graph: z.any().optional(),
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Shape of the vision JSON we consume. Kept in-sync with
|
|
28
|
+
* `analyze_floorplan_image`'s output schema (walls / rooms /
|
|
29
|
+
* approximateDimensions / confidence).
|
|
30
|
+
*/
|
|
31
|
+
const VisionResponseSchema = z.object({
|
|
32
|
+
walls: z.array(z.object({
|
|
33
|
+
start: z.tuple([z.number(), z.number()]),
|
|
34
|
+
end: z.tuple([z.number(), z.number()]),
|
|
35
|
+
thickness: z.number().optional(),
|
|
36
|
+
})),
|
|
37
|
+
rooms: z.array(z.object({
|
|
38
|
+
name: z.string(),
|
|
39
|
+
polygon: z.array(z.tuple([z.number(), z.number()])),
|
|
40
|
+
approximateAreaSqM: z.number().optional(),
|
|
41
|
+
})),
|
|
42
|
+
approximateDimensions: z.object({
|
|
43
|
+
widthM: z.number(),
|
|
44
|
+
depthM: z.number(),
|
|
45
|
+
}),
|
|
46
|
+
confidence: z.number().min(0).max(1),
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* System prompt mirrors `analyze_floorplan_image` — the contract between
|
|
50
|
+
* orchestrator and host is identical, so we keep the prompt verbatim to
|
|
51
|
+
* guarantee wire-compatible responses.
|
|
52
|
+
*/
|
|
53
|
+
const SYSTEM_PROMPT = `You are a vision assistant that extracts structured floor-plan data from an image.
|
|
54
|
+
Your ONLY job: return a JSON object that exactly matches this schema — no prose, no markdown fences.
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
"walls": [{ "start": [x, z], "end": [x, z], "thickness": number? }, ...],
|
|
58
|
+
"rooms": [{ "name": string, "polygon": [[x,z], ...], "approximateAreaSqM": number? }, ...],
|
|
59
|
+
"approximateDimensions": { "widthM": number, "depthM": number },
|
|
60
|
+
"confidence": number 0..1
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Coordinates are in metres. Origin can be the floor plan's centre or bottom-left — be consistent.
|
|
64
|
+
If the image is unclear, lower the confidence score but still produce your best attempt.
|
|
65
|
+
DO NOT wrap the JSON in markdown. DO NOT explain. Just output the raw JSON.`;
|
|
66
|
+
const DATA_URI_RE = /^data:(image\/[a-z0-9.+-]+);base64,(.+)$/i;
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the `image` input into a sampling-ready image block. Follows the
|
|
69
|
+
* same fetch/data-uri/raw-base64 rules as the vision tool so the user gets
|
|
70
|
+
* consistent behaviour whether they call `photo_to_scene` or
|
|
71
|
+
* `analyze_floorplan_image` directly.
|
|
72
|
+
*/
|
|
73
|
+
async function resolveImageBlock(image) {
|
|
74
|
+
if (/^https?:\/\//i.test(image)) {
|
|
75
|
+
// SSRF-safe fetch (see packages/mcp/src/lib/safe-fetch.ts).
|
|
76
|
+
const { safeFetch } = await import('../../lib/safe-fetch');
|
|
77
|
+
const res = await safeFetch(image, { accept: 'image/*' });
|
|
78
|
+
const data = res.buffer.toString('base64');
|
|
79
|
+
const mimeType = res.contentType ?? 'image/jpeg';
|
|
80
|
+
return { type: 'image', data, mimeType };
|
|
81
|
+
}
|
|
82
|
+
const dataUriMatch = image.match(DATA_URI_RE);
|
|
83
|
+
if (dataUriMatch) {
|
|
84
|
+
return {
|
|
85
|
+
type: 'image',
|
|
86
|
+
mimeType: dataUriMatch[1],
|
|
87
|
+
data: dataUriMatch[2],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return { type: 'image', mimeType: 'image/jpeg', data: image };
|
|
91
|
+
}
|
|
92
|
+
/** Collect all text content blocks returned by the sampling host into one string. */
|
|
93
|
+
function extractText(content) {
|
|
94
|
+
const blocks = Array.isArray(content) ? content : [content];
|
|
95
|
+
const texts = [];
|
|
96
|
+
for (const block of blocks) {
|
|
97
|
+
if (block && typeof block === 'object' && block.type === 'text') {
|
|
98
|
+
const t = block.text;
|
|
99
|
+
if (typeof t === 'string')
|
|
100
|
+
texts.push(t);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return texts.join('\n').trim();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Call the host's sampling capability to analyse a floor-plan photo. Throws
|
|
107
|
+
* `sampling_unavailable` when the host has not advertised the capability and
|
|
108
|
+
* `sampling_response_unparseable` / `sampling_response_invalid` when the
|
|
109
|
+
* reply cannot be mapped onto `VisionResponseSchema`.
|
|
110
|
+
*/
|
|
111
|
+
async function callVisionSampling(server, image, scaleHint) {
|
|
112
|
+
const caps = server.server.getClientCapabilities();
|
|
113
|
+
if (!caps?.sampling) {
|
|
114
|
+
throw new McpError(ErrorCode.InvalidRequest, 'sampling_unavailable');
|
|
115
|
+
}
|
|
116
|
+
const imageBlock = await resolveImageBlock(image);
|
|
117
|
+
const instruction = scaleHint
|
|
118
|
+
? `Analyze this floor plan. Scale hint: ${scaleHint}. Return ONLY the JSON described by the system prompt.`
|
|
119
|
+
: 'Analyze this floor plan. Return ONLY the JSON described by the system prompt.';
|
|
120
|
+
const response = await server.server.createMessage({
|
|
121
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
122
|
+
temperature: 0,
|
|
123
|
+
maxTokens: 2000,
|
|
124
|
+
messages: [
|
|
125
|
+
{
|
|
126
|
+
role: 'user',
|
|
127
|
+
content: [imageBlock, { type: 'text', text: instruction }],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
const text = extractText(response.content);
|
|
132
|
+
if (!text) {
|
|
133
|
+
throw new McpError(ErrorCode.InternalError, 'sampling_response_unparseable', {
|
|
134
|
+
reason: 'no text content returned by host',
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
let parsed;
|
|
138
|
+
try {
|
|
139
|
+
parsed = JSON.parse(text);
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
throw new McpError(ErrorCode.InternalError, 'sampling_response_unparseable', {
|
|
143
|
+
raw: text,
|
|
144
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
const validation = VisionResponseSchema.safeParse(parsed);
|
|
148
|
+
if (!validation.success) {
|
|
149
|
+
throw new McpError(ErrorCode.InternalError, 'sampling_response_invalid', {
|
|
150
|
+
raw: text,
|
|
151
|
+
errors: validation.error.issues,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return validation.data;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Build a SceneGraph (flat `nodes` dict + `rootNodeIds`) from the vision
|
|
158
|
+
* response. Uses the schema factories for every node so IDs, defaults, and
|
|
159
|
+
* parent linkage match what the core store would produce. Each node is
|
|
160
|
+
* revalidated via `AnyNode.safeParse`; failures are dropped with a warning.
|
|
161
|
+
*/
|
|
162
|
+
function buildSceneGraphFromVision(vision, defaultWallThickness, defaultWallHeight) {
|
|
163
|
+
const warnings = [];
|
|
164
|
+
// Build the skeleton: site → building → level.
|
|
165
|
+
const building = BuildingNode.parse({});
|
|
166
|
+
const level = LevelNode.parse({ level: 0 });
|
|
167
|
+
const site = SiteNode.parse({ children: [building] });
|
|
168
|
+
// Link parent ids so downstream traversal works.
|
|
169
|
+
const siteId = site.id;
|
|
170
|
+
const buildingId = building.id;
|
|
171
|
+
const levelId = level.id;
|
|
172
|
+
const linkedBuilding = {
|
|
173
|
+
...building,
|
|
174
|
+
parentId: siteId,
|
|
175
|
+
};
|
|
176
|
+
const linkedLevel = {
|
|
177
|
+
...level,
|
|
178
|
+
parentId: buildingId,
|
|
179
|
+
};
|
|
180
|
+
linkedBuilding.children = [levelId];
|
|
181
|
+
// Collect level children (ids of walls/zones we create below).
|
|
182
|
+
const levelChildren = [];
|
|
183
|
+
const nodes = {};
|
|
184
|
+
// Validate + add site, building, level in that order.
|
|
185
|
+
const siteValidated = AnyNode.safeParse(site);
|
|
186
|
+
if (!siteValidated.success) {
|
|
187
|
+
warnings.push(`site node failed schema validation: ${siteValidated.error.message}`);
|
|
188
|
+
}
|
|
189
|
+
nodes[siteId] = (siteValidated.success ? siteValidated.data : site);
|
|
190
|
+
const buildingValidated = AnyNode.safeParse(linkedBuilding);
|
|
191
|
+
if (!buildingValidated.success) {
|
|
192
|
+
warnings.push(`building node failed schema validation: ${buildingValidated.error.message}`);
|
|
193
|
+
}
|
|
194
|
+
nodes[buildingId] = (buildingValidated.success ? buildingValidated.data : linkedBuilding);
|
|
195
|
+
// Walls.
|
|
196
|
+
let wallsAdded = 0;
|
|
197
|
+
for (let i = 0; i < vision.walls.length; i++) {
|
|
198
|
+
const w = vision.walls[i];
|
|
199
|
+
try {
|
|
200
|
+
const wall = WallNode.parse({
|
|
201
|
+
start: w.start,
|
|
202
|
+
end: w.end,
|
|
203
|
+
thickness: w.thickness ?? defaultWallThickness,
|
|
204
|
+
height: defaultWallHeight,
|
|
205
|
+
});
|
|
206
|
+
const linkedWall = {
|
|
207
|
+
...wall,
|
|
208
|
+
parentId: levelId,
|
|
209
|
+
};
|
|
210
|
+
const validated = AnyNode.safeParse(linkedWall);
|
|
211
|
+
if (!validated.success) {
|
|
212
|
+
warnings.push(`wall[${i}] dropped: ${validated.error.message}`);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
nodes[wall.id] = validated.data;
|
|
216
|
+
levelChildren.push(wall.id);
|
|
217
|
+
wallsAdded++;
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
221
|
+
warnings.push(`wall[${i}] dropped: ${msg}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Rooms → zones.
|
|
225
|
+
let roomsAdded = 0;
|
|
226
|
+
for (let i = 0; i < vision.rooms.length; i++) {
|
|
227
|
+
const r = vision.rooms[i];
|
|
228
|
+
try {
|
|
229
|
+
const zone = ZoneNode.parse({
|
|
230
|
+
name: r.name,
|
|
231
|
+
polygon: r.polygon,
|
|
232
|
+
});
|
|
233
|
+
const linkedZone = {
|
|
234
|
+
...zone,
|
|
235
|
+
parentId: levelId,
|
|
236
|
+
};
|
|
237
|
+
const validated = AnyNode.safeParse(linkedZone);
|
|
238
|
+
if (!validated.success) {
|
|
239
|
+
warnings.push(`room[${i}] dropped: ${validated.error.message}`);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
nodes[zone.id] = validated.data;
|
|
243
|
+
levelChildren.push(zone.id);
|
|
244
|
+
roomsAdded++;
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
248
|
+
warnings.push(`room[${i}] dropped: ${msg}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Finalise the level's children array now that walls/zones are in the dict.
|
|
252
|
+
;
|
|
253
|
+
linkedLevel.children = levelChildren;
|
|
254
|
+
const levelValidated = AnyNode.safeParse(linkedLevel);
|
|
255
|
+
if (!levelValidated.success) {
|
|
256
|
+
warnings.push(`level node failed schema validation: ${levelValidated.error.message}`);
|
|
257
|
+
}
|
|
258
|
+
nodes[levelId] = (levelValidated.success ? levelValidated.data : linkedLevel);
|
|
259
|
+
return {
|
|
260
|
+
nodes,
|
|
261
|
+
rootNodeIds: [siteId],
|
|
262
|
+
walls: wallsAdded,
|
|
263
|
+
rooms: roomsAdded,
|
|
264
|
+
warnings,
|
|
265
|
+
levelId,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
export function registerPhotoToScene(server, bridge) {
|
|
269
|
+
server.registerTool('photo_to_scene', {
|
|
270
|
+
title: 'Photo to Pascal scene',
|
|
271
|
+
description: 'Orchestrator: analyse a floor-plan photo via MCP sampling, translate the structured vision result into a Pascal SceneGraph (site → building → level with walls and zones), optionally save it, and swap the bridge to the new scene. Requires host support for sampling.',
|
|
272
|
+
inputSchema: photoToSceneInput,
|
|
273
|
+
outputSchema: photoToSceneOutput,
|
|
274
|
+
}, async ({ image, scaleHint, name, save, defaultWallThickness, defaultWallHeight }) => {
|
|
275
|
+
// 1. Vision.
|
|
276
|
+
const vision = await callVisionSampling(server, image, scaleHint);
|
|
277
|
+
// 2. Build scene graph.
|
|
278
|
+
const built = buildSceneGraphFromVision(vision, defaultWallThickness, defaultWallHeight);
|
|
279
|
+
const graph = {
|
|
280
|
+
nodes: built.nodes,
|
|
281
|
+
rootNodeIds: built.rootNodeIds,
|
|
282
|
+
collections: {},
|
|
283
|
+
};
|
|
284
|
+
// 5. Swap the bridge to the new scene so follow-up MCP calls operate on it.
|
|
285
|
+
bridge.setScene(graph.nodes, graph.rootNodeIds);
|
|
286
|
+
const notes = built.warnings.length > 0 ? built.warnings.join('; ') : undefined;
|
|
287
|
+
// 4. Save or return inline.
|
|
288
|
+
if (save) {
|
|
289
|
+
const meta = await bridge.saveScene({
|
|
290
|
+
name,
|
|
291
|
+
graph,
|
|
292
|
+
});
|
|
293
|
+
bridge.setActiveScene(meta);
|
|
294
|
+
await appendLiveSceneEvent(bridge, meta.id, meta.version, 'photo_to_scene', graph);
|
|
295
|
+
const payload = {
|
|
296
|
+
sceneId: meta.id,
|
|
297
|
+
url: `/scene/${meta.id}`,
|
|
298
|
+
walls: built.walls,
|
|
299
|
+
rooms: built.rooms,
|
|
300
|
+
confidence: vision.confidence,
|
|
301
|
+
};
|
|
302
|
+
if (notes)
|
|
303
|
+
payload.notes = notes;
|
|
304
|
+
return {
|
|
305
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
306
|
+
structuredContent: payload,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
const payload = {
|
|
310
|
+
walls: built.walls,
|
|
311
|
+
rooms: built.rooms,
|
|
312
|
+
confidence: vision.confidence,
|
|
313
|
+
graph,
|
|
314
|
+
};
|
|
315
|
+
bridge.clearActiveScene();
|
|
316
|
+
if (notes)
|
|
317
|
+
payload.notes = notes;
|
|
318
|
+
return {
|
|
319
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
320
|
+
structuredContent: payload,
|
|
321
|
+
};
|
|
322
|
+
});
|
|
323
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
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 placeItemInput: {
|
|
5
|
+
catalogItemId: z.ZodString;
|
|
6
|
+
targetNodeId: z.ZodString;
|
|
7
|
+
position: z.ZodArray<z.ZodNumber>;
|
|
8
|
+
rotation: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
};
|
|
10
|
+
export declare const placeItemOutput: {
|
|
11
|
+
itemId: z.ZodString;
|
|
12
|
+
status: z.ZodOptional<z.ZodString>;
|
|
13
|
+
};
|
|
14
|
+
export declare function registerPlaceItem(server: McpServer, bridge: SceneOperations): void;
|
|
15
|
+
//# sourceMappingURL=place-item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"place-item.d.ts","sourceRoot":"","sources":["../../src/tools/place-item.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,cAAc;;;;;CAK1B,CAAA;AAED,eAAO,MAAM,eAAe;;;CAG3B,CAAA;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAsFlF"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ItemNode } from '@pascal-app/core/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { findCatalogItem } from './asset-catalog';
|
|
4
|
+
import { ErrorCode, throwMcpError } from './errors';
|
|
5
|
+
import { projectWorldPointToWallLocalX, wallLength } from './geometry';
|
|
6
|
+
import { publishLiveSceneSnapshot } from './live-sync';
|
|
7
|
+
import { NodeIdSchema, Vec3Schema } from './schemas';
|
|
8
|
+
export const placeItemInput = {
|
|
9
|
+
catalogItemId: z.string().min(1),
|
|
10
|
+
targetNodeId: NodeIdSchema,
|
|
11
|
+
position: Vec3Schema,
|
|
12
|
+
rotation: z.number().optional(),
|
|
13
|
+
};
|
|
14
|
+
export const placeItemOutput = {
|
|
15
|
+
itemId: z.string(),
|
|
16
|
+
status: z.string().optional(),
|
|
17
|
+
};
|
|
18
|
+
export function registerPlaceItem(server, bridge) {
|
|
19
|
+
server.registerTool('place_item', {
|
|
20
|
+
title: 'Place item',
|
|
21
|
+
description: 'Place a catalog item into the scene. Target a level/slab/zone for floor items, a wall for wall-attached items, or a ceiling for ceiling-attached items. Do not target the site node directly.',
|
|
22
|
+
inputSchema: placeItemInput,
|
|
23
|
+
outputSchema: placeItemOutput,
|
|
24
|
+
}, async ({ catalogItemId, targetNodeId, position, rotation }) => {
|
|
25
|
+
const target = bridge.getNode(targetNodeId);
|
|
26
|
+
if (!target) {
|
|
27
|
+
throwMcpError(ErrorCode.InvalidParams, `Target node not found: ${targetNodeId}`);
|
|
28
|
+
}
|
|
29
|
+
const targetType = target.type;
|
|
30
|
+
if (targetType !== 'level' &&
|
|
31
|
+
targetType !== 'slab' &&
|
|
32
|
+
targetType !== 'zone' &&
|
|
33
|
+
targetType !== 'wall' &&
|
|
34
|
+
targetType !== 'ceiling') {
|
|
35
|
+
throwMcpError(ErrorCode.InvalidRequest, `Cannot place item on ${targetType}; target must be a level, slab, zone, wall, or ceiling. Site-level placement is not supported yet because site.children is reserved for buildings.`);
|
|
36
|
+
}
|
|
37
|
+
const catalogAsset = findCatalogItem(catalogItemId);
|
|
38
|
+
const baseAsset = catalogAsset ?? {
|
|
39
|
+
id: catalogItemId,
|
|
40
|
+
name: catalogItemId,
|
|
41
|
+
category: 'unknown',
|
|
42
|
+
thumbnail: '',
|
|
43
|
+
src: 'asset://placeholder',
|
|
44
|
+
dimensions: [0.5, 0.5, 0.5],
|
|
45
|
+
offset: [0, 0, 0],
|
|
46
|
+
rotation: [0, 0, 0],
|
|
47
|
+
scale: [1, 1, 1],
|
|
48
|
+
};
|
|
49
|
+
const requestedPosition = position;
|
|
50
|
+
const parentId = targetType === 'slab' || targetType === 'zone'
|
|
51
|
+
? bridge.resolveLevelId(targetNodeId)
|
|
52
|
+
: targetNodeId;
|
|
53
|
+
if (!parentId) {
|
|
54
|
+
throwMcpError(ErrorCode.InvalidParams, `Could not resolve a level parent for target ${targetNodeId}`);
|
|
55
|
+
}
|
|
56
|
+
const wallExtras = {};
|
|
57
|
+
let itemPosition = requestedPosition;
|
|
58
|
+
if (targetType === 'wall') {
|
|
59
|
+
const localX = projectWorldPointToWallLocalX(target, requestedPosition);
|
|
60
|
+
const length = wallLength(target);
|
|
61
|
+
itemPosition = [localX, requestedPosition[1], 0];
|
|
62
|
+
Object.assign(wallExtras, {
|
|
63
|
+
wallId: targetNodeId,
|
|
64
|
+
wallT: length === 0 ? 0 : localX / length,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const item = ItemNode.parse({
|
|
68
|
+
position: itemPosition,
|
|
69
|
+
rotation: [0, rotation ?? 0, 0],
|
|
70
|
+
asset: baseAsset,
|
|
71
|
+
...wallExtras,
|
|
72
|
+
});
|
|
73
|
+
const id = bridge.createNode(item, parentId);
|
|
74
|
+
await publishLiveSceneSnapshot(bridge, 'place_item');
|
|
75
|
+
const payload = {
|
|
76
|
+
itemId: id,
|
|
77
|
+
status: catalogAsset ? 'ok' : 'catalog_unavailable',
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
81
|
+
structuredContent: payload,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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 redoInput: {
|
|
5
|
+
steps: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
};
|
|
7
|
+
export declare const redoOutput: {
|
|
8
|
+
redone: z.ZodNumber;
|
|
9
|
+
};
|
|
10
|
+
export declare function registerRedo(server: McpServer, bridge: SceneOperations): void;
|
|
11
|
+
//# sourceMappingURL=redo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redo.d.ts","sourceRoot":"","sources":["../../src/tools/redo.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;AAGpD,eAAO,MAAM,SAAS;;CAErB,CAAA;AAED,eAAO,MAAM,UAAU;;CAEtB,CAAA;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAoB7E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { publishLiveSceneSnapshot } from './live-sync';
|
|
3
|
+
export const redoInput = {
|
|
4
|
+
steps: z.number().int().positive().optional(),
|
|
5
|
+
};
|
|
6
|
+
export const redoOutput = {
|
|
7
|
+
redone: z.number(),
|
|
8
|
+
};
|
|
9
|
+
export function registerRedo(server, bridge) {
|
|
10
|
+
server.registerTool('redo', {
|
|
11
|
+
title: 'Redo',
|
|
12
|
+
description: 'Redo the next N previously-undone steps (default 1). Returns the number of steps actually redone.',
|
|
13
|
+
inputSchema: redoInput,
|
|
14
|
+
outputSchema: redoOutput,
|
|
15
|
+
}, async ({ steps }) => {
|
|
16
|
+
const redone = bridge.redo(steps ?? 1);
|
|
17
|
+
if (redone > 0)
|
|
18
|
+
await publishLiveSceneSnapshot(bridge, 'redo');
|
|
19
|
+
const payload = { redone };
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
22
|
+
structuredContent: payload,
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
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 searchAssetsInput: {
|
|
5
|
+
query: z.ZodString;
|
|
6
|
+
category: z.ZodOptional<z.ZodString>;
|
|
7
|
+
};
|
|
8
|
+
export declare const searchAssetsOutput: {
|
|
9
|
+
results: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
10
|
+
total: z.ZodNumber;
|
|
11
|
+
};
|
|
12
|
+
export declare const createRoomInput: {
|
|
13
|
+
levelId: z.ZodString;
|
|
14
|
+
name: z.ZodString;
|
|
15
|
+
polygon: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
16
|
+
color: z.ZodOptional<z.ZodString>;
|
|
17
|
+
wallHeight: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
wallThickness: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
};
|
|
20
|
+
export declare const createRoomOutput: {
|
|
21
|
+
zoneId: z.ZodString;
|
|
22
|
+
slabId: z.ZodString;
|
|
23
|
+
ceilingId: z.ZodString;
|
|
24
|
+
wallIds: z.ZodArray<z.ZodString>;
|
|
25
|
+
areaSqMeters: z.ZodNumber;
|
|
26
|
+
};
|
|
27
|
+
export declare const addDoorInput: {
|
|
28
|
+
wallId: z.ZodString;
|
|
29
|
+
t: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
hingesSide: z.ZodOptional<z.ZodEnum<{
|
|
34
|
+
left: "left";
|
|
35
|
+
right: "right";
|
|
36
|
+
}>>;
|
|
37
|
+
swingDirection: z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
inward: "inward";
|
|
39
|
+
outward: "outward";
|
|
40
|
+
}>>;
|
|
41
|
+
};
|
|
42
|
+
export declare const addDoorOutput: {
|
|
43
|
+
doorId: z.ZodString;
|
|
44
|
+
localX: z.ZodNumber;
|
|
45
|
+
t: z.ZodNumber;
|
|
46
|
+
position: z.ZodNumber;
|
|
47
|
+
wallLength: z.ZodNumber;
|
|
48
|
+
clamped: z.ZodBoolean;
|
|
49
|
+
coordinateSystem: z.ZodLiteral<"wall-local-meters">;
|
|
50
|
+
};
|
|
51
|
+
export declare const addWindowInput: {
|
|
52
|
+
wallId: z.ZodString;
|
|
53
|
+
t: z.ZodOptional<z.ZodNumber>;
|
|
54
|
+
position: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
sillHeight: z.ZodOptional<z.ZodNumber>;
|
|
58
|
+
};
|
|
59
|
+
export declare const addWindowOutput: {
|
|
60
|
+
windowId: z.ZodString;
|
|
61
|
+
localX: z.ZodNumber;
|
|
62
|
+
t: z.ZodNumber;
|
|
63
|
+
position: z.ZodNumber;
|
|
64
|
+
wallLength: z.ZodNumber;
|
|
65
|
+
clamped: z.ZodBoolean;
|
|
66
|
+
coordinateSystem: z.ZodLiteral<"wall-local-meters">;
|
|
67
|
+
sillHeight: z.ZodNumber;
|
|
68
|
+
};
|
|
69
|
+
export declare const furnishRoomInput: {
|
|
70
|
+
levelId: z.ZodOptional<z.ZodString>;
|
|
71
|
+
zoneId: z.ZodOptional<z.ZodString>;
|
|
72
|
+
roomType: z.ZodEnum<{
|
|
73
|
+
bedroom: "bedroom";
|
|
74
|
+
storage: "storage";
|
|
75
|
+
living: "living";
|
|
76
|
+
dining: "dining";
|
|
77
|
+
kitchen: "kitchen";
|
|
78
|
+
bathroom: "bathroom";
|
|
79
|
+
laundry: "laundry";
|
|
80
|
+
entry: "entry";
|
|
81
|
+
hallway: "hallway";
|
|
82
|
+
}>;
|
|
83
|
+
polygon: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodNumber>>>;
|
|
84
|
+
doorWallIndex: z.ZodOptional<z.ZodNumber>;
|
|
85
|
+
};
|
|
86
|
+
export declare const furnishRoomOutput: {
|
|
87
|
+
placed: z.ZodNumber;
|
|
88
|
+
itemIds: z.ZodArray<z.ZodString>;
|
|
89
|
+
skipped: z.ZodArray<z.ZodString>;
|
|
90
|
+
};
|
|
91
|
+
export declare function registerSearchAssets(server: McpServer): void;
|
|
92
|
+
export declare function registerCreateRoom(server: McpServer, bridge: SceneOperations): void;
|
|
93
|
+
export declare function registerAddDoor(server: McpServer, bridge: SceneOperations): void;
|
|
94
|
+
export declare function registerAddWindow(server: McpServer, bridge: SceneOperations): void;
|
|
95
|
+
export declare function registerFurnishRoom(server: McpServer, bridge: SceneOperations): void;
|
|
96
|
+
export declare function registerRoomTools(server: McpServer, bridge: SceneOperations): void;
|
|
97
|
+
//# sourceMappingURL=room-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-tools.d.ts","sourceRoot":"","sources":["../../src/tools/room-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAWxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AA0BpD,eAAO,MAAM,iBAAiB;;;CAG7B,CAAA;AAED,eAAO,MAAM,kBAAkB;;;CAG9B,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;CAO3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;CAM5B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAQxB,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;CAQzB,CAAA;AAED,eAAO,MAAM,cAAc;;;;;;;CAO1B,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;CAS3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;CAM5B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;CAI7B,CAAA;AA+PD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsB5D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqDnF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA2ChF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA0ClF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAsEpF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAMlF"}
|