@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 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/tools/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;GAGG;AAEH,iFAAiF;AACjF,eAAO,MAAM,YAAY,aAAoB,CAAA;AAE7C;;;;GAIG;AACH,eAAO,MAAM,UAAU,yBAAoC,CAAA;AAE3D,6BAA6B;AAC7B,eAAO,MAAM,UAAU,yBAAoC,CAAA;AAE3D;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAA;AAEF,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAA;AAEF,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAA;AAEF,eAAO,MAAM,WAAW;;;;;;;;;;;;yBAItB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Shared Zod schemas used by multiple MCP tools. Keep DRY — if a shape is
|
|
4
|
+
* referenced by more than one tool, define it here.
|
|
5
|
+
*/
|
|
6
|
+
/** A node identifier — non-empty string. The core uses `${prefix}_${nanoid}`. */
|
|
7
|
+
export const NodeIdSchema = z.string().min(1);
|
|
8
|
+
/**
|
|
9
|
+
* 2D point as [x, z] (floor plane). Use array length constraints instead of
|
|
10
|
+
* `z.tuple()` so MCP hosts that only accept JSON Schema's common `items` shape
|
|
11
|
+
* can register the tools.
|
|
12
|
+
*/
|
|
13
|
+
export const Vec2Schema = z.array(z.number()).min(2).max(2);
|
|
14
|
+
/** 3D point as [x, y, z]. */
|
|
15
|
+
export const Vec3Schema = z.array(z.number()).min(3).max(3);
|
|
16
|
+
/**
|
|
17
|
+
* A single patch operation. Union of create / update / delete.
|
|
18
|
+
*
|
|
19
|
+
* For `create`, the node object must include `type` so Zod can discriminate at
|
|
20
|
+
* the bridge layer — we accept a plain object here and let the bridge's Zod
|
|
21
|
+
* re-parse catch structural issues. For `update`, `data` is a partial merge.
|
|
22
|
+
*/
|
|
23
|
+
export const CreatePatchSchema = z.object({
|
|
24
|
+
op: z.literal('create'),
|
|
25
|
+
node: z.record(z.string(), z.unknown()),
|
|
26
|
+
parentId: NodeIdSchema.optional(),
|
|
27
|
+
});
|
|
28
|
+
export const UpdatePatchSchema = z.object({
|
|
29
|
+
op: z.literal('update'),
|
|
30
|
+
id: NodeIdSchema,
|
|
31
|
+
data: z.record(z.string(), z.unknown()),
|
|
32
|
+
});
|
|
33
|
+
export const DeletePatchSchema = z.object({
|
|
34
|
+
op: z.literal('delete'),
|
|
35
|
+
id: NodeIdSchema,
|
|
36
|
+
cascade: z.boolean().optional(),
|
|
37
|
+
});
|
|
38
|
+
export const PatchSchema = z.discriminatedUnion('op', [
|
|
39
|
+
CreatePatchSchema,
|
|
40
|
+
UpdatePatchSchema,
|
|
41
|
+
DeletePatchSchema,
|
|
42
|
+
]);
|
|
@@ -0,0 +1,14 @@
|
|
|
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 setZoneInput: {
|
|
5
|
+
levelId: z.ZodString;
|
|
6
|
+
polygon: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
7
|
+
label: z.ZodString;
|
|
8
|
+
properties: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
9
|
+
};
|
|
10
|
+
export declare const setZoneOutput: {
|
|
11
|
+
zoneId: z.ZodString;
|
|
12
|
+
};
|
|
13
|
+
export declare function registerSetZone(server: McpServer, bridge: SceneOperations): void;
|
|
14
|
+
//# sourceMappingURL=set-zone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-zone.d.ts","sourceRoot":"","sources":["../../src/tools/set-zone.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;AAKpD,eAAO,MAAM,YAAY;;;;;CAKxB,CAAA;AAED,eAAO,MAAM,aAAa;;CAEzB,CAAA;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAgDhF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ZoneNode } from '@pascal-app/core/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { ErrorCode, throwMcpError } from './errors';
|
|
4
|
+
import { publishLiveSceneSnapshot } from './live-sync';
|
|
5
|
+
import { NodeIdSchema, Vec2Schema } from './schemas';
|
|
6
|
+
export const setZoneInput = {
|
|
7
|
+
levelId: NodeIdSchema,
|
|
8
|
+
polygon: z.array(Vec2Schema).min(3),
|
|
9
|
+
label: z.string().min(1),
|
|
10
|
+
properties: z.record(z.string(), z.unknown()).optional(),
|
|
11
|
+
};
|
|
12
|
+
export const setZoneOutput = {
|
|
13
|
+
zoneId: z.string(),
|
|
14
|
+
};
|
|
15
|
+
export function registerSetZone(server, bridge) {
|
|
16
|
+
server.registerTool('set_zone', {
|
|
17
|
+
title: 'Set zone',
|
|
18
|
+
description: 'Create a polygonal zone on the given level. label is stored as the zone name and properties are merged into metadata.',
|
|
19
|
+
inputSchema: setZoneInput,
|
|
20
|
+
outputSchema: setZoneOutput,
|
|
21
|
+
}, async ({ levelId, polygon, label, properties }) => {
|
|
22
|
+
const parent = bridge.getNode(levelId);
|
|
23
|
+
if (!parent) {
|
|
24
|
+
throwMcpError(ErrorCode.InvalidParams, `Level not found: ${levelId}`);
|
|
25
|
+
}
|
|
26
|
+
if (parent.type !== 'level') {
|
|
27
|
+
throwMcpError(ErrorCode.InvalidParams, `Node ${levelId} is a ${parent.type}, expected level`);
|
|
28
|
+
}
|
|
29
|
+
if (typeof parent.metadata === 'object' &&
|
|
30
|
+
parent.metadata !== null &&
|
|
31
|
+
'role' in parent.metadata &&
|
|
32
|
+
parent.metadata.role === 'roof') {
|
|
33
|
+
throwMcpError(ErrorCode.InvalidParams, `Roof support level ${levelId} is not an occupied story; create zones on an occupied level instead`);
|
|
34
|
+
}
|
|
35
|
+
const zone = ZoneNode.parse({
|
|
36
|
+
name: label,
|
|
37
|
+
polygon: polygon,
|
|
38
|
+
metadata: properties ?? {},
|
|
39
|
+
});
|
|
40
|
+
const id = bridge.createNode(zone, levelId);
|
|
41
|
+
await publishLiveSceneSnapshot(bridge, 'set_zone');
|
|
42
|
+
const payload = { zoneId: id };
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
45
|
+
structuredContent: payload,
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
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 createFromTemplateInput: {
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
name: z.ZodOptional<z.ZodString>;
|
|
7
|
+
/**
|
|
8
|
+
* When persistence operations are wired into the MCP server, set this flag to
|
|
9
|
+
* `true` to immediately save the instantiated template and return its
|
|
10
|
+
* `SceneMeta`. When `false` (default) the template is applied to the bridge
|
|
11
|
+
* only.
|
|
12
|
+
*/
|
|
13
|
+
save: z.ZodDefault<z.ZodBoolean>;
|
|
14
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
15
|
+
};
|
|
16
|
+
export declare const createFromTemplateOutput: {
|
|
17
|
+
templateId: z.ZodString;
|
|
18
|
+
rootNodeIds: z.ZodArray<z.ZodString>;
|
|
19
|
+
nodeCount: z.ZodNumber;
|
|
20
|
+
/** Present when `save: true` (and a store was available). */
|
|
21
|
+
scene: z.ZodOptional<z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
name: z.ZodString;
|
|
24
|
+
projectId: z.ZodNullable<z.ZodString>;
|
|
25
|
+
thumbnailUrl: z.ZodNullable<z.ZodString>;
|
|
26
|
+
version: z.ZodNumber;
|
|
27
|
+
createdAt: z.ZodString;
|
|
28
|
+
updatedAt: z.ZodString;
|
|
29
|
+
ownerId: z.ZodNullable<z.ZodString>;
|
|
30
|
+
sizeBytes: z.ZodNumber;
|
|
31
|
+
nodeCount: z.ZodNumber;
|
|
32
|
+
url: z.ZodString;
|
|
33
|
+
editorUrl: z.ZodString;
|
|
34
|
+
published: z.ZodBoolean;
|
|
35
|
+
isDraft: z.ZodBoolean;
|
|
36
|
+
saveMode: z.ZodEnum<{
|
|
37
|
+
draft: "draft";
|
|
38
|
+
checkpoint: "checkpoint";
|
|
39
|
+
}>;
|
|
40
|
+
graphHash: z.ZodOptional<z.ZodString>;
|
|
41
|
+
levelIds: z.ZodArray<z.ZodString>;
|
|
42
|
+
defaultLevelId: z.ZodNullable<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* `create_from_template` — instantiate a seed template into the bridge, and
|
|
47
|
+
* optionally persist it via the attached scene operations.
|
|
48
|
+
*
|
|
49
|
+
* The source template is cloned with fresh ids (`cloneSceneGraph`) so the
|
|
50
|
+
* deterministic placeholders (`site_empty`, `wall_n`, …) don't collide
|
|
51
|
+
* across repeated calls or with other scenes.
|
|
52
|
+
*/
|
|
53
|
+
export declare function registerCreateFromTemplate(server: McpServer, bridge: SceneOperations): void;
|
|
54
|
+
//# sourceMappingURL=create-from-template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-from-template.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/create-from-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAMvD,eAAO,MAAM,uBAAuB;;;IAYlC;;;;;OAKG;;;CAGJ,CAAA;AAED,eAAO,MAAM,wBAAwB;;;;IAInC,6DAA6D;;;;;;;;;;;;;;;;;;;;;;;;CAuB9D,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA8F3F"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { cloneSceneGraph } from '@pascal-app/core/clone-scene-graph';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { rehydrateSiteChildren } from '../../lib/rehydrate-site-children';
|
|
4
|
+
import { isTemplateId, TEMPLATES } from '../../templates';
|
|
5
|
+
import { ErrorCode, throwMcpError } from '../errors';
|
|
6
|
+
import { appendLiveSceneEvent } from '../live-sync';
|
|
7
|
+
import { currentLevelContext, sceneMetaPayload } from '../scene-lifecycle/metadata';
|
|
8
|
+
export const createFromTemplateInput = {
|
|
9
|
+
id: z
|
|
10
|
+
.string()
|
|
11
|
+
.describe('Template id (see `list_templates`). Currently one of: "empty-studio", "two-bedroom", "garden-house".'),
|
|
12
|
+
name: z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1)
|
|
15
|
+
.max(200)
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Optional display name for the saved scene. Defaults to the template name.'),
|
|
18
|
+
/**
|
|
19
|
+
* When persistence operations are wired into the MCP server, set this flag to
|
|
20
|
+
* `true` to immediately save the instantiated template and return its
|
|
21
|
+
* `SceneMeta`. When `false` (default) the template is applied to the bridge
|
|
22
|
+
* only.
|
|
23
|
+
*/
|
|
24
|
+
save: z.boolean().default(false),
|
|
25
|
+
projectId: z.string().optional(),
|
|
26
|
+
};
|
|
27
|
+
export const createFromTemplateOutput = {
|
|
28
|
+
templateId: z.string(),
|
|
29
|
+
rootNodeIds: z.array(z.string()),
|
|
30
|
+
nodeCount: z.number(),
|
|
31
|
+
/** Present when `save: true` (and a store was available). */
|
|
32
|
+
scene: z
|
|
33
|
+
.object({
|
|
34
|
+
id: z.string(),
|
|
35
|
+
name: z.string(),
|
|
36
|
+
projectId: z.string().nullable(),
|
|
37
|
+
thumbnailUrl: z.string().nullable(),
|
|
38
|
+
version: z.number(),
|
|
39
|
+
createdAt: z.string(),
|
|
40
|
+
updatedAt: z.string(),
|
|
41
|
+
ownerId: z.string().nullable(),
|
|
42
|
+
sizeBytes: z.number(),
|
|
43
|
+
nodeCount: z.number(),
|
|
44
|
+
url: z.string(),
|
|
45
|
+
editorUrl: z.string(),
|
|
46
|
+
published: z.boolean(),
|
|
47
|
+
isDraft: z.boolean(),
|
|
48
|
+
saveMode: z.enum(['draft', 'checkpoint']),
|
|
49
|
+
graphHash: z.string().optional(),
|
|
50
|
+
levelIds: z.array(z.string()),
|
|
51
|
+
defaultLevelId: z.string().nullable(),
|
|
52
|
+
})
|
|
53
|
+
.optional(),
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* `create_from_template` — instantiate a seed template into the bridge, and
|
|
57
|
+
* optionally persist it via the attached scene operations.
|
|
58
|
+
*
|
|
59
|
+
* The source template is cloned with fresh ids (`cloneSceneGraph`) so the
|
|
60
|
+
* deterministic placeholders (`site_empty`, `wall_n`, …) don't collide
|
|
61
|
+
* across repeated calls or with other scenes.
|
|
62
|
+
*/
|
|
63
|
+
export function registerCreateFromTemplate(server, bridge) {
|
|
64
|
+
server.registerTool('create_from_template', {
|
|
65
|
+
title: 'Create scene from template',
|
|
66
|
+
description: 'Instantiate a seed Pascal scene template into the bridge. Regenerates all ids before applying. When `save: true` and a SceneStore is wired, also persists the new scene and returns the SceneMeta.',
|
|
67
|
+
inputSchema: createFromTemplateInput,
|
|
68
|
+
outputSchema: createFromTemplateOutput,
|
|
69
|
+
}, async ({ id, name, save, projectId }) => {
|
|
70
|
+
if (!isTemplateId(id)) {
|
|
71
|
+
throwMcpError(ErrorCode.InvalidParams, `unknown_template: ${id}. Call list_templates for the set of valid ids.`);
|
|
72
|
+
}
|
|
73
|
+
const entry = TEMPLATES[id];
|
|
74
|
+
// Clone: regenerate ids so each instantiation is independent.
|
|
75
|
+
// `cloneSceneGraph` flattens SiteNode.children to string ids; rehydrate
|
|
76
|
+
// them back to embedded objects to satisfy the SiteNode schema (see
|
|
77
|
+
// CROSS_CUTTING §2).
|
|
78
|
+
const cloned = rehydrateSiteChildren(cloneSceneGraph(entry.template));
|
|
79
|
+
const nodes = cloned.nodes;
|
|
80
|
+
const rootNodeIds = cloned.rootNodeIds;
|
|
81
|
+
try {
|
|
82
|
+
bridge.setScene(nodes, rootNodeIds);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
86
|
+
throwMcpError(ErrorCode.InternalError, `apply_failed: ${msg}`);
|
|
87
|
+
}
|
|
88
|
+
const basePayload = {
|
|
89
|
+
templateId: entry.id,
|
|
90
|
+
rootNodeIds: rootNodeIds,
|
|
91
|
+
nodeCount: Object.keys(nodes).length,
|
|
92
|
+
};
|
|
93
|
+
if (!save) {
|
|
94
|
+
bridge.clearActiveScene();
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: 'text', text: JSON.stringify(basePayload) }],
|
|
97
|
+
structuredContent: basePayload,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (!bridge.hasStore) {
|
|
101
|
+
// Graceful no-store mode: report that save was skipped rather than
|
|
102
|
+
// erroring — this makes the tool usable in headless bridge-only
|
|
103
|
+
// deployments (tests, smoke scripts) without crashing.
|
|
104
|
+
bridge.clearActiveScene();
|
|
105
|
+
const payload = { ...basePayload, saveSkipped: true };
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
108
|
+
structuredContent: payload,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
let saveProjectId = projectId;
|
|
113
|
+
if (!saveProjectId && bridge.canCreateProject) {
|
|
114
|
+
const project = await bridge.createProject({ name: name ?? entry.name });
|
|
115
|
+
saveProjectId = project.projectId;
|
|
116
|
+
}
|
|
117
|
+
const meta = await bridge.saveScene({
|
|
118
|
+
...(saveProjectId !== undefined ? { id: saveProjectId, projectId: saveProjectId } : {}),
|
|
119
|
+
name: name ?? entry.name,
|
|
120
|
+
graph: { nodes, rootNodeIds },
|
|
121
|
+
saveMode: 'draft',
|
|
122
|
+
publish: false,
|
|
123
|
+
operation: 'create_from_template',
|
|
124
|
+
});
|
|
125
|
+
bridge.setActiveScene(meta);
|
|
126
|
+
await appendLiveSceneEvent(bridge, meta.id, meta.version, 'create_from_template', {
|
|
127
|
+
nodes,
|
|
128
|
+
rootNodeIds,
|
|
129
|
+
});
|
|
130
|
+
const scene = {
|
|
131
|
+
...sceneMetaPayload(meta, { nodes, rootNodeIds }),
|
|
132
|
+
...currentLevelContext(bridge),
|
|
133
|
+
};
|
|
134
|
+
const payload = { ...basePayload, scene };
|
|
135
|
+
return {
|
|
136
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
137
|
+
structuredContent: payload,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
142
|
+
throwMcpError(ErrorCode.InternalError, `save_failed: ${msg}`);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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 createHouseFromBriefInput: {
|
|
5
|
+
brief: z.ZodString;
|
|
6
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
7
|
+
projectName: z.ZodOptional<z.ZodString>;
|
|
8
|
+
bedroomCount: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
rooms: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
10
|
+
style: z.ZodOptional<z.ZodString>;
|
|
11
|
+
landscaping: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
constraints: z.ZodOptional<z.ZodString>;
|
|
13
|
+
};
|
|
14
|
+
export declare const createHouseFromBriefOutput: {
|
|
15
|
+
projectId: z.ZodNullable<z.ZodString>;
|
|
16
|
+
editorUrl: z.ZodNullable<z.ZodString>;
|
|
17
|
+
url: z.ZodNullable<z.ZodString>;
|
|
18
|
+
version: z.ZodNullable<z.ZodNumber>;
|
|
19
|
+
published: z.ZodBoolean;
|
|
20
|
+
isDraft: z.ZodBoolean;
|
|
21
|
+
templateId: z.ZodString;
|
|
22
|
+
nodeCount: z.ZodNumber;
|
|
23
|
+
roomCount: z.ZodNumber;
|
|
24
|
+
levelIds: z.ZodArray<z.ZodString>;
|
|
25
|
+
defaultLevelId: z.ZodNullable<z.ZodString>;
|
|
26
|
+
validation: z.ZodObject<{
|
|
27
|
+
valid: z.ZodBoolean;
|
|
28
|
+
errors: z.ZodArray<z.ZodString>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
summary: z.ZodString;
|
|
31
|
+
limitations: z.ZodArray<z.ZodString>;
|
|
32
|
+
nextStep: z.ZodString;
|
|
33
|
+
};
|
|
34
|
+
export declare function registerCreateHouseFromBrief(server: McpServer, bridge: SceneOperations): void;
|
|
35
|
+
//# sourceMappingURL=create-house-from-brief.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-house-from-brief.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/create-house-from-brief.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAMvD,eAAO,MAAM,yBAAyB;;;;;;;;;CASrC,CAAA;AAED,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;CAmBtC,CAAA;AAmCD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqI7F"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { cloneSceneGraph } from '@pascal-app/core/clone-scene-graph';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { rehydrateSiteChildren } from '../../lib/rehydrate-site-children';
|
|
4
|
+
import { isTemplateId, TEMPLATES } from '../../templates';
|
|
5
|
+
import { ErrorCode, throwMcpError } from '../errors';
|
|
6
|
+
import { appendLiveSceneEvent } from '../live-sync';
|
|
7
|
+
import { currentLevelContext, sceneMetaPayload } from '../scene-lifecycle/metadata';
|
|
8
|
+
export const createHouseFromBriefInput = {
|
|
9
|
+
brief: z.string().min(1),
|
|
10
|
+
projectId: z.string().optional(),
|
|
11
|
+
projectName: z.string().min(1).max(200).optional(),
|
|
12
|
+
bedroomCount: z.number().int().min(0).max(12).optional(),
|
|
13
|
+
rooms: z.array(z.string().min(1)).optional(),
|
|
14
|
+
style: z.string().optional(),
|
|
15
|
+
landscaping: z.boolean().optional(),
|
|
16
|
+
constraints: z.string().optional(),
|
|
17
|
+
};
|
|
18
|
+
export const createHouseFromBriefOutput = {
|
|
19
|
+
projectId: z.string().nullable(),
|
|
20
|
+
editorUrl: z.string().nullable(),
|
|
21
|
+
url: z.string().nullable(),
|
|
22
|
+
version: z.number().nullable(),
|
|
23
|
+
published: z.boolean(),
|
|
24
|
+
isDraft: z.boolean(),
|
|
25
|
+
templateId: z.string(),
|
|
26
|
+
nodeCount: z.number(),
|
|
27
|
+
roomCount: z.number(),
|
|
28
|
+
levelIds: z.array(z.string()),
|
|
29
|
+
defaultLevelId: z.string().nullable(),
|
|
30
|
+
validation: z.object({
|
|
31
|
+
valid: z.boolean(),
|
|
32
|
+
errors: z.array(z.string()),
|
|
33
|
+
}),
|
|
34
|
+
summary: z.string(),
|
|
35
|
+
limitations: z.array(z.string()),
|
|
36
|
+
nextStep: z.string(),
|
|
37
|
+
};
|
|
38
|
+
function chooseTemplate(args) {
|
|
39
|
+
const requested = new Set((args.rooms ?? []).map((room) => room.toLowerCase()));
|
|
40
|
+
if (args.landscaping ||
|
|
41
|
+
requested.has('garden') ||
|
|
42
|
+
requested.has('patio') ||
|
|
43
|
+
requested.has('yard')) {
|
|
44
|
+
return 'garden-house';
|
|
45
|
+
}
|
|
46
|
+
if ((args.bedroomCount ?? 0) <= 1)
|
|
47
|
+
return 'empty-studio';
|
|
48
|
+
if ((args.bedroomCount ?? 0) <= 2)
|
|
49
|
+
return 'two-bedroom';
|
|
50
|
+
return 'garden-house';
|
|
51
|
+
}
|
|
52
|
+
function countNodeTypes(nodes) {
|
|
53
|
+
let roomCount = 0;
|
|
54
|
+
for (const node of Object.values(nodes)) {
|
|
55
|
+
if (node.type === 'zone')
|
|
56
|
+
roomCount++;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
nodeCount: Object.keys(nodes).length,
|
|
60
|
+
roomCount,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function registerCreateHouseFromBrief(server, bridge) {
|
|
64
|
+
server.registerTool('create_house_from_brief', {
|
|
65
|
+
title: 'Create house from brief',
|
|
66
|
+
description: 'High-level hosted workflow for external agents: choose a starter house from a brief, create/save/publish it, and return the editor URL. Use semantic tools afterward for exact customization.',
|
|
67
|
+
inputSchema: createHouseFromBriefInput,
|
|
68
|
+
outputSchema: createHouseFromBriefOutput,
|
|
69
|
+
}, async ({ brief, projectId, projectName, bedroomCount, rooms, style, landscaping, constraints, }) => {
|
|
70
|
+
const templateId = chooseTemplate({
|
|
71
|
+
...(bedroomCount !== undefined ? { bedroomCount } : {}),
|
|
72
|
+
...(rooms !== undefined ? { rooms } : {}),
|
|
73
|
+
...(landscaping !== undefined ? { landscaping } : {}),
|
|
74
|
+
});
|
|
75
|
+
if (!isTemplateId(templateId)) {
|
|
76
|
+
throwMcpError(ErrorCode.InternalError, `unknown_template: ${templateId}`);
|
|
77
|
+
}
|
|
78
|
+
const entry = TEMPLATES[templateId];
|
|
79
|
+
const cloned = rehydrateSiteChildren(cloneSceneGraph(entry.template));
|
|
80
|
+
const nodes = cloned.nodes;
|
|
81
|
+
const rootNodeIds = cloned.rootNodeIds;
|
|
82
|
+
const counts = countNodeTypes(nodes);
|
|
83
|
+
try {
|
|
84
|
+
bridge.setScene(nodes, rootNodeIds);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
88
|
+
throwMcpError(ErrorCode.InternalError, `apply_failed: ${msg}`);
|
|
89
|
+
}
|
|
90
|
+
const rawValidation = bridge.validateScene();
|
|
91
|
+
const validation = {
|
|
92
|
+
valid: rawValidation.valid,
|
|
93
|
+
errors: rawValidation.errors.map((error) => `${error.nodeId}:${error.path}: ${error.message}`),
|
|
94
|
+
};
|
|
95
|
+
const limitations = [];
|
|
96
|
+
if ((bedroomCount ?? 0) > 2) {
|
|
97
|
+
limitations.push('MVP create_house_from_brief uses the closest built-in template for 3+ bedroom requests; refine with create_room/add_door/add_window for exact room count.');
|
|
98
|
+
}
|
|
99
|
+
if (style || constraints) {
|
|
100
|
+
limitations.push('Style and constraints are recorded in the summary but not yet fully synthesized into custom geometry.');
|
|
101
|
+
}
|
|
102
|
+
if (!bridge.hasStore) {
|
|
103
|
+
const payload = {
|
|
104
|
+
projectId: null,
|
|
105
|
+
editorUrl: null,
|
|
106
|
+
url: null,
|
|
107
|
+
version: null,
|
|
108
|
+
published: false,
|
|
109
|
+
isDraft: false,
|
|
110
|
+
templateId,
|
|
111
|
+
nodeCount: counts.nodeCount,
|
|
112
|
+
roomCount: counts.roomCount,
|
|
113
|
+
...currentLevelContext(bridge),
|
|
114
|
+
validation,
|
|
115
|
+
summary: `Applied ${entry.name} starter scene from brief: ${brief}`,
|
|
116
|
+
limitations,
|
|
117
|
+
nextStep: 'No SceneStore is attached. Call save_scene later in a hosted MCP session to publish.',
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
121
|
+
structuredContent: payload,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
let saveProjectId = projectId;
|
|
126
|
+
if (!saveProjectId && bridge.canCreateProject) {
|
|
127
|
+
const project = await bridge.createProject({ name: projectName ?? entry.name });
|
|
128
|
+
saveProjectId = project.projectId;
|
|
129
|
+
}
|
|
130
|
+
const meta = await bridge.saveScene({
|
|
131
|
+
...(saveProjectId !== undefined ? { id: saveProjectId, projectId: saveProjectId } : {}),
|
|
132
|
+
name: projectName ?? entry.name,
|
|
133
|
+
graph: { nodes, rootNodeIds },
|
|
134
|
+
saveMode: 'draft',
|
|
135
|
+
publish: false,
|
|
136
|
+
operation: 'create_house_from_brief',
|
|
137
|
+
});
|
|
138
|
+
bridge.setActiveScene(meta);
|
|
139
|
+
await appendLiveSceneEvent(bridge, meta.id, meta.version, 'create_house_from_brief', {
|
|
140
|
+
nodes,
|
|
141
|
+
rootNodeIds,
|
|
142
|
+
});
|
|
143
|
+
const scene = sceneMetaPayload(meta, { nodes, rootNodeIds });
|
|
144
|
+
const payload = {
|
|
145
|
+
projectId: scene.projectId ?? scene.id,
|
|
146
|
+
editorUrl: scene.editorUrl,
|
|
147
|
+
url: scene.url,
|
|
148
|
+
version: scene.version,
|
|
149
|
+
published: scene.published,
|
|
150
|
+
isDraft: scene.isDraft,
|
|
151
|
+
templateId,
|
|
152
|
+
nodeCount: scene.nodeCount,
|
|
153
|
+
roomCount: counts.roomCount,
|
|
154
|
+
...currentLevelContext(bridge),
|
|
155
|
+
validation,
|
|
156
|
+
summary: `Created ${scene.name} from ${entry.name}. Brief: ${brief}`,
|
|
157
|
+
limitations,
|
|
158
|
+
nextStep: 'Call verify_scene and get_project_status. If the brief needs more specificity, refine with semantic tools and save_scene again.',
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
162
|
+
structuredContent: payload,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
167
|
+
throwMcpError(ErrorCode.InternalError, `save_failed: ${msg}`);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { SceneOperations } from '../../operations';
|
|
3
|
+
/**
|
|
4
|
+
* Register the template MCP tools (`list_templates`, `create_from_template`)
|
|
5
|
+
* against the given server.
|
|
6
|
+
*
|
|
7
|
+
* When persistence operations are unavailable, `create_from_template` still
|
|
8
|
+
* applies the template to the bridge but skips the save step.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerTemplateTools(server: McpServer, bridge: SceneOperations): void;
|
|
11
|
+
export { createFromTemplateInput, createFromTemplateOutput, registerCreateFromTemplate, } from './create-from-template';
|
|
12
|
+
export { createHouseFromBriefInput, createHouseFromBriefOutput, registerCreateHouseFromBrief, } from './create-house-from-brief';
|
|
13
|
+
export { listTemplatesInput, listTemplatesOutput, registerListTemplates, } from './list-templates';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAKvD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAItF;AAED,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerCreateFromTemplate } from './create-from-template';
|
|
2
|
+
import { registerCreateHouseFromBrief } from './create-house-from-brief';
|
|
3
|
+
import { registerListTemplates } from './list-templates';
|
|
4
|
+
/**
|
|
5
|
+
* Register the template MCP tools (`list_templates`, `create_from_template`)
|
|
6
|
+
* against the given server.
|
|
7
|
+
*
|
|
8
|
+
* When persistence operations are unavailable, `create_from_template` still
|
|
9
|
+
* applies the template to the bridge but skips the save step.
|
|
10
|
+
*/
|
|
11
|
+
export function registerTemplateTools(server, bridge) {
|
|
12
|
+
registerListTemplates(server);
|
|
13
|
+
registerCreateFromTemplate(server, bridge);
|
|
14
|
+
registerCreateHouseFromBrief(server, bridge);
|
|
15
|
+
}
|
|
16
|
+
export { createFromTemplateInput, createFromTemplateOutput, registerCreateFromTemplate, } from './create-from-template';
|
|
17
|
+
export { createHouseFromBriefInput, createHouseFromBriefOutput, registerCreateHouseFromBrief, } from './create-house-from-brief';
|
|
18
|
+
export { listTemplatesInput, listTemplatesOutput, registerListTemplates, } from './list-templates';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const listTemplatesInput: {};
|
|
4
|
+
export declare const listTemplatesOutput: {
|
|
5
|
+
templates: z.ZodArray<z.ZodObject<{
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
name: z.ZodString;
|
|
8
|
+
description: z.ZodString;
|
|
9
|
+
nodeCount: z.ZodNumber;
|
|
10
|
+
}, z.core.$strip>>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* `list_templates` — enumerate the seed templates shipped with the MCP server.
|
|
14
|
+
* Stateless; used by the `from_brief` prompt and by the UI to populate a
|
|
15
|
+
* "start from a template" picker.
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerListTemplates(server: McpServer): void;
|
|
18
|
+
//# sourceMappingURL=list-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-templates.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/list-templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,kBAAkB,IAAc,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;CAS/B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwB7D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TEMPLATES } from '../../templates';
|
|
3
|
+
export const listTemplatesInput = {};
|
|
4
|
+
export const listTemplatesOutput = {
|
|
5
|
+
templates: z.array(z.object({
|
|
6
|
+
id: z.string(),
|
|
7
|
+
name: z.string(),
|
|
8
|
+
description: z.string(),
|
|
9
|
+
nodeCount: z.number(),
|
|
10
|
+
})),
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* `list_templates` — enumerate the seed templates shipped with the MCP server.
|
|
14
|
+
* Stateless; used by the `from_brief` prompt and by the UI to populate a
|
|
15
|
+
* "start from a template" picker.
|
|
16
|
+
*/
|
|
17
|
+
export function registerListTemplates(server) {
|
|
18
|
+
server.registerTool('list_templates', {
|
|
19
|
+
title: 'List scene templates',
|
|
20
|
+
description: 'List the seed Pascal scene templates available to `create_from_template`. Returns the id, display name, one-line description and node count for each.',
|
|
21
|
+
inputSchema: listTemplatesInput,
|
|
22
|
+
outputSchema: listTemplatesOutput,
|
|
23
|
+
}, async () => {
|
|
24
|
+
const templates = Object.values(TEMPLATES).map((entry) => ({
|
|
25
|
+
id: entry.id,
|
|
26
|
+
name: entry.name,
|
|
27
|
+
description: entry.description,
|
|
28
|
+
nodeCount: Object.keys(entry.template.nodes).length,
|
|
29
|
+
}));
|
|
30
|
+
const payload = { templates };
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
33
|
+
structuredContent: payload,
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -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 undoInput: {
|
|
5
|
+
steps: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
};
|
|
7
|
+
export declare const undoOutput: {
|
|
8
|
+
undone: z.ZodNumber;
|
|
9
|
+
};
|
|
10
|
+
export declare function registerUndo(server: McpServer, bridge: SceneOperations): void;
|
|
11
|
+
//# sourceMappingURL=undo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../src/tools/undo.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"}
|