@pascal-app/mcp 1.0.1 → 1.0.4
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/README.md +47 -26
- package/dist/bin/pascal-mcp.js +8 -2
- package/dist/bridge/scene-bridge.d.ts +41 -6
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +230 -45
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/operations/scene-operations.d.ts +23 -3
- package/dist/operations/scene-operations.d.ts.map +1 -1
- package/dist/operations/scene-operations.js +31 -1
- package/dist/prompts/from-brief.js +1 -1
- package/dist/prompts/iterate-on-feedback.js +1 -1
- package/dist/prompts/scene-guidance.js +3 -3
- package/dist/resources/agent-guide.d.ts.map +1 -1
- package/dist/resources/agent-guide.js +22 -1
- package/dist/resources/catalog-items.d.ts +4 -5
- package/dist/resources/catalog-items.d.ts.map +1 -1
- package/dist/resources/catalog-items.js +7 -9
- 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 +3 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +5 -2
- package/dist/server.d.ts +19 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +14 -6
- 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 +2 -2
- 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 +32 -3
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +12 -0
- 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 +58 -0
- package/dist/tools/add-object.d.ts +60 -0
- package/dist/tools/add-object.d.ts.map +1 -0
- package/dist/tools/add-object.js +156 -0
- package/dist/tools/apply-patch.d.ts +3 -0
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +28 -2
- 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 +10 -12
- package/dist/tools/check-collisions.d.ts +1 -1
- package/dist/tools/check-collisions.d.ts.map +1 -1
- package/dist/tools/check-collisions.js +1 -2
- 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 +52 -0
- package/dist/tools/construction-tools.d.ts +8 -41
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +120 -230
- package/dist/tools/create-unit.d.ts +2 -0
- package/dist/tools/create-unit.d.ts.map +1 -1
- package/dist/tools/describe-node.d.ts.map +1 -1
- package/dist/tools/describe-node.js +8 -6
- package/dist/tools/errors.d.ts +11 -0
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +10 -0
- package/dist/tools/find-nodes.d.ts +3 -19
- package/dist/tools/find-nodes.d.ts.map +1 -1
- package/dist/tools/find-nodes.js +150 -53
- 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 +1 -0
- package/dist/tools/get-scene.d.ts.map +1 -1
- package/dist/tools/get-scene.js +3 -1
- 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 +30 -0
- package/dist/tools/index.d.ts +10 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +17 -26
- package/dist/tools/live-sync.d.ts +24 -5
- package/dist/tools/live-sync.d.ts.map +1 -1
- package/dist/tools/live-sync.js +47 -26
- 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 +6 -0
- package/dist/tools/measure.d.ts.map +1 -1
- package/dist/tools/measure.js +33 -65
- 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.map +1 -1
- package/dist/tools/normalize-schema-dialect.js +20 -0
- package/dist/tools/patch-guards.d.ts +58 -0
- package/dist/tools/patch-guards.d.ts.map +1 -0
- package/dist/tools/patch-guards.js +253 -0
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.js +3 -2
- package/dist/tools/place-design.d.ts +34 -0
- package/dist/tools/place-design.d.ts.map +1 -0
- package/dist/tools/place-design.js +91 -0
- package/dist/tools/redo.d.ts +2 -0
- package/dist/tools/redo.d.ts.map +1 -1
- package/dist/tools/redo.js +2 -2
- package/dist/tools/room-tools.d.ts +50 -113
- package/dist/tools/room-tools.d.ts.map +1 -1
- package/dist/tools/room-tools.js +129 -565
- package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/create-project.js +26 -1
- package/dist/tools/scene-lifecycle/delete-scene.d.ts +2 -0
- package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.js +4 -3
- package/dist/tools/scene-lifecycle/save-scene.d.ts +1 -0
- package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/save-scene.js +46 -6
- package/dist/tools/scene-lifecycle/test-utils.d.ts +2 -2
- 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 +2 -0
- package/dist/tools/set-unit-members.d.ts.map +1 -1
- package/dist/tools/set-zone.d.ts +2 -0
- package/dist/tools/set-zone.d.ts.map +1 -1
- package/dist/tools/set-zone.js +2 -2
- package/dist/tools/shared-tools.d.ts +30 -0
- package/dist/tools/shared-tools.d.ts.map +1 -0
- package/dist/tools/shared-tools.js +361 -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/undo.d.ts +2 -0
- package/dist/tools/undo.d.ts.map +1 -1
- package/dist/tools/undo.js +2 -2
- package/dist/tools/validate-design.d.ts +136 -0
- package/dist/tools/validate-design.d.ts.map +1 -0
- package/dist/tools/validate-design.js +28 -0
- package/dist/tools/validate-scene.d.ts +5 -0
- package/dist/tools/validate-scene.d.ts.map +1 -1
- package/dist/tools/validate-scene.js +8 -6
- package/dist/tools/variants/mutations.js +1 -1
- package/dist/tools/view-scene.d.ts +38 -0
- package/dist/tools/view-scene.d.ts.map +1 -0
- package/dist/tools/view-scene.js +63 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +17 -3
- package/examples/embed-in-agent.ts +1 -1
- package/examples/generate-apartment.md +9 -11
- package/examples/photo-to-scene.md +1 -1
- package/examples/renovate-from-photos.md +3 -4
- package/package.json +12 -6
- 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/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/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
|
@@ -9,6 +9,11 @@ export declare const validateSceneOutput: {
|
|
|
9
9
|
path: z.ZodString;
|
|
10
10
|
message: z.ZodString;
|
|
11
11
|
}, z.core.$strip>>;
|
|
12
|
+
warnings: z.ZodArray<z.ZodObject<{
|
|
13
|
+
nodeId: z.ZodString;
|
|
14
|
+
path: z.ZodString;
|
|
15
|
+
message: z.ZodString;
|
|
16
|
+
}, z.core.$strip>>;
|
|
12
17
|
};
|
|
13
18
|
export declare function registerValidateScene(server: McpServer, bridge: SceneOperations): void;
|
|
14
19
|
//# sourceMappingURL=validate-scene.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-scene.d.ts","sourceRoot":"","sources":["../../src/tools/validate-scene.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,kBAAkB,IAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"validate-scene.d.ts","sourceRoot":"","sources":["../../src/tools/validate-scene.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,kBAAkB,IAAK,CAAA;AAQpC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;CAI/B,CAAA;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAmBtF"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
|
|
3
3
|
export const validateSceneInput = {};
|
|
4
|
+
const validationIssue = z.object({
|
|
5
|
+
nodeId: z.string(),
|
|
6
|
+
path: z.string(),
|
|
7
|
+
message: z.string(),
|
|
8
|
+
});
|
|
4
9
|
export const validateSceneOutput = {
|
|
5
10
|
valid: z.boolean(),
|
|
6
|
-
errors: z.array(
|
|
7
|
-
|
|
8
|
-
path: z.string(),
|
|
9
|
-
message: z.string(),
|
|
10
|
-
})),
|
|
11
|
+
errors: z.array(validationIssue),
|
|
12
|
+
warnings: z.array(validationIssue),
|
|
11
13
|
};
|
|
12
14
|
export function registerValidateScene(server, bridge) {
|
|
13
15
|
server.registerTool('validate_scene', {
|
|
14
16
|
title: 'Validate scene',
|
|
15
|
-
description: 'Run Zod validation against every node in the scene. Returns `{ valid, errors }` where each
|
|
17
|
+
description: 'Run Zod validation against every node in the scene. Returns `{ valid, errors, warnings }` where each entry has `{ nodeId, path, message }`. Warnings do not fail validation; for example a hidden Site, whose flag hides only its own ground and boundary while the buildings on it stay visible and exported.',
|
|
16
18
|
inputSchema: validateSceneInput,
|
|
17
19
|
outputSchema: validateSceneOutput,
|
|
18
20
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
@@ -31,7 +31,7 @@ function cloneGraph(graph) {
|
|
|
31
31
|
}
|
|
32
32
|
const WALL_THICKNESS_OPTIONS = [0.1, 0.15, 0.2, 0.25];
|
|
33
33
|
const WALL_HEIGHT_OPTIONS = [2.4, 2.6, 2.7, 3.0];
|
|
34
|
-
const FENCE_STYLES = ['privacy', 'slat', 'rail'];
|
|
34
|
+
const FENCE_STYLES = ['privacy', 'slat', 'rail', 'picket'];
|
|
35
35
|
/** Fisher–Yates shuffle in place using the provided RNG. */
|
|
36
36
|
function shuffleInPlace(arr, rng) {
|
|
37
37
|
for (let i = arr.length - 1; i > 0; i--) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type SceneViewCrop, type SceneViewInterior, type SceneViewPose } from '@pascal-app/core/agent-operations';
|
|
3
|
+
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
+
/** A picture of the scene, rendered by an editor tab open on the project. */
|
|
5
|
+
export type SceneViewCapture = {
|
|
6
|
+
image: Uint8Array;
|
|
7
|
+
mimeType: string;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
/** Which tab rendered it, and when: the scene as that tab showed it then. */
|
|
11
|
+
tab: string;
|
|
12
|
+
capturedAt: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Asks an editor open on the project for a picture, the MCP having no renderer of its own. Refuses
|
|
16
|
+
* `editor_tab_required` when none answers.
|
|
17
|
+
*/
|
|
18
|
+
export type SceneViewHost = {
|
|
19
|
+
capture(request: {
|
|
20
|
+
projectId: string;
|
|
21
|
+
pose: SceneViewPose;
|
|
22
|
+
size: {
|
|
23
|
+
w: number;
|
|
24
|
+
h: number;
|
|
25
|
+
};
|
|
26
|
+
/** A look inside this floor: the editor leaves the rest out and cuts everything on it. */
|
|
27
|
+
interior?: SceneViewInterior;
|
|
28
|
+
}): Promise<SceneViewCapture>;
|
|
29
|
+
/** Crops the reference photo to a region; without it a view with a photo is refused. */
|
|
30
|
+
crop?(request: SceneViewCrop): Promise<{
|
|
31
|
+
image: Uint8Array;
|
|
32
|
+
mimeType: string;
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
export declare function registerViewScene(server: McpServer, operations: SceneOperations, views?: SceneViewHost): void;
|
|
38
|
+
//# sourceMappingURL=view-scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-scene.d.ts","sourceRoot":"","sources":["../../src/tools/view-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAGnB,MAAM,mCAAmC,CAAA;AAG1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAIpD,6EAA6E;AAC7E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,UAAU,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,OAAO,EAAE;QACf,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,aAAa,CAAA;QACnB,IAAI,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QAC9B,0FAA0F;QAC1F,QAAQ,CAAC,EAAE,iBAAiB,CAAA;KAC7B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC7B,wFAAwF;IACxF,IAAI,CAAC,CACH,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnF,CAAA;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,eAAe,EAC3B,KAAK,CAAC,EAAE,aAAa,QAuEtB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { sceneViewNote, sceneViewPlan, } from '@pascal-app/core/agent-operations';
|
|
2
|
+
import { refuse, viewSceneTool } from '@pascal-app/core/agent-tools';
|
|
3
|
+
import { READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
|
+
import { refusalResult } from './errors.js';
|
|
5
|
+
export function registerViewScene(server, operations, views) {
|
|
6
|
+
server.registerTool(viewSceneTool.name, {
|
|
7
|
+
title: viewSceneTool.title,
|
|
8
|
+
description: viewSceneTool.description,
|
|
9
|
+
inputSchema: viewSceneTool.input,
|
|
10
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
11
|
+
}, async (input) => {
|
|
12
|
+
try {
|
|
13
|
+
if (!views)
|
|
14
|
+
refuse('view_unavailable', 'This Pascal server has no editor to render with: take sizes and counts from the tools.');
|
|
15
|
+
const projectId = operations.getActiveScene()?.projectId;
|
|
16
|
+
if (!projectId)
|
|
17
|
+
refuse('no_project', 'This session has no project open to look at: load or create one.');
|
|
18
|
+
const { pose, size, crop, interior } = sceneViewPlan(operations.getNodes(), input);
|
|
19
|
+
if (crop && !views.crop)
|
|
20
|
+
refuse('photo_crop_unavailable', 'This Pascal server cannot crop a photo: crop the region yourself and lay it beside the view.');
|
|
21
|
+
const [shot, cropped] = await Promise.all([
|
|
22
|
+
views.capture({ projectId: projectId, pose, size, ...(interior ? { interior } : {}) }),
|
|
23
|
+
crop ? views.crop(crop) : undefined,
|
|
24
|
+
]);
|
|
25
|
+
const payload = {
|
|
26
|
+
status: 'viewed',
|
|
27
|
+
camera: pose,
|
|
28
|
+
size: { width: shot.width, height: shot.height },
|
|
29
|
+
tab: shot.tab,
|
|
30
|
+
capturedAt: shot.capturedAt,
|
|
31
|
+
note: sceneViewNote(),
|
|
32
|
+
...(crop && cropped
|
|
33
|
+
? {
|
|
34
|
+
photoRegion: crop.region,
|
|
35
|
+
photoCropSize: { width: cropped.width, height: cropped.height },
|
|
36
|
+
}
|
|
37
|
+
: {}),
|
|
38
|
+
};
|
|
39
|
+
const image = (data, mimeType) => ({
|
|
40
|
+
type: 'image',
|
|
41
|
+
data: Buffer.from(data).toString('base64'),
|
|
42
|
+
mimeType,
|
|
43
|
+
});
|
|
44
|
+
return {
|
|
45
|
+
content: cropped
|
|
46
|
+
? [
|
|
47
|
+
{ type: 'text', text: JSON.stringify(payload) },
|
|
48
|
+
{ type: 'text', text: 'The model, from the view:' },
|
|
49
|
+
image(shot.image, shot.mimeType),
|
|
50
|
+
{ type: 'text', text: 'The photo, cropped to the region:' },
|
|
51
|
+
image(cropped.image, cropped.mimeType),
|
|
52
|
+
]
|
|
53
|
+
: [
|
|
54
|
+
image(shot.image, shot.mimeType),
|
|
55
|
+
{ type: 'text', text: JSON.stringify(payload) },
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return refusalResult(error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The package version, for the server's handshake. Read from package.json
|
|
3
|
+
* at runtime under Node (and Bun) without a static `node:fs` import, so the
|
|
4
|
+
* server entry also bundles for the browser, where the editor runs it in-page.
|
|
5
|
+
*/
|
|
1
6
|
export declare const version: string;
|
|
2
7
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,OAAO,QACkE,CAAA"}
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The package version, for the server's handshake. Read from package.json
|
|
3
|
+
* at runtime under Node (and Bun) without a static `node:fs` import, so the
|
|
4
|
+
* server entry also bundles for the browser, where the editor runs it in-page.
|
|
5
|
+
*/
|
|
6
|
+
export const version = (typeof process !== 'undefined' && process.env?.PASCAL_MCP_VERSION) || readVersion();
|
|
7
|
+
function readVersion() {
|
|
8
|
+
try {
|
|
9
|
+
const fs = globalThis.process?.getBuiltinModule?.('node:fs');
|
|
10
|
+
if (!fs)
|
|
11
|
+
return '0.0.0';
|
|
12
|
+
return JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return '0.0.0';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -157,36 +157,34 @@ them by name:
|
|
|
157
157
|
|
|
158
158
|
### 5. Cut doors and windows
|
|
159
159
|
|
|
160
|
-
The agent uses `
|
|
161
|
-
|
|
160
|
+
The agent uses `add_door` for the entry doors on each interior partition and
|
|
161
|
+
`add_window` for the windows on the south and east façades:
|
|
162
162
|
|
|
163
163
|
```jsonc
|
|
164
|
-
// tool:
|
|
164
|
+
// tool: add_window (called once per window)
|
|
165
165
|
{
|
|
166
|
-
"name": "
|
|
166
|
+
"name": "add_window",
|
|
167
167
|
"arguments": {
|
|
168
168
|
"wallId": "wall-south", // perimeter wall [0,0] → [10,0]
|
|
169
|
-
"
|
|
170
|
-
"position": 0.25, // 25% along centerline
|
|
169
|
+
"t": 0.25, // 25% along centerline
|
|
171
170
|
"width": 1.2,
|
|
172
171
|
"height": 1.2
|
|
173
172
|
}
|
|
174
173
|
}
|
|
175
|
-
// → { "
|
|
174
|
+
// → { "windowId": "window-south-1", ... }
|
|
176
175
|
```
|
|
177
176
|
|
|
178
177
|
```jsonc
|
|
179
178
|
{
|
|
180
|
-
"name": "
|
|
179
|
+
"name": "add_door",
|
|
181
180
|
"arguments": {
|
|
182
181
|
"wallId": "wall-bed1", // partition wall to Bedroom 1
|
|
183
|
-
"
|
|
184
|
-
"position": 0.4,
|
|
182
|
+
"t": 0.4,
|
|
185
183
|
"width": 0.9,
|
|
186
184
|
"height": 2.1
|
|
187
185
|
}
|
|
188
186
|
}
|
|
189
|
-
// → { "
|
|
187
|
+
// → { "doorId": "door-bed1", ... }
|
|
190
188
|
```
|
|
191
189
|
|
|
192
190
|
The agent repeats this for Bedroom 2's door, the bathroom door, and two
|
|
@@ -110,7 +110,7 @@ operate on it without reloading:
|
|
|
110
110
|
> **User:** add a door on the south wall between Living and Kitchen.
|
|
111
111
|
|
|
112
112
|
The agent calls `find_nodes({ type: "wall" })`, picks the appropriate
|
|
113
|
-
wall, and issues `
|
|
113
|
+
wall, and issues `add_door` — no extra wiring needed.
|
|
114
114
|
|
|
115
115
|
## Takeaways
|
|
116
116
|
|
|
@@ -129,16 +129,15 @@ Bedroom polygons from the floorplan rooms.
|
|
|
129
129
|
|
|
130
130
|
### 4. Cut the identified openings
|
|
131
131
|
|
|
132
|
-
For each window the vision tool reported, the agent calls `
|
|
132
|
+
For each window the vision tool reported, the agent calls `add_window`
|
|
133
133
|
against the corresponding perimeter wall:
|
|
134
134
|
|
|
135
135
|
```jsonc
|
|
136
136
|
{
|
|
137
|
-
"name": "
|
|
137
|
+
"name": "add_window",
|
|
138
138
|
"arguments": {
|
|
139
139
|
"wallId": "wall-south",
|
|
140
|
-
"
|
|
141
|
-
"position": 0.5,
|
|
140
|
+
"t": 0.5,
|
|
142
141
|
"width": 1.4,
|
|
143
142
|
"height": 1.5
|
|
144
143
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pascal-app/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Model Context Protocol server for Pascal 3D editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,10 +35,15 @@
|
|
|
35
35
|
"types": "./dist/bridge/index.d.ts",
|
|
36
36
|
"import": "./dist/bridge/index.js",
|
|
37
37
|
"default": "./dist/bridge/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./tools/*": {
|
|
40
|
+
"types": "./dist/tools/*.d.ts",
|
|
41
|
+
"import": "./dist/tools/*.js",
|
|
42
|
+
"default": "./dist/tools/*.js"
|
|
38
43
|
}
|
|
39
44
|
},
|
|
40
45
|
"bin": {
|
|
41
|
-
"pascal-mcp": "
|
|
46
|
+
"pascal-mcp": "dist/bin/pascal-mcp.js"
|
|
42
47
|
},
|
|
43
48
|
"files": [
|
|
44
49
|
"dist",
|
|
@@ -47,7 +52,7 @@
|
|
|
47
52
|
"CHANGELOG.md"
|
|
48
53
|
],
|
|
49
54
|
"scripts": {
|
|
50
|
-
"build": "tsc --build && bun ../../scripts/fix-node-esm-imports.ts ../core/dist && bun ../../scripts/fix-node-esm-imports.ts dist",
|
|
55
|
+
"build": "tsc --build && bun ../../scripts/fix-node-esm-imports.ts ../core/dist && bun ../../scripts/fix-node-esm-imports.ts ../geometry-script/dist && bun ../../scripts/fix-node-esm-imports.ts dist",
|
|
51
56
|
"dev": "tsgo --build --watch",
|
|
52
57
|
"start": "bun dist/bin/pascal-mcp.js",
|
|
53
58
|
"test": "bun test",
|
|
@@ -56,15 +61,16 @@
|
|
|
56
61
|
"prepublishOnly": "bun run build && bun test && bun run smoke:node"
|
|
57
62
|
},
|
|
58
63
|
"peerDependencies": {
|
|
59
|
-
"@pascal-app/core": "^1.0.
|
|
64
|
+
"@pascal-app/core": "^1.0.4"
|
|
60
65
|
},
|
|
61
66
|
"dependencies": {
|
|
62
67
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
68
|
+
"@pascal-app/geometry-script": "^1.0.4",
|
|
63
69
|
"@pascal-app/lingo": "^0.2.0",
|
|
64
70
|
"zod": ">=4.5.4 <4.6"
|
|
65
71
|
},
|
|
66
72
|
"devDependencies": {
|
|
67
|
-
"@pascal-app/core": "^1.0.
|
|
73
|
+
"@pascal-app/core": "^1.0.4",
|
|
68
74
|
"@pascal/typescript-config": "*",
|
|
69
75
|
"@types/node": "^22.19.20",
|
|
70
76
|
"typescript": "6.0.3"
|
|
@@ -80,7 +86,7 @@
|
|
|
80
86
|
],
|
|
81
87
|
"repository": {
|
|
82
88
|
"type": "git",
|
|
83
|
-
"url": "https://github.com/pascalorg/editor.git",
|
|
89
|
+
"url": "git+https://github.com/pascalorg/editor.git",
|
|
84
90
|
"directory": "packages/mcp"
|
|
85
91
|
},
|
|
86
92
|
"license": "MIT",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
-
export declare const createLevelInput: {
|
|
5
|
-
buildingId: z.ZodString;
|
|
6
|
-
elevation: z.ZodOptional<z.ZodNumber>;
|
|
7
|
-
height: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
8
|
-
label: z.ZodOptional<z.ZodString>;
|
|
9
|
-
};
|
|
10
|
-
export declare const createLevelOutput: {
|
|
11
|
-
persistence: z.ZodOptional<z.ZodObject<{
|
|
12
|
-
status: z.ZodEnum<{
|
|
13
|
-
unbound: "unbound";
|
|
14
|
-
events_unsupported: "events_unsupported";
|
|
15
|
-
}>;
|
|
16
|
-
warning: z.ZodString;
|
|
17
|
-
}, z.core.$strip>>;
|
|
18
|
-
levelId: z.ZodString;
|
|
19
|
-
};
|
|
20
|
-
export declare function registerCreateLevel(server: McpServer, bridge: SceneOperations): void;
|
|
21
|
-
//# sourceMappingURL=create-level.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-level.d.ts","sourceRoot":"","sources":["../../src/tools/create-level.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAIxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,gBAAgB;;;;;CAW5B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;CAG7B,CAAA;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAgDpF"}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_LEVEL_HEIGHT } from '@pascal-app/core';
|
|
2
|
-
import { LevelNode } from '@pascal-app/core/schema';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
import { ADDITIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
5
|
-
import { ErrorCode, throwMcpError } from './errors.js';
|
|
6
|
-
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
7
|
-
import { measurement } from './measurement.js';
|
|
8
|
-
import { NodeIdSchema } from './schemas.js';
|
|
9
|
-
export const createLevelInput = {
|
|
10
|
-
buildingId: NodeIdSchema,
|
|
11
|
-
elevation: z
|
|
12
|
-
.number()
|
|
13
|
-
.optional()
|
|
14
|
-
.describe("Legacy parameter; new levels are appended above the building's current top level."),
|
|
15
|
-
height: measurement('length', 'm', {
|
|
16
|
-
min: 0,
|
|
17
|
-
description: 'Stored floor-to-floor storey height.',
|
|
18
|
-
}).optional(),
|
|
19
|
-
label: z.string().optional(),
|
|
20
|
-
};
|
|
21
|
-
export const createLevelOutput = {
|
|
22
|
-
levelId: z.string(),
|
|
23
|
-
...liveSyncOutput,
|
|
24
|
-
};
|
|
25
|
-
export function registerCreateLevel(server, bridge) {
|
|
26
|
-
server.registerTool('create_level', {
|
|
27
|
-
title: 'Create level',
|
|
28
|
-
description: "Append a new level above the given building's current top level. height is stored as the level's floor-to-floor storey height.",
|
|
29
|
-
inputSchema: createLevelInput,
|
|
30
|
-
outputSchema: createLevelOutput,
|
|
31
|
-
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
32
|
-
}, async ({ buildingId, height, label }) => {
|
|
33
|
-
const parent = bridge.getNode(buildingId);
|
|
34
|
-
if (!parent) {
|
|
35
|
-
throwMcpError(ErrorCode.InvalidParams, `Building not found: ${buildingId}`);
|
|
36
|
-
}
|
|
37
|
-
if (parent.type !== 'building') {
|
|
38
|
-
throwMcpError(ErrorCode.InvalidParams, `Node ${buildingId} is a ${parent.type}, expected building`);
|
|
39
|
-
}
|
|
40
|
-
const metadata = {};
|
|
41
|
-
if (label !== undefined)
|
|
42
|
-
metadata.label = label;
|
|
43
|
-
const existingOrdinals = bridge
|
|
44
|
-
.getChildren(buildingId)
|
|
45
|
-
.filter((node) => node.type === 'level')
|
|
46
|
-
.map((node) => node.level);
|
|
47
|
-
const nextOrdinal = Math.max(-1, ...existingOrdinals) + 1;
|
|
48
|
-
const levelNode = LevelNode.parse({
|
|
49
|
-
level: nextOrdinal,
|
|
50
|
-
height: height ?? DEFAULT_LEVEL_HEIGHT,
|
|
51
|
-
children: [],
|
|
52
|
-
...(Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
53
|
-
...(label !== undefined ? { name: label } : {}),
|
|
54
|
-
});
|
|
55
|
-
const id = bridge.createNode(levelNode, buildingId);
|
|
56
|
-
const persistence = await publishLiveSceneSnapshot(bridge, 'create_level');
|
|
57
|
-
const payload = { levelId: id, ...persistencePayload(persistence) };
|
|
58
|
-
return {
|
|
59
|
-
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
60
|
-
structuredContent: payload,
|
|
61
|
-
};
|
|
62
|
-
});
|
|
63
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
-
export declare const createWallInput: {
|
|
5
|
-
levelId: z.ZodString;
|
|
6
|
-
start: z.ZodArray<z.ZodNumber>;
|
|
7
|
-
end: z.ZodArray<z.ZodNumber>;
|
|
8
|
-
thickness: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
9
|
-
height: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
10
|
-
};
|
|
11
|
-
export declare const createWallOutput: {
|
|
12
|
-
persistence: z.ZodOptional<z.ZodObject<{
|
|
13
|
-
status: z.ZodEnum<{
|
|
14
|
-
unbound: "unbound";
|
|
15
|
-
events_unsupported: "events_unsupported";
|
|
16
|
-
}>;
|
|
17
|
-
warning: z.ZodString;
|
|
18
|
-
}, z.core.$strip>>;
|
|
19
|
-
wallId: z.ZodString;
|
|
20
|
-
};
|
|
21
|
-
export declare function registerCreateWall(server: McpServer, bridge: SceneOperations): void;
|
|
22
|
-
//# sourceMappingURL=create-wall.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-wall.d.ts","sourceRoot":"","sources":["../../src/tools/create-wall.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,eAAe;;;;;;CAS3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;CAG5B,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAiDnF"}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { WallNode } from '@pascal-app/core/schema';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { ADDITIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
|
-
import { ErrorCode, throwMcpError } from './errors.js';
|
|
5
|
-
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
6
|
-
import { measurement } from './measurement.js';
|
|
7
|
-
import { NodeIdSchema, Vec2Schema } from './schemas.js';
|
|
8
|
-
export const createWallInput = {
|
|
9
|
-
levelId: NodeIdSchema,
|
|
10
|
-
start: Vec2Schema,
|
|
11
|
-
end: Vec2Schema,
|
|
12
|
-
thickness: measurement('length', 'm', {
|
|
13
|
-
positive: true,
|
|
14
|
-
description: 'Wall thickness.',
|
|
15
|
-
}).optional(),
|
|
16
|
-
height: measurement('length', 'm', { positive: true, description: 'Wall height.' }).optional(),
|
|
17
|
-
};
|
|
18
|
-
export const createWallOutput = {
|
|
19
|
-
wallId: z.string(),
|
|
20
|
-
...liveSyncOutput,
|
|
21
|
-
};
|
|
22
|
-
export function registerCreateWall(server, bridge) {
|
|
23
|
-
server.registerTool('create_wall', {
|
|
24
|
-
title: 'Create wall',
|
|
25
|
-
description: 'Create a new wall on the given level between two 2D points. Thickness and height default to the core library defaults when omitted.',
|
|
26
|
-
inputSchema: createWallInput,
|
|
27
|
-
outputSchema: createWallOutput,
|
|
28
|
-
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
29
|
-
}, async ({ levelId, start, end, thickness, height }) => {
|
|
30
|
-
const parent = bridge.getNode(levelId);
|
|
31
|
-
if (!parent) {
|
|
32
|
-
throwMcpError(ErrorCode.InvalidParams, `Level not found: ${levelId}`);
|
|
33
|
-
}
|
|
34
|
-
if (parent.type !== 'level') {
|
|
35
|
-
throwMcpError(ErrorCode.InvalidParams, `Node ${levelId} is a ${parent.type}, expected level`);
|
|
36
|
-
}
|
|
37
|
-
if (typeof parent.metadata === 'object' &&
|
|
38
|
-
parent.metadata !== null &&
|
|
39
|
-
'role' in parent.metadata &&
|
|
40
|
-
parent.metadata.role === 'roof') {
|
|
41
|
-
throwMcpError(ErrorCode.InvalidParams, `Roof support level ${levelId} is not an occupied story; create walls on an occupied level instead`);
|
|
42
|
-
}
|
|
43
|
-
const wall = WallNode.parse({
|
|
44
|
-
start: start,
|
|
45
|
-
end: end,
|
|
46
|
-
...(thickness !== undefined ? { thickness } : {}),
|
|
47
|
-
...(height !== undefined ? { height } : {}),
|
|
48
|
-
});
|
|
49
|
-
const id = bridge.createNode(wall, levelId);
|
|
50
|
-
const persistence = await publishLiveSceneSnapshot(bridge, 'create_wall');
|
|
51
|
-
const payload = { wallId: id, ...persistencePayload(persistence) };
|
|
52
|
-
return {
|
|
53
|
-
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
54
|
-
structuredContent: payload,
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
-
export declare const cutOpeningInput: {
|
|
5
|
-
wallId: z.ZodString;
|
|
6
|
-
type: z.ZodEnum<{
|
|
7
|
-
door: "door";
|
|
8
|
-
window: "window";
|
|
9
|
-
}>;
|
|
10
|
-
position: z.ZodNumber;
|
|
11
|
-
width: z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>;
|
|
12
|
-
height: z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>;
|
|
13
|
-
};
|
|
14
|
-
export declare const cutOpeningOutput: {
|
|
15
|
-
persistence: z.ZodOptional<z.ZodObject<{
|
|
16
|
-
status: z.ZodEnum<{
|
|
17
|
-
unbound: "unbound";
|
|
18
|
-
events_unsupported: "events_unsupported";
|
|
19
|
-
}>;
|
|
20
|
-
warning: z.ZodString;
|
|
21
|
-
}, z.core.$strip>>;
|
|
22
|
-
openingId: z.ZodString;
|
|
23
|
-
};
|
|
24
|
-
export declare function registerCutOpening(server: McpServer, bridge: SceneOperations): void;
|
|
25
|
-
//# sourceMappingURL=cut-opening.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cut-opening.d.ts","sourceRoot":"","sources":["../../src/tools/cut-opening.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;AAQpD,eAAO,MAAM,eAAe;;;;;;;;;CAM3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;CAG5B,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA0DnF"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { DoorNode, WindowNode } from '@pascal-app/core/schema';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { ADDITIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
|
-
import { ErrorCode, throwMcpError } from './errors.js';
|
|
5
|
-
import { wallLength, wallLocalXFromT } from './geometry.js';
|
|
6
|
-
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
7
|
-
import { measurement } from './measurement.js';
|
|
8
|
-
import { NodeIdSchema } from './schemas.js';
|
|
9
|
-
export const cutOpeningInput = {
|
|
10
|
-
wallId: NodeIdSchema,
|
|
11
|
-
type: z.enum(['door', 'window']),
|
|
12
|
-
position: z.number().min(0).max(1),
|
|
13
|
-
width: measurement('length', 'm', { positive: true, description: 'Opening width.' }),
|
|
14
|
-
height: measurement('length', 'm', { positive: true, description: 'Opening height.' }),
|
|
15
|
-
};
|
|
16
|
-
export const cutOpeningOutput = {
|
|
17
|
-
openingId: z.string(),
|
|
18
|
-
...liveSyncOutput,
|
|
19
|
-
};
|
|
20
|
-
export function registerCutOpening(server, bridge) {
|
|
21
|
-
server.registerTool('cut_opening', {
|
|
22
|
-
title: 'Cut opening',
|
|
23
|
-
description: 'Cut a door or window opening into an existing wall. position is a parametric 0..1 offset along the wall centreline.',
|
|
24
|
-
inputSchema: cutOpeningInput,
|
|
25
|
-
outputSchema: cutOpeningOutput,
|
|
26
|
-
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
27
|
-
}, async ({ wallId, type, position, width, height }) => {
|
|
28
|
-
const wall = bridge.getNode(wallId);
|
|
29
|
-
if (!wall) {
|
|
30
|
-
throwMcpError(ErrorCode.InvalidParams, `Wall not found: ${wallId}`);
|
|
31
|
-
}
|
|
32
|
-
if (wall.type !== 'wall') {
|
|
33
|
-
throwMcpError(ErrorCode.InvalidParams, `Node ${wallId} is a ${wall.type}, expected wall`);
|
|
34
|
-
}
|
|
35
|
-
const length = wallLength(wall);
|
|
36
|
-
if (length < width) {
|
|
37
|
-
throwMcpError(ErrorCode.InvalidParams, `Wall ${wallId} is ${length.toFixed(2)}m long, too short for a ${width.toFixed(2)}m opening`);
|
|
38
|
-
}
|
|
39
|
-
// `position` is public MCP ergonomics: 0..1 along the wall. Door/window
|
|
40
|
-
// nodes store wall-local meters in position[0], so convert before writing.
|
|
41
|
-
const base = {
|
|
42
|
-
wallId,
|
|
43
|
-
width,
|
|
44
|
-
height,
|
|
45
|
-
position: [wallLocalXFromT(wall, position, width), height / 2, 0],
|
|
46
|
-
};
|
|
47
|
-
const opening = type === 'door'
|
|
48
|
-
? DoorNode.parse(base)
|
|
49
|
-
: WindowNode.parse({
|
|
50
|
-
...base,
|
|
51
|
-
position: [base.position[0], 0.9 + height / 2, 0],
|
|
52
|
-
});
|
|
53
|
-
const id = bridge.createNode(opening, wallId);
|
|
54
|
-
const persistence = await publishLiveSceneSnapshot(bridge, 'cut_opening');
|
|
55
|
-
const payload = { openingId: id, ...persistencePayload(persistence) };
|
|
56
|
-
return {
|
|
57
|
-
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
58
|
-
structuredContent: payload,
|
|
59
|
-
};
|
|
60
|
-
});
|
|
61
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
-
export declare const deleteNodeInput: {
|
|
5
|
-
id: z.ZodString;
|
|
6
|
-
cascade: z.ZodOptional<z.ZodBoolean>;
|
|
7
|
-
};
|
|
8
|
-
export declare const deleteNodeOutput: {
|
|
9
|
-
persistence: z.ZodOptional<z.ZodObject<{
|
|
10
|
-
status: z.ZodEnum<{
|
|
11
|
-
unbound: "unbound";
|
|
12
|
-
events_unsupported: "events_unsupported";
|
|
13
|
-
}>;
|
|
14
|
-
warning: z.ZodString;
|
|
15
|
-
}, z.core.$strip>>;
|
|
16
|
-
deletedIds: z.ZodArray<z.ZodString>;
|
|
17
|
-
};
|
|
18
|
-
export declare function registerDeleteNode(server: McpServer, bridge: SceneOperations): void;
|
|
19
|
-
//# sourceMappingURL=delete-node.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"delete-node.d.ts","sourceRoot":"","sources":["../../src/tools/delete-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,eAAO,MAAM,eAAe;;;CAG3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;CAG5B,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA8BnF"}
|