@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,24 @@
|
|
|
1
|
+
import type { WallNode } from '@pascal-app/core/schema';
|
|
2
|
+
export type Vec2 = [number, number];
|
|
3
|
+
export type Vec3 = [number, number, number];
|
|
4
|
+
export declare function distance2D(a: Vec2, b: Vec2): number;
|
|
5
|
+
export declare function wallLength(wall: Pick<WallNode, 'start' | 'end'>): number;
|
|
6
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
7
|
+
export declare function wallLocalXFromT(wall: Pick<WallNode, 'start' | 'end'>, t: number, width: number): number;
|
|
8
|
+
export declare function projectWorldPointToWallLocalX(wall: Pick<WallNode, 'start' | 'end'>, position: Vec3): number;
|
|
9
|
+
export declare function polygonArea(points: Vec2[]): number;
|
|
10
|
+
export declare function polygonBounds(points: Vec2[]): {
|
|
11
|
+
minX: number;
|
|
12
|
+
maxX: number;
|
|
13
|
+
minZ: number;
|
|
14
|
+
maxZ: number;
|
|
15
|
+
width: number;
|
|
16
|
+
depth: number;
|
|
17
|
+
centerX: number;
|
|
18
|
+
centerZ: number;
|
|
19
|
+
};
|
|
20
|
+
export declare function pointInBoundsWithPadding(x: number, z: number, bounds: ReturnType<typeof polygonBounds>, padding: number): boolean;
|
|
21
|
+
export declare function pointOnSegment(point: Vec2, a: Vec2, b: Vec2, tolerance?: number): boolean;
|
|
22
|
+
export declare function pointInPolygon(point: Vec2, polygon: Vec2[], includeBoundary?: boolean): boolean;
|
|
23
|
+
export declare function polygonContainsPolygon(outer: Vec2[], inner: Vec2[]): boolean;
|
|
24
|
+
//# sourceMappingURL=geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/tools/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAEvD,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AACnC,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE3C,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAInD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,MAAM,CAExE;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC,EACrC,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,GACZ,MAAM,CAGR;AAED,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC,EACrC,QAAQ,EAAE,IAAI,GACb,MAAM,CAWR;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CASlD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAiBA;AAED,wBAAgB,wBAAwB,CACtC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,OAAO,CAOT;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,SAAO,GAAG,OAAO,CAOvF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,eAAe,UAAO,GAAG,OAAO,CAgB5F;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAE5E"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export function distance2D(a, b) {
|
|
2
|
+
const dx = b[0] - a[0];
|
|
3
|
+
const dz = b[1] - a[1];
|
|
4
|
+
return Math.sqrt(dx * dx + dz * dz);
|
|
5
|
+
}
|
|
6
|
+
export function wallLength(wall) {
|
|
7
|
+
return distance2D(wall.start, wall.end);
|
|
8
|
+
}
|
|
9
|
+
export function clamp(value, min, max) {
|
|
10
|
+
if (max < min)
|
|
11
|
+
return (min + max) / 2;
|
|
12
|
+
return Math.max(min, Math.min(max, value));
|
|
13
|
+
}
|
|
14
|
+
export function wallLocalXFromT(wall, t, width) {
|
|
15
|
+
const length = wallLength(wall);
|
|
16
|
+
return clamp(t * length, width / 2, length - width / 2);
|
|
17
|
+
}
|
|
18
|
+
export function projectWorldPointToWallLocalX(wall, position) {
|
|
19
|
+
const [sx, sz] = wall.start;
|
|
20
|
+
const [ex, ez] = wall.end;
|
|
21
|
+
const dx = ex - sx;
|
|
22
|
+
const dz = ez - sz;
|
|
23
|
+
const len = Math.sqrt(dx * dx + dz * dz);
|
|
24
|
+
if (len === 0)
|
|
25
|
+
return 0;
|
|
26
|
+
const px = position[0] - sx;
|
|
27
|
+
const pz = position[2] - sz;
|
|
28
|
+
const distance = px * (dx / len) + pz * (dz / len);
|
|
29
|
+
return clamp(distance, 0, len);
|
|
30
|
+
}
|
|
31
|
+
export function polygonArea(points) {
|
|
32
|
+
if (points.length < 3)
|
|
33
|
+
return 0;
|
|
34
|
+
let area = 0;
|
|
35
|
+
for (let i = 0; i < points.length; i++) {
|
|
36
|
+
const current = points[i];
|
|
37
|
+
const next = points[(i + 1) % points.length];
|
|
38
|
+
area += current[0] * next[1] - next[0] * current[1];
|
|
39
|
+
}
|
|
40
|
+
return Math.abs(area) / 2;
|
|
41
|
+
}
|
|
42
|
+
export function polygonBounds(points) {
|
|
43
|
+
const xs = points.map((p) => p[0]);
|
|
44
|
+
const zs = points.map((p) => p[1]);
|
|
45
|
+
const minX = Math.min(...xs);
|
|
46
|
+
const maxX = Math.max(...xs);
|
|
47
|
+
const minZ = Math.min(...zs);
|
|
48
|
+
const maxZ = Math.max(...zs);
|
|
49
|
+
return {
|
|
50
|
+
minX,
|
|
51
|
+
maxX,
|
|
52
|
+
minZ,
|
|
53
|
+
maxZ,
|
|
54
|
+
width: maxX - minX,
|
|
55
|
+
depth: maxZ - minZ,
|
|
56
|
+
centerX: (minX + maxX) / 2,
|
|
57
|
+
centerZ: (minZ + maxZ) / 2,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function pointInBoundsWithPadding(x, z, bounds, padding) {
|
|
61
|
+
return (x >= bounds.minX + padding &&
|
|
62
|
+
x <= bounds.maxX - padding &&
|
|
63
|
+
z >= bounds.minZ + padding &&
|
|
64
|
+
z <= bounds.maxZ - padding);
|
|
65
|
+
}
|
|
66
|
+
export function pointOnSegment(point, a, b, tolerance = 1e-6) {
|
|
67
|
+
const cross = (point[1] - a[1]) * (b[0] - a[0]) - (point[0] - a[0]) * (b[1] - a[1]);
|
|
68
|
+
if (Math.abs(cross) > tolerance)
|
|
69
|
+
return false;
|
|
70
|
+
const dot = (point[0] - a[0]) * (b[0] - a[0]) + (point[1] - a[1]) * (b[1] - a[1]);
|
|
71
|
+
if (dot < -tolerance)
|
|
72
|
+
return false;
|
|
73
|
+
const lenSq = (b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2;
|
|
74
|
+
return dot <= lenSq + tolerance;
|
|
75
|
+
}
|
|
76
|
+
export function pointInPolygon(point, polygon, includeBoundary = true) {
|
|
77
|
+
if (polygon.length < 3)
|
|
78
|
+
return false;
|
|
79
|
+
let inside = false;
|
|
80
|
+
const [x, z] = point;
|
|
81
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
82
|
+
const a = polygon[i];
|
|
83
|
+
const b = polygon[j];
|
|
84
|
+
if (pointOnSegment(point, a, b))
|
|
85
|
+
return includeBoundary;
|
|
86
|
+
const intersects = a[1] > z !== b[1] > z && x < ((b[0] - a[0]) * (z - a[1])) / (b[1] - a[1]) + a[0];
|
|
87
|
+
if (intersects)
|
|
88
|
+
inside = !inside;
|
|
89
|
+
}
|
|
90
|
+
return inside;
|
|
91
|
+
}
|
|
92
|
+
export function polygonContainsPolygon(outer, inner) {
|
|
93
|
+
return inner.every((point) => pointInPolygon(point, outer, true));
|
|
94
|
+
}
|
|
@@ -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 getNodeInput: {
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
};
|
|
7
|
+
export declare const getNodeOutput: {
|
|
8
|
+
node: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
9
|
+
};
|
|
10
|
+
export declare function registerGetNode(server: McpServer, bridge: SceneOperations): void;
|
|
11
|
+
//# sourceMappingURL=get-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-node.d.ts","sourceRoot":"","sources":["../../src/tools/get-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;AAIpD,eAAO,MAAM,YAAY;;CAExB,CAAA;AAED,eAAO,MAAM,aAAa;;CAEzB,CAAA;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqBhF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ErrorCode, throwMcpError } from './errors';
|
|
3
|
+
import { NodeIdSchema } from './schemas';
|
|
4
|
+
export const getNodeInput = {
|
|
5
|
+
id: NodeIdSchema,
|
|
6
|
+
};
|
|
7
|
+
export const getNodeOutput = {
|
|
8
|
+
node: z.record(z.string(), z.unknown()),
|
|
9
|
+
};
|
|
10
|
+
export function registerGetNode(server, bridge) {
|
|
11
|
+
server.registerTool('get_node', {
|
|
12
|
+
title: 'Get node',
|
|
13
|
+
description: 'Return the full node payload for the given ID.',
|
|
14
|
+
inputSchema: getNodeInput,
|
|
15
|
+
outputSchema: getNodeOutput,
|
|
16
|
+
}, async ({ id }) => {
|
|
17
|
+
const node = bridge.getNode(id);
|
|
18
|
+
if (!node) {
|
|
19
|
+
throwMcpError(ErrorCode.InvalidParams, `Node not found: ${id}`);
|
|
20
|
+
}
|
|
21
|
+
const payload = { node: node };
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
24
|
+
structuredContent: payload,
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -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 getSceneInput: {};
|
|
5
|
+
export declare const getSceneOutput: {
|
|
6
|
+
nodes: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
7
|
+
rootNodeIds: z.ZodArray<z.ZodString>;
|
|
8
|
+
collections: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
9
|
+
};
|
|
10
|
+
export declare function registerGetScene(server: McpServer, bridge: SceneOperations): void;
|
|
11
|
+
//# sourceMappingURL=get-scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-scene.d.ts","sourceRoot":"","sources":["../../src/tools/get-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;AAEpD,eAAO,MAAM,aAAa,IAAK,CAAA;AAE/B,eAAO,MAAM,cAAc;;;;CAI1B,CAAA;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAuBjF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const getSceneInput = {};
|
|
3
|
+
export const getSceneOutput = {
|
|
4
|
+
nodes: z.record(z.string(), z.unknown()),
|
|
5
|
+
rootNodeIds: z.array(z.string()),
|
|
6
|
+
collections: z.record(z.string(), z.unknown()).optional(),
|
|
7
|
+
};
|
|
8
|
+
export function registerGetScene(server, bridge) {
|
|
9
|
+
server.registerTool('get_scene', {
|
|
10
|
+
title: 'Get scene',
|
|
11
|
+
description: 'Returns the full scene graph: flat node dictionary, root node IDs, and collections.',
|
|
12
|
+
inputSchema: getSceneInput,
|
|
13
|
+
outputSchema: getSceneOutput,
|
|
14
|
+
}, async () => {
|
|
15
|
+
const scene = bridge.exportJSON();
|
|
16
|
+
const payload = {
|
|
17
|
+
nodes: scene.nodes,
|
|
18
|
+
rootNodeIds: scene.rootNodeIds,
|
|
19
|
+
collections: (scene.collections ?? {}),
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
23
|
+
structuredContent: payload,
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { SceneOperations } from '../operations';
|
|
3
|
+
/**
|
|
4
|
+
* Register every non-vision MCP tool against the given server.
|
|
5
|
+
* Vision tools (analyze_floorplan_image, analyze_room_photo) are registered
|
|
6
|
+
* separately via `registerVisionTools` (Agent E).
|
|
7
|
+
*
|
|
8
|
+
* Scene-lifecycle tools (save/load/list/delete/rename scene) are registered
|
|
9
|
+
* when persistence operations are available.
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerTools(server: McpServer, operations: SceneOperations): void;
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AA4BpD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CA6BlF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { registerApplyPatch } from './apply-patch';
|
|
2
|
+
import { registerCheckCollisions } from './check-collisions';
|
|
3
|
+
import { registerConstructionTools } from './construction-tools';
|
|
4
|
+
import { registerCreateLevel } from './create-level';
|
|
5
|
+
import { registerCreateWall } from './create-wall';
|
|
6
|
+
import { registerCutOpening } from './cut-opening';
|
|
7
|
+
import { registerDeleteNode } from './delete-node';
|
|
8
|
+
import { registerDescribeNode } from './describe-node';
|
|
9
|
+
import { registerDuplicateLevel } from './duplicate-level';
|
|
10
|
+
import { registerExportGlb } from './export-glb';
|
|
11
|
+
import { registerExportJson } from './export-json';
|
|
12
|
+
import { registerFindNodes } from './find-nodes';
|
|
13
|
+
import { registerGetNode } from './get-node';
|
|
14
|
+
import { registerGetScene } from './get-scene';
|
|
15
|
+
import { registerMeasure } from './measure';
|
|
16
|
+
import { registerPhotoToSceneTool } from './photo-to-scene';
|
|
17
|
+
import { registerPlaceItem } from './place-item';
|
|
18
|
+
import { registerRedo } from './redo';
|
|
19
|
+
import { registerRoomTools } from './room-tools';
|
|
20
|
+
import { registerSceneLifecycleTools } from './scene-lifecycle';
|
|
21
|
+
import { registerSceneQueryTools } from './scene-query';
|
|
22
|
+
import { registerSetZone } from './set-zone';
|
|
23
|
+
import { registerTemplateTools } from './templates';
|
|
24
|
+
import { registerUndo } from './undo';
|
|
25
|
+
import { registerValidateScene } from './validate-scene';
|
|
26
|
+
import { registerVariantTools } from './variants';
|
|
27
|
+
/**
|
|
28
|
+
* Register every non-vision MCP tool against the given server.
|
|
29
|
+
* Vision tools (analyze_floorplan_image, analyze_room_photo) are registered
|
|
30
|
+
* separately via `registerVisionTools` (Agent E).
|
|
31
|
+
*
|
|
32
|
+
* Scene-lifecycle tools (save/load/list/delete/rename scene) are registered
|
|
33
|
+
* when persistence operations are available.
|
|
34
|
+
*/
|
|
35
|
+
export function registerTools(server, operations) {
|
|
36
|
+
registerGetScene(server, operations);
|
|
37
|
+
registerGetNode(server, operations);
|
|
38
|
+
registerDescribeNode(server, operations);
|
|
39
|
+
registerFindNodes(server, operations);
|
|
40
|
+
registerSceneQueryTools(server, operations);
|
|
41
|
+
registerMeasure(server, operations);
|
|
42
|
+
registerConstructionTools(server, operations);
|
|
43
|
+
registerRoomTools(server, operations);
|
|
44
|
+
registerApplyPatch(server, operations);
|
|
45
|
+
registerCreateLevel(server, operations);
|
|
46
|
+
registerCreateWall(server, operations);
|
|
47
|
+
registerPlaceItem(server, operations);
|
|
48
|
+
registerCutOpening(server, operations);
|
|
49
|
+
registerSetZone(server, operations);
|
|
50
|
+
registerDuplicateLevel(server, operations);
|
|
51
|
+
registerDeleteNode(server, operations);
|
|
52
|
+
registerUndo(server, operations);
|
|
53
|
+
registerRedo(server, operations);
|
|
54
|
+
registerExportJson(server, operations);
|
|
55
|
+
registerExportGlb(server, operations);
|
|
56
|
+
registerValidateScene(server, operations);
|
|
57
|
+
registerCheckCollisions(server, operations);
|
|
58
|
+
registerTemplateTools(server, operations);
|
|
59
|
+
if (operations.hasStore) {
|
|
60
|
+
registerSceneLifecycleTools(server, operations);
|
|
61
|
+
registerVariantTools(server, operations);
|
|
62
|
+
registerPhotoToSceneTool(server, operations);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SceneGraph } from '@pascal-app/core/clone-scene-graph';
|
|
2
|
+
import type { SceneOperations } from '../operations';
|
|
3
|
+
export declare function syncDerivedStairOpenings(operations: SceneOperations): number;
|
|
4
|
+
/**
|
|
5
|
+
* Persist the bridge's current graph to the active scene and append a live
|
|
6
|
+
* event for browser subscribers. No-ops when the MCP session is not currently
|
|
7
|
+
* bound to a saved scene.
|
|
8
|
+
*/
|
|
9
|
+
export declare function publishLiveSceneSnapshot(operations: SceneOperations, kind: string): Promise<void>;
|
|
10
|
+
export declare function appendLiveSceneEvent(operations: SceneOperations, sceneId: string, version: number, kind: string, graph: SceneGraph): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=live-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-sync.d.ts","sourceRoot":"","sources":["../../src/tools/live-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AAEpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAIpD,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAW5E;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { syncAutoStairOpenings } from '@pascal-app/core/stair-openings';
|
|
2
|
+
import { SceneVersionConflictError } from '../storage/types';
|
|
3
|
+
import { ErrorCode, throwMcpError } from './errors';
|
|
4
|
+
export function syncDerivedStairOpenings(operations) {
|
|
5
|
+
const updates = syncAutoStairOpenings(operations.getNodes());
|
|
6
|
+
if (updates.length === 0)
|
|
7
|
+
return 0;
|
|
8
|
+
operations.applyPatch(updates.map((update) => ({
|
|
9
|
+
op: 'update',
|
|
10
|
+
id: update.id,
|
|
11
|
+
data: update.data,
|
|
12
|
+
})));
|
|
13
|
+
return updates.length;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Persist the bridge's current graph to the active scene and append a live
|
|
17
|
+
* event for browser subscribers. No-ops when the MCP session is not currently
|
|
18
|
+
* bound to a saved scene.
|
|
19
|
+
*/
|
|
20
|
+
export async function publishLiveSceneSnapshot(operations, kind) {
|
|
21
|
+
syncDerivedStairOpenings(operations);
|
|
22
|
+
const active = operations.getActiveScene();
|
|
23
|
+
if (!(active && operations.canAppendSceneEvents))
|
|
24
|
+
return;
|
|
25
|
+
const graph = operations.exportSceneGraph();
|
|
26
|
+
try {
|
|
27
|
+
const meta = await operations.saveScene({
|
|
28
|
+
id: active.id,
|
|
29
|
+
name: active.name,
|
|
30
|
+
projectId: active.projectId,
|
|
31
|
+
ownerId: active.ownerId,
|
|
32
|
+
thumbnailUrl: active.thumbnailUrl,
|
|
33
|
+
graph,
|
|
34
|
+
expectedVersion: active.version,
|
|
35
|
+
saveMode: 'draft',
|
|
36
|
+
publish: false,
|
|
37
|
+
operation: kind,
|
|
38
|
+
});
|
|
39
|
+
operations.setActiveScene(meta);
|
|
40
|
+
await operations.appendSceneEvent({
|
|
41
|
+
sceneId: meta.id,
|
|
42
|
+
version: meta.version,
|
|
43
|
+
kind,
|
|
44
|
+
graph,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof SceneVersionConflictError) {
|
|
49
|
+
throwMcpError(ErrorCode.InvalidRequest, 'live_sync_version_conflict', {
|
|
50
|
+
sceneId: active.id,
|
|
51
|
+
expectedVersion: active.version,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
55
|
+
throwMcpError(ErrorCode.InternalError, `live_sync_failed: ${message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function appendLiveSceneEvent(operations, sceneId, version, kind, graph) {
|
|
59
|
+
if (!operations.canAppendSceneEvents)
|
|
60
|
+
return;
|
|
61
|
+
await operations.appendSceneEvent({ sceneId, version, kind, graph });
|
|
62
|
+
}
|
|
@@ -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 measureInput: {
|
|
5
|
+
fromId: z.ZodString;
|
|
6
|
+
toId: z.ZodString;
|
|
7
|
+
};
|
|
8
|
+
export declare const measureOutput: {
|
|
9
|
+
distanceMeters: z.ZodNumber;
|
|
10
|
+
areaSqMeters: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
units: z.ZodLiteral<"meters">;
|
|
12
|
+
};
|
|
13
|
+
export declare function registerMeasure(server: McpServer, bridge: SceneOperations): void;
|
|
14
|
+
//# sourceMappingURL=measure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../../src/tools/measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAIpD,eAAO,MAAM,YAAY;;;CAGxB,CAAA;AAED,eAAO,MAAM,aAAa;;;;CAIzB,CAAA;AAsED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAmEhF"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ErrorCode, throwMcpError } from './errors';
|
|
3
|
+
import { NodeIdSchema } from './schemas';
|
|
4
|
+
export const measureInput = {
|
|
5
|
+
fromId: NodeIdSchema,
|
|
6
|
+
toId: NodeIdSchema,
|
|
7
|
+
};
|
|
8
|
+
export const measureOutput = {
|
|
9
|
+
distanceMeters: z.number(),
|
|
10
|
+
areaSqMeters: z.number().optional(),
|
|
11
|
+
units: z.literal('meters'),
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Compute a 3D centre point in level-coordinate space for distance measurement.
|
|
15
|
+
*
|
|
16
|
+
* For walls / fences: midpoint of the start/end segment at Y=0.
|
|
17
|
+
* For positioned nodes (item, door, window, building, stair, roof): `position`.
|
|
18
|
+
* For polygon nodes (slab, ceiling, zone): 2D centroid lifted to Y=0.
|
|
19
|
+
* For site: centroid of property line at Y=0 if available.
|
|
20
|
+
*
|
|
21
|
+
* Returns null if no representative centre can be derived (e.g. level node
|
|
22
|
+
* has no position of its own).
|
|
23
|
+
*/
|
|
24
|
+
function getCentre(node) {
|
|
25
|
+
switch (node.type) {
|
|
26
|
+
case 'wall':
|
|
27
|
+
case 'fence': {
|
|
28
|
+
const [x1, z1] = node.start;
|
|
29
|
+
const [x2, z2] = node.end;
|
|
30
|
+
return [(x1 + x2) / 2, 0, (z1 + z2) / 2];
|
|
31
|
+
}
|
|
32
|
+
case 'item':
|
|
33
|
+
case 'door':
|
|
34
|
+
case 'window':
|
|
35
|
+
case 'building':
|
|
36
|
+
case 'stair':
|
|
37
|
+
case 'roof':
|
|
38
|
+
return node.position;
|
|
39
|
+
case 'slab':
|
|
40
|
+
case 'ceiling':
|
|
41
|
+
case 'zone': {
|
|
42
|
+
const poly = node.polygon;
|
|
43
|
+
if (!poly || poly.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
let cx = 0;
|
|
46
|
+
let cz = 0;
|
|
47
|
+
for (const [x, z] of poly) {
|
|
48
|
+
cx += x;
|
|
49
|
+
cz += z;
|
|
50
|
+
}
|
|
51
|
+
return [cx / poly.length, 0, cz / poly.length];
|
|
52
|
+
}
|
|
53
|
+
case 'site': {
|
|
54
|
+
const pts = node.polygon?.points ?? [];
|
|
55
|
+
if (pts.length === 0)
|
|
56
|
+
return [0, 0, 0];
|
|
57
|
+
let cx = 0;
|
|
58
|
+
let cz = 0;
|
|
59
|
+
for (const [x, z] of pts) {
|
|
60
|
+
cx += x;
|
|
61
|
+
cz += z;
|
|
62
|
+
}
|
|
63
|
+
return [cx / pts.length, 0, cz / pts.length];
|
|
64
|
+
}
|
|
65
|
+
default:
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Compute polygon area via the shoelace formula. */
|
|
70
|
+
function shoelaceArea(polygon) {
|
|
71
|
+
if (polygon.length < 3)
|
|
72
|
+
return 0;
|
|
73
|
+
let sum = 0;
|
|
74
|
+
const n = polygon.length;
|
|
75
|
+
for (let i = 0; i < n; i++) {
|
|
76
|
+
const [x1, z1] = polygon[i];
|
|
77
|
+
const [x2, z2] = polygon[(i + 1) % n];
|
|
78
|
+
sum += x1 * z2 - x2 * z1;
|
|
79
|
+
}
|
|
80
|
+
return Math.abs(sum) / 2;
|
|
81
|
+
}
|
|
82
|
+
export function registerMeasure(server, bridge) {
|
|
83
|
+
server.registerTool('measure', {
|
|
84
|
+
title: 'Measure',
|
|
85
|
+
description: 'Measure distance (in meters) between two nodes, or the area of a polygon node when fromId === toId.',
|
|
86
|
+
inputSchema: measureInput,
|
|
87
|
+
outputSchema: measureOutput,
|
|
88
|
+
}, async ({ fromId, toId }) => {
|
|
89
|
+
const from = bridge.getNode(fromId);
|
|
90
|
+
if (!from) {
|
|
91
|
+
throwMcpError(ErrorCode.InvalidParams, `Node not found: ${fromId}`);
|
|
92
|
+
}
|
|
93
|
+
const to = bridge.getNode(toId);
|
|
94
|
+
if (!to) {
|
|
95
|
+
throwMcpError(ErrorCode.InvalidParams, `Node not found: ${toId}`);
|
|
96
|
+
}
|
|
97
|
+
// Self-measurement: compute area for polygon-bearing nodes.
|
|
98
|
+
if (fromId === toId) {
|
|
99
|
+
const n = from;
|
|
100
|
+
if (n.type === 'zone' || n.type === 'slab' || n.type === 'ceiling') {
|
|
101
|
+
const area = shoelaceArea(n.polygon);
|
|
102
|
+
const payload = {
|
|
103
|
+
distanceMeters: 0,
|
|
104
|
+
areaSqMeters: area,
|
|
105
|
+
units: 'meters',
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
109
|
+
structuredContent: payload,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// For non-polygon self, distance is 0 and no area.
|
|
113
|
+
const payload = { distanceMeters: 0, units: 'meters' };
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
116
|
+
structuredContent: payload,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const fromCentre = getCentre(from);
|
|
120
|
+
const toCentre = getCentre(to);
|
|
121
|
+
if (!(fromCentre && toCentre)) {
|
|
122
|
+
throwMcpError(ErrorCode.InvalidRequest, `Cannot derive centre for measurement between ${from.type} and ${to.type}`);
|
|
123
|
+
}
|
|
124
|
+
const dx = fromCentre[0] - toCentre[0];
|
|
125
|
+
const dy = fromCentre[1] - toCentre[1];
|
|
126
|
+
const dz = fromCentre[2] - toCentre[2];
|
|
127
|
+
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
128
|
+
const payload = {
|
|
129
|
+
distanceMeters: distance,
|
|
130
|
+
units: 'meters',
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
134
|
+
structuredContent: payload,
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { SceneOperations } from '../../operations';
|
|
3
|
+
/**
|
|
4
|
+
* Register the `photo_to_scene` orchestrator tool. Chains the vision
|
|
5
|
+
* (`analyze_floorplan_image`-equivalent sampling call) → SceneGraph
|
|
6
|
+
* synthesis → optional scene save → bridge setScene so callers get a navigable
|
|
7
|
+
* Pascal scene from a single photo upload.
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerPhotoToSceneTool(server: McpServer, bridge: SceneOperations): void;
|
|
10
|
+
export { photoToSceneInput, photoToSceneOutput, registerPhotoToScene, } from './photo-to-scene';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/photo-to-scene/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAEzF;AAED,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { registerPhotoToScene } from './photo-to-scene';
|
|
2
|
+
/**
|
|
3
|
+
* Register the `photo_to_scene` orchestrator tool. Chains the vision
|
|
4
|
+
* (`analyze_floorplan_image`-equivalent sampling call) → SceneGraph
|
|
5
|
+
* synthesis → optional scene save → bridge setScene so callers get a navigable
|
|
6
|
+
* Pascal scene from a single photo upload.
|
|
7
|
+
*/
|
|
8
|
+
export function registerPhotoToSceneTool(server, bridge) {
|
|
9
|
+
registerPhotoToScene(server, bridge);
|
|
10
|
+
}
|
|
11
|
+
export { photoToSceneInput, photoToSceneOutput, registerPhotoToScene, } from './photo-to-scene';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { SceneOperations } from '../../operations';
|
|
4
|
+
/**
|
|
5
|
+
* Input shape for the `photo_to_scene` orchestrator. `image` matches the
|
|
6
|
+
* contract documented on `analyze_floorplan_image` — base64 or http(s) URL.
|
|
7
|
+
*/
|
|
8
|
+
export declare const photoToSceneInput: {
|
|
9
|
+
image: z.ZodString;
|
|
10
|
+
scaleHint: z.ZodOptional<z.ZodString>;
|
|
11
|
+
name: z.ZodDefault<z.ZodString>;
|
|
12
|
+
save: z.ZodDefault<z.ZodBoolean>;
|
|
13
|
+
defaultWallThickness: z.ZodDefault<z.ZodNumber>;
|
|
14
|
+
defaultWallHeight: z.ZodDefault<z.ZodNumber>;
|
|
15
|
+
};
|
|
16
|
+
export declare const photoToSceneOutput: {
|
|
17
|
+
sceneId: z.ZodOptional<z.ZodString>;
|
|
18
|
+
url: z.ZodOptional<z.ZodString>;
|
|
19
|
+
walls: z.ZodNumber;
|
|
20
|
+
rooms: z.ZodNumber;
|
|
21
|
+
confidence: z.ZodNumber;
|
|
22
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
23
|
+
graph: z.ZodOptional<z.ZodAny>;
|
|
24
|
+
};
|
|
25
|
+
export declare function registerPhotoToScene(server: McpServer, bridge: SceneOperations): void;
|
|
26
|
+
//# sourceMappingURL=photo-to-scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photo-to-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/photo-to-scene/photo-to-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAYxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD;;;GAGG;AACH,eAAO,MAAM,iBAAiB;;;;;;;CAO7B,CAAA;AAED,eAAO,MAAM,kBAAkB;;;;;;;;CAQ9B,CAAA;AAiTD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA6ErF"}
|