@pascal-app/mcp 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/README.md +166 -62
- package/dist/bin/pascal-mcp.js +1 -1
- package/dist/bridge/agent-session.d.ts +18 -0
- package/dist/bridge/agent-session.d.ts.map +1 -0
- package/dist/bridge/agent-session.js +15 -0
- package/dist/bridge/index.d.ts +1 -1
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.d.ts +3 -0
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +7 -0
- package/dist/lib/safe-fetch.d.ts +22 -4
- package/dist/lib/safe-fetch.d.ts.map +1 -1
- package/dist/lib/safe-fetch.js +233 -134
- package/dist/operations/scene-operations.d.ts +18 -0
- package/dist/operations/scene-operations.d.ts.map +1 -1
- package/dist/operations/scene-operations.js +11 -0
- package/dist/prompts/from-brief.d.ts +1 -1
- package/dist/prompts/from-brief.d.ts.map +1 -1
- package/dist/prompts/from-brief.js +3 -3
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.js +2 -2
- package/dist/prompts/renovation-from-photos.d.ts +1 -1
- package/dist/prompts/renovation-from-photos.d.ts.map +1 -1
- package/dist/prompts/renovation-from-photos.js +2 -2
- package/dist/prompts/scene-guidance.d.ts.map +1 -1
- package/dist/prompts/scene-guidance.js +10 -3
- package/dist/resources/agent-guide.d.ts +1 -1
- package/dist/resources/agent-guide.d.ts.map +1 -1
- package/dist/resources/agent-guide.js +52 -44
- package/dist/resources/catalog-items.d.ts +1 -1
- package/dist/resources/catalog-items.d.ts.map +1 -1
- package/dist/resources/constraints.d.ts +1 -1
- package/dist/resources/constraints.d.ts.map +1 -1
- package/dist/resources/constraints.js +1 -1
- package/dist/resources/design-schema.d.ts +1 -1
- package/dist/resources/design-schema.d.ts.map +1 -1
- package/dist/resources/index.d.ts +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/scene-current.d.ts +1 -1
- package/dist/resources/scene-current.d.ts.map +1 -1
- package/dist/resources/scene-summary.d.ts +1 -1
- package/dist/resources/scene-summary.d.ts.map +1 -1
- package/dist/server.d.ts +7 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +59 -21
- package/dist/storage/disk-artifact-store.d.ts.map +1 -1
- package/dist/storage/sqlite-scene-store.d.ts +1 -1
- package/dist/storage/sqlite-scene-store.d.ts.map +1 -1
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/templates/empty-studio.d.ts +3 -3
- package/dist/templates/empty-studio.d.ts.map +1 -1
- package/dist/templates/garden-house.d.ts +3 -3
- package/dist/templates/garden-house.d.ts.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/two-bedroom.d.ts +3 -3
- package/dist/templates/two-bedroom.d.ts.map +1 -1
- package/dist/tools/add-column.d.ts +1 -1
- package/dist/tools/add-column.d.ts.map +1 -1
- package/dist/tools/add-column.js +3 -2
- package/dist/tools/add-object.d.ts +19 -3
- package/dist/tools/add-object.d.ts.map +1 -1
- package/dist/tools/add-object.js +66 -35
- package/dist/tools/annotations.d.ts.map +1 -1
- package/dist/tools/apply-patch.d.ts +6 -2
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +13 -8
- package/dist/tools/asset-catalog.d.ts.map +1 -1
- package/dist/tools/asset-catalog.js +23 -0
- package/dist/tools/author-scene.d.ts +10 -0
- package/dist/tools/author-scene.d.ts.map +1 -0
- package/dist/tools/author-scene.js +140 -0
- package/dist/tools/check-collisions.d.ts +6 -6
- package/dist/tools/check-collisions.d.ts.map +1 -1
- package/dist/tools/check-collisions.js +6 -6
- package/dist/tools/clear-scene.d.ts +1 -1
- package/dist/tools/clear-scene.d.ts.map +1 -1
- package/dist/tools/clear-scene.js +3 -3
- package/dist/tools/collections.d.ts +1 -1
- package/dist/tools/collections.d.ts.map +1 -1
- package/dist/tools/collections.js +3 -2
- package/dist/tools/construction-tools.d.ts +6 -49
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +9 -158
- package/dist/tools/create-unit.d.ts +3 -3
- package/dist/tools/create-unit.d.ts.map +1 -1
- package/dist/tools/create-unit.js +2 -2
- package/dist/tools/errors.d.ts +5 -5
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +4 -4
- package/dist/tools/export-glb.d.ts +1 -1
- package/dist/tools/export-glb.d.ts.map +1 -1
- package/dist/tools/export-glb.js +2 -2
- package/dist/tools/export-json.d.ts +1 -1
- package/dist/tools/export-json.d.ts.map +1 -1
- package/dist/tools/export-json.js +2 -2
- package/dist/tools/get-scene.d.ts +1 -1
- package/dist/tools/get-scene.d.ts.map +1 -1
- package/dist/tools/get-scene.js +2 -2
- package/dist/tools/hosted-services.d.ts +1 -1
- package/dist/tools/hosted-services.d.ts.map +1 -1
- package/dist/tools/hosted-services.js +13 -3
- package/dist/tools/index.d.ts +4 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +8 -13
- package/dist/tools/level-height-guard.d.ts +2 -0
- package/dist/tools/level-height-guard.d.ts.map +1 -0
- package/dist/tools/level-height-guard.js +11 -0
- package/dist/tools/list-units.d.ts +2 -2
- package/dist/tools/list-units.d.ts.map +1 -1
- package/dist/tools/list-units.js +2 -2
- package/dist/tools/live-sync.d.ts +1 -1
- package/dist/tools/live-sync.d.ts.map +1 -1
- package/dist/tools/live-sync.js +4 -4
- package/dist/tools/measure.d.ts +1 -1
- package/dist/tools/measure.d.ts.map +1 -1
- package/dist/tools/measure.js +7 -7
- package/dist/tools/node-world-point.d.ts +1 -1
- package/dist/tools/node-world-point.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.js +2 -3
- package/dist/tools/patch-guards.d.ts +6 -4
- package/dist/tools/patch-guards.d.ts.map +1 -1
- package/dist/tools/patch-guards.js +5 -2
- package/dist/tools/photo-to-scene/index.d.ts +1 -1
- package/dist/tools/photo-to-scene/index.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts +3 -3
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.js +7 -7
- package/dist/tools/project-files.d.ts +4 -0
- package/dist/tools/project-files.d.ts.map +1 -0
- package/dist/tools/project-files.js +30 -0
- package/dist/tools/redo.d.ts +2 -2
- package/dist/tools/redo.d.ts.map +1 -1
- package/dist/tools/redo.js +2 -2
- package/dist/tools/retired-tools.d.ts +10 -0
- package/dist/tools/retired-tools.d.ts.map +1 -0
- package/dist/tools/retired-tools.js +22 -0
- package/dist/tools/roof-level-guard.d.ts +2 -0
- package/dist/tools/roof-level-guard.d.ts.map +1 -0
- package/dist/tools/roof-level-guard.js +22 -0
- package/dist/tools/room-tools.d.ts +47 -46
- package/dist/tools/room-tools.d.ts.map +1 -1
- package/dist/tools/room-tools.js +6 -5
- package/dist/tools/scene-lifecycle/create-project.d.ts +1 -1
- package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/create-project.js +5 -5
- package/dist/tools/scene-lifecycle/delete-scene.d.ts +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.js +6 -6
- package/dist/tools/scene-lifecycle/get-project-status.d.ts +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.js +6 -6
- package/dist/tools/scene-lifecycle/index.d.ts +1 -1
- package/dist/tools/scene-lifecycle/index.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.js +4 -4
- package/dist/tools/scene-lifecycle/load-scene.d.ts +2 -2
- package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/load-scene.js +5 -5
- package/dist/tools/scene-lifecycle/metadata.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.js +6 -6
- package/dist/tools/scene-lifecycle/save-scene.d.ts +5 -3
- package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/save-scene.js +80 -12
- package/dist/tools/scene-lifecycle/test-utils.d.ts +1 -1
- package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -1
- package/dist/tools/set-unit-members.d.ts +2 -2
- package/dist/tools/set-unit-members.d.ts.map +1 -1
- package/dist/tools/set-unit-members.js +6 -6
- package/dist/tools/set-zone.d.ts +2 -2
- package/dist/tools/set-zone.d.ts.map +1 -1
- package/dist/tools/set-zone.js +30 -18
- package/dist/tools/shared-tools.d.ts +15 -5
- package/dist/tools/shared-tools.d.ts.map +1 -1
- package/dist/tools/shared-tools.js +242 -29
- package/dist/tools/structure-tools.d.ts +3 -3
- package/dist/tools/templates/create-from-template.d.ts +2 -2
- package/dist/tools/templates/create-from-template.d.ts.map +1 -1
- package/dist/tools/templates/create-from-template.js +6 -6
- package/dist/tools/templates/create-house-from-brief.d.ts +1 -1
- package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -1
- package/dist/tools/templates/create-house-from-brief.js +6 -6
- package/dist/tools/templates/index.d.ts +1 -1
- package/dist/tools/templates/index.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.d.ts +1 -1
- package/dist/tools/templates/list-templates.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.js +2 -2
- package/dist/tools/undo.d.ts +2 -2
- package/dist/tools/undo.d.ts.map +1 -1
- package/dist/tools/undo.js +2 -2
- package/dist/tools/unit-members.d.ts.map +1 -1
- package/dist/tools/unit-members.js +6 -6
- package/dist/tools/variants/generate-variants.d.ts +6 -6
- package/dist/tools/variants/generate-variants.d.ts.map +1 -1
- package/dist/tools/variants/generate-variants.js +6 -6
- package/dist/tools/variants/index.d.ts +1 -1
- package/dist/tools/variants/index.d.ts.map +1 -1
- package/dist/tools/view-scene.d.ts +8 -2
- package/dist/tools/view-scene.d.ts.map +1 -1
- package/dist/tools/view-scene.js +17 -5
- package/dist/tools/vision/analyze-floorplan-image.d.ts +1 -1
- package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -1
- package/dist/tools/vision/analyze-floorplan-image.js +7 -7
- package/dist/tools/vision/analyze-room-photo.d.ts +1 -1
- package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -1
- package/dist/tools/vision/analyze-room-photo.js +7 -7
- package/dist/tools/vision/index.d.ts +1 -1
- package/dist/tools/vision/index.d.ts.map +1 -1
- package/dist/transports/http.d.ts +8 -2
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +9 -3
- package/dist/transports/stdio.d.ts +15 -9
- package/dist/transports/stdio.d.ts.map +1 -1
- package/dist/transports/stdio.js +18 -11
- package/examples/coordinate-conventions-demo.md +12 -13
- package/examples/embed-in-agent.ts +5 -6
- package/examples/generate-apartment.md +4 -4
- package/examples/photo-to-scene.md +2 -3
- package/examples/renovate-from-photos.md +3 -5
- package/package.json +13 -9
- package/dist/tools/describe-node.d.ts +0 -17
- package/dist/tools/describe-node.d.ts.map +0 -1
- package/dist/tools/describe-node.js +0 -99
- package/dist/tools/find-nodes.d.ts +0 -16
- package/dist/tools/find-nodes.d.ts.map +0 -1
- package/dist/tools/find-nodes.js +0 -204
- package/dist/tools/place-design.d.ts +0 -34
- package/dist/tools/place-design.d.ts.map +0 -1
- package/dist/tools/place-design.js +0 -91
- package/dist/tools/validate-design.d.ts +0 -136
- package/dist/tools/validate-design.d.ts.map +0 -1
- package/dist/tools/validate-design.js +0 -28
- package/dist/tools/validate-scene.d.ts +0 -19
- package/dist/tools/validate-scene.d.ts.map +0 -1
- package/dist/tools/validate-scene.js +0 -28
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { SceneNotFoundError, SceneVersionConflictError } from '../../storage/types.js';
|
|
3
3
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
5
5
|
export const deleteSceneInput = {
|
|
6
6
|
id: z.string().min(1).max(64),
|
|
7
7
|
expectedVersion: z.number().int().positive().optional(),
|
|
@@ -15,8 +15,8 @@ export function registerDeleteScene(server, operations) {
|
|
|
15
15
|
server.registerTool('delete_scene', {
|
|
16
16
|
title: 'Delete scene',
|
|
17
17
|
description: "Remove a stored scene by id. In Pascal this never deletes the project: it hides it from Pascal's public listings until it is next saved with content, and answers `deleted: false, hidden: true` with a message; its owner can delete it from the projects page. Only someone who can manage the project may hide it. A local scene store deletes the scene. Optionally pass `expectedVersion` for optimistic concurrency.",
|
|
18
|
-
inputSchema: deleteSceneInput,
|
|
19
|
-
outputSchema: deleteSceneOutput,
|
|
18
|
+
inputSchema: z.object(deleteSceneInput),
|
|
19
|
+
outputSchema: z.object(deleteSceneOutput),
|
|
20
20
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
21
21
|
}, async ({ id, expectedVersion }) => {
|
|
22
22
|
try {
|
|
@@ -30,16 +30,16 @@ export function registerDeleteScene(server, operations) {
|
|
|
30
30
|
}
|
|
31
31
|
catch (err) {
|
|
32
32
|
if (err instanceof SceneNotFoundError) {
|
|
33
|
-
throwMcpError(
|
|
33
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'scene_not_found', { id });
|
|
34
34
|
}
|
|
35
35
|
if (err instanceof SceneVersionConflictError) {
|
|
36
|
-
throwMcpError(
|
|
36
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, 'version_conflict', {
|
|
37
37
|
id,
|
|
38
38
|
expectedVersion,
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
const msg = err instanceof Error ? err.message : String(err);
|
|
42
|
-
throwMcpError(
|
|
42
|
+
throwMcpError(ProtocolErrorCode.InternalError, msg);
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../../operations/index.js';
|
|
4
4
|
export declare const getProjectStatusInput: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-project-status.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/get-project-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"get-project-status.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/get-project-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAKvD,eAAO,MAAM,qBAAqB;IAChC,EAAE;CACH,CAAA;AAED,eAAO,MAAM,sBAAsB;IACjC,EAAE;IACF,SAAS;IACT,IAAI;IACJ,SAAS;IACT,GAAG;IACH,OAAO;IACP,YAAY;IACZ,gBAAgB;IAChB,aAAa;IACb,YAAY;IACZ,qBAAqB;IACrB,OAAO;IACP,OAAO;IACP,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,QAAQ;IACR,cAAc;IACd,QAAQ;CACT,CAAA;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CA4C7F"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ProtocolError, ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
4
4
|
import { currentLevelContext, projectStatusPayload } from './metadata.js';
|
|
5
5
|
export const getProjectStatusInput = {
|
|
6
6
|
id: z.string().min(1).max(64),
|
|
@@ -32,14 +32,14 @@ export function registerGetProjectStatus(server, operations) {
|
|
|
32
32
|
server.registerTool('get_project_status', {
|
|
33
33
|
title: 'Get project status',
|
|
34
34
|
description: 'Authoritative status/debug call for a Pascal project: editor URL, browser-visible version, latest saved version, published version, node count, and graph hash.',
|
|
35
|
-
inputSchema: getProjectStatusInput,
|
|
36
|
-
outputSchema: getProjectStatusOutput,
|
|
35
|
+
inputSchema: z.object(getProjectStatusInput),
|
|
36
|
+
outputSchema: z.object(getProjectStatusOutput),
|
|
37
37
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
38
38
|
}, async ({ id }) => {
|
|
39
39
|
try {
|
|
40
40
|
const status = await operations.getProjectStatus(id);
|
|
41
41
|
if (!status) {
|
|
42
|
-
throwMcpError(
|
|
42
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'project_not_found', { id });
|
|
43
43
|
}
|
|
44
44
|
const activeScene = operations.getActiveScene();
|
|
45
45
|
if (activeScene?.id !== status.id) {
|
|
@@ -62,10 +62,10 @@ export function registerGetProjectStatus(server, operations) {
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
catch (err) {
|
|
65
|
-
if (err instanceof
|
|
65
|
+
if (err instanceof ProtocolError)
|
|
66
66
|
throw err;
|
|
67
67
|
const msg = err instanceof Error ? err.message : String(err);
|
|
68
|
-
throwMcpError(
|
|
68
|
+
throwMcpError(ProtocolErrorCode.InternalError, msg);
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
71
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { SceneOperations } from '../../operations/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Register the scene-lifecycle MCP tools (`save_scene`, `load_scene`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AASvD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAQhG;AAED,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACjG,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AACzF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACrF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACjF,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACzF,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../../operations/index.js';
|
|
4
4
|
export declare const listScenesInput: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-scenes.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/list-scenes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"list-scenes.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/list-scenes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAMvD,eAAO,MAAM,eAAe;IAC1B,SAAS;IACT,KAAK;CACN,CAAA;AAED,eAAO,MAAM,gBAAgB;IAC3B,MAAM;;;;;;;;;;;;;;;;CAkBP,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CA4BvF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { READ_ONLY_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
4
4
|
const DEFAULT_LIMIT = 100;
|
|
5
5
|
export const listScenesInput = {
|
|
6
6
|
projectId: z.string().optional(),
|
|
@@ -28,8 +28,8 @@ export function registerListScenes(server, operations) {
|
|
|
28
28
|
server.registerTool('list_scenes', {
|
|
29
29
|
title: 'List scenes',
|
|
30
30
|
description: 'List scenes in the SceneStore. Optionally filter by `projectId` and cap results with `limit` (default 100).',
|
|
31
|
-
inputSchema: listScenesInput,
|
|
32
|
-
outputSchema: listScenesOutput,
|
|
31
|
+
inputSchema: z.object(listScenesInput),
|
|
32
|
+
outputSchema: z.object(listScenesOutput),
|
|
33
33
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
34
34
|
}, async ({ projectId, limit }) => {
|
|
35
35
|
try {
|
|
@@ -45,7 +45,7 @@ export function registerListScenes(server, operations) {
|
|
|
45
45
|
}
|
|
46
46
|
catch (err) {
|
|
47
47
|
const msg = err instanceof Error ? err.message : String(err);
|
|
48
|
-
throwMcpError(
|
|
48
|
+
throwMcpError(ProtocolErrorCode.InternalError, msg);
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../../operations/index.js';
|
|
4
4
|
export declare const loadSceneInput: {
|
|
@@ -20,8 +20,8 @@ export declare const loadSceneOutput: {
|
|
|
20
20
|
published: z.ZodBoolean;
|
|
21
21
|
isDraft: z.ZodBoolean;
|
|
22
22
|
saveMode: z.ZodEnum<{
|
|
23
|
-
draft: "draft";
|
|
24
23
|
checkpoint: "checkpoint";
|
|
24
|
+
draft: "draft";
|
|
25
25
|
}>;
|
|
26
26
|
graphHash: z.ZodOptional<z.ZodString>;
|
|
27
27
|
levelIds: z.ZodArray<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/load-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"load-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/load-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAKvD,eAAO,MAAM,cAAc;IACzB,EAAE;CACH,CAAA;AAED,eAAO,MAAM,eAAe;IAC1B,EAAE;IACF,IAAI;IACJ,SAAS;IACT,YAAY;IACZ,OAAO;IACP,SAAS;IACT,SAAS;IACT,OAAO;IACP,SAAS;IACT,SAAS;IACT,GAAG;IACH,SAAS;IACT,SAAS;IACT,OAAO;IACP,QAAQ;;;;IACR,SAAS;IACT,QAAQ;IACR,cAAc;CACf,CAAA;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAiClF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
4
4
|
import { currentLevelContext, sceneMetaPayload } from './metadata.js';
|
|
5
5
|
export const loadSceneInput = {
|
|
6
6
|
id: z.string().min(1).max(64),
|
|
@@ -29,13 +29,13 @@ export function registerLoadScene(server, bridge) {
|
|
|
29
29
|
server.registerTool('load_scene', {
|
|
30
30
|
title: 'Load scene',
|
|
31
31
|
description: 'Load a scene from the SceneStore into the bridge. Returns the scene metadata. Throws `scene_not_found` if the id does not exist.',
|
|
32
|
-
inputSchema: loadSceneInput,
|
|
33
|
-
outputSchema: loadSceneOutput,
|
|
32
|
+
inputSchema: z.object(loadSceneInput),
|
|
33
|
+
outputSchema: z.object(loadSceneOutput),
|
|
34
34
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
35
35
|
}, async ({ id }) => {
|
|
36
36
|
const result = await bridge.loadStoredScene(id);
|
|
37
37
|
if (!result) {
|
|
38
|
-
throwMcpError(
|
|
38
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'scene_not_found', { id });
|
|
39
39
|
}
|
|
40
40
|
try {
|
|
41
41
|
bridge.loadJSON(result.graph);
|
|
@@ -43,7 +43,7 @@ export function registerLoadScene(server, bridge) {
|
|
|
43
43
|
}
|
|
44
44
|
catch (err) {
|
|
45
45
|
const msg = err instanceof Error ? err.message : String(err);
|
|
46
|
-
throwMcpError(
|
|
46
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, `load_failed: ${msg}`, { id });
|
|
47
47
|
}
|
|
48
48
|
const payload = {
|
|
49
49
|
...sceneMetaPayload(result, result.graph),
|
|
@@ -22,7 +22,6 @@ export declare function sceneMetaPayload(meta: SceneMeta, graph?: SceneGraph): {
|
|
|
22
22
|
graphHash: string | undefined;
|
|
23
23
|
};
|
|
24
24
|
export declare function projectStatusPayload(status: ProjectStatus, nextStep?: string): {
|
|
25
|
-
nextStep?: string | undefined;
|
|
26
25
|
id: string;
|
|
27
26
|
projectId: string;
|
|
28
27
|
name: string;
|
|
@@ -41,6 +40,7 @@ export declare function projectStatusPayload(status: ProjectStatus, nextStep?: s
|
|
|
41
40
|
graphHash: string | null;
|
|
42
41
|
createdAt: string;
|
|
43
42
|
updatedAt: string;
|
|
43
|
+
nextStep?: string | undefined;
|
|
44
44
|
};
|
|
45
45
|
export declare function currentLevelContext(operations: SceneOperations): {
|
|
46
46
|
levelIds: string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../../operations/index.js';
|
|
4
4
|
export declare const renameSceneInput: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rename-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/rename-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"rename-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/rename-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAKvD,eAAO,MAAM,gBAAgB;IAC3B,EAAE;IACF,OAAO;IACP,eAAe;CAChB,CAAA;AAED,eAAO,MAAM,iBAAiB;IAC5B,EAAE;IACF,IAAI;IACJ,SAAS;IACT,YAAY;IACZ,OAAO;IACP,SAAS;IACT,SAAS;IACT,OAAO;IACP,SAAS;IACT,SAAS;CACV,CAAA;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CA+CxF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { SceneNotFoundError, SceneVersionConflictError } from '../../storage/types.js';
|
|
3
3
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
5
5
|
export const renameSceneInput = {
|
|
6
6
|
id: z.string().min(1).max(64),
|
|
7
7
|
newName: z.string().min(1).max(200),
|
|
@@ -23,8 +23,8 @@ export function registerRenameScene(server, operations) {
|
|
|
23
23
|
server.registerTool('rename_scene', {
|
|
24
24
|
title: 'Rename scene',
|
|
25
25
|
description: 'Rename a scene in the SceneStore. Returns the updated SceneMeta. Optionally pass `expectedVersion` for optimistic concurrency.',
|
|
26
|
-
inputSchema: renameSceneInput,
|
|
27
|
-
outputSchema: renameSceneOutput,
|
|
26
|
+
inputSchema: z.object(renameSceneInput),
|
|
27
|
+
outputSchema: z.object(renameSceneOutput),
|
|
28
28
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
29
29
|
}, async ({ id, newName, expectedVersion }) => {
|
|
30
30
|
try {
|
|
@@ -50,16 +50,16 @@ export function registerRenameScene(server, operations) {
|
|
|
50
50
|
}
|
|
51
51
|
catch (err) {
|
|
52
52
|
if (err instanceof SceneNotFoundError) {
|
|
53
|
-
throwMcpError(
|
|
53
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'scene_not_found', { id });
|
|
54
54
|
}
|
|
55
55
|
if (err instanceof SceneVersionConflictError) {
|
|
56
|
-
throwMcpError(
|
|
56
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, 'version_conflict', {
|
|
57
57
|
id,
|
|
58
58
|
expectedVersion,
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
const msg = err instanceof Error ? err.message : String(err);
|
|
62
|
-
throwMcpError(
|
|
62
|
+
throwMcpError(ProtocolErrorCode.InternalError, msg);
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../../operations/index.js';
|
|
4
4
|
export declare const saveSceneInput: {
|
|
@@ -8,8 +8,8 @@ export declare const saveSceneInput: {
|
|
|
8
8
|
expectedVersion: z.ZodOptional<z.ZodNumber>;
|
|
9
9
|
replace: z.ZodOptional<z.ZodBoolean>;
|
|
10
10
|
saveMode: z.ZodDefault<z.ZodEnum<{
|
|
11
|
-
draft: "draft";
|
|
12
11
|
checkpoint: "checkpoint";
|
|
12
|
+
draft: "draft";
|
|
13
13
|
}>>;
|
|
14
14
|
publish: z.ZodOptional<z.ZodBoolean>;
|
|
15
15
|
thumbnail: z.ZodOptional<z.ZodString>;
|
|
@@ -32,12 +32,14 @@ export declare const saveSceneOutput: {
|
|
|
32
32
|
published: z.ZodBoolean;
|
|
33
33
|
isDraft: z.ZodBoolean;
|
|
34
34
|
saveMode: z.ZodEnum<{
|
|
35
|
-
draft: "draft";
|
|
36
35
|
checkpoint: "checkpoint";
|
|
36
|
+
draft: "draft";
|
|
37
37
|
}>;
|
|
38
38
|
graphHash: z.ZodOptional<z.ZodString>;
|
|
39
39
|
levelIds: z.ZodArray<z.ZodString>;
|
|
40
40
|
defaultLevelId: z.ZodNullable<z.ZodString>;
|
|
41
|
+
/** What the server changed in a provided graph before saving it, one line each. */
|
|
42
|
+
notes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
41
43
|
};
|
|
42
44
|
export declare function registerSaveScene(server: McpServer, bridge: SceneOperations): void;
|
|
43
45
|
//# sourceMappingURL=save-scene.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/save-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"save-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/save-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAU7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAOvD,eAAO,MAAM,cAAc;IACzB,EAAE;IACF,IAAI;IACJ,SAAS;IACT,eAAe;IACf,OAAO;IAMP,QAAQ;;;;IAMR,OAAO;IAMP,SAAS;IACT,mBAAmB;IAInB,KAAK;CAMN,CAAA;AAED,eAAO,MAAM,eAAe;IAC1B,EAAE;IACF,IAAI;IACJ,SAAS;IACT,YAAY;IACZ,OAAO;IACP,SAAS;IACT,SAAS;IACT,OAAO;IACP,SAAS;IACT,SAAS;IACT,GAAG;IACH,SAAS;IACT,SAAS;IACT,OAAO;IACP,QAAQ;;;;IACR,SAAS;IACT,QAAQ;IACR,cAAc;IACd,mFAAmF;IACnF,KAAK;CACN,CAAA;AAgFD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqIlF"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { applySceneWrites, seatWrittenRoofs, } from '@pascal-app/core/agent-operations';
|
|
2
|
+
import { isAgentRefusal } from '@pascal-app/core/agent-tools';
|
|
1
3
|
import { migrateLegacyWallAssemblies } from '@pascal-app/core/scene-migrations';
|
|
2
4
|
import { AnyNode } from '@pascal-app/core/schema';
|
|
3
5
|
import { z } from 'zod';
|
|
4
6
|
import { SceneVersionConflictError } from '../../storage/types.js';
|
|
5
7
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
6
|
-
import {
|
|
8
|
+
import { ProtocolErrorCode, throwMcpError, toolError } from '../errors.js';
|
|
7
9
|
import { appendLiveSceneEvent } from '../live-sync.js';
|
|
8
10
|
import { currentLevelContext, sceneMetaPayload } from './metadata.js';
|
|
9
11
|
export const saveSceneInput = {
|
|
@@ -31,7 +33,7 @@ export const saveSceneInput = {
|
|
|
31
33
|
graph: z
|
|
32
34
|
.record(z.string(), z.unknown())
|
|
33
35
|
.optional()
|
|
34
|
-
.describe(
|
|
36
|
+
.describe("Full SceneGraph { nodes, rootNodeIds, collections? } to save instead of the bridge state. Judged against the scene it is saved over (the session's scene when the save goes to it, else the stored scene `id` names) as apply_patch is: a roof it puts on the walls of the storey holding it goes to the level above them, said in notes, and storey content on a roof level is refused. A graph with no scene under it is saved as it is."),
|
|
35
37
|
};
|
|
36
38
|
export const saveSceneOutput = {
|
|
37
39
|
id: z.string(),
|
|
@@ -52,7 +54,50 @@ export const saveSceneOutput = {
|
|
|
52
54
|
graphHash: z.string().optional(),
|
|
53
55
|
levelIds: z.array(z.string()),
|
|
54
56
|
defaultLevelId: z.string().nullable(),
|
|
57
|
+
/** What the server changed in a provided graph before saving it, one line each. */
|
|
58
|
+
notes: z.array(z.string()).optional(),
|
|
55
59
|
};
|
|
60
|
+
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
61
|
+
/** A graph as writes over the scene in hand, so a rule on writes judges only what it changes. */
|
|
62
|
+
function writesOver(scene, nodes) {
|
|
63
|
+
const writes = [];
|
|
64
|
+
for (const node of Object.values(nodes)) {
|
|
65
|
+
const prior = scene[node.id];
|
|
66
|
+
if (!prior) {
|
|
67
|
+
writes.push({ op: 'create', node });
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const next = node;
|
|
71
|
+
const data = Object.fromEntries([...new Set([...Object.keys(prior), ...Object.keys(next)])]
|
|
72
|
+
.filter((key) => !same(prior[key], next[key]))
|
|
73
|
+
.map((key) => [key, next[key]]));
|
|
74
|
+
if (Object.keys(data).length)
|
|
75
|
+
writes.push({ op: 'update', id: node.id, data });
|
|
76
|
+
}
|
|
77
|
+
for (const id of Object.keys(scene))
|
|
78
|
+
if (!nodes[id])
|
|
79
|
+
writes.push({ op: 'delete', id });
|
|
80
|
+
return writes;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The scene a provided graph is saved over, as it stands: the session's when the save goes to the
|
|
84
|
+
* scene in hand, else the stored one. Null for a new scene: a graph with nothing under it is saved
|
|
85
|
+
* as it is, its roofs never judged against an unrelated scene (a legacy project saved from a fresh
|
|
86
|
+
* session would otherwise read as all new writes, and be migrated or refused).
|
|
87
|
+
*/
|
|
88
|
+
async function savedOver(bridge, target) {
|
|
89
|
+
const active = bridge.getActiveScene();
|
|
90
|
+
const inHand = active &&
|
|
91
|
+
(target.id !== undefined
|
|
92
|
+
? active.id === target.id
|
|
93
|
+
: target.projectId !== undefined && active.projectId === target.projectId);
|
|
94
|
+
if (inHand)
|
|
95
|
+
return bridge.getNodes();
|
|
96
|
+
if (target.id === undefined)
|
|
97
|
+
return null;
|
|
98
|
+
const stored = await bridge.loadStoredScene(target.id).catch(() => null);
|
|
99
|
+
return stored?.graph.nodes ?? null;
|
|
100
|
+
}
|
|
56
101
|
/** A saved scene that is more than the default site, building and level. */
|
|
57
102
|
const HOLDS_CONTENT = 3;
|
|
58
103
|
/**
|
|
@@ -73,14 +118,14 @@ async function requireSceneLoadedFrom(bridge, target) {
|
|
|
73
118
|
: 0;
|
|
74
119
|
if (nodeCount <= HOLDS_CONTENT)
|
|
75
120
|
return;
|
|
76
|
-
throwMcpError(
|
|
121
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, `scene_not_loaded: this session's scene was not loaded from ${target.projectId ?? target.id}, which holds ${nodeCount} nodes — the server may have reloaded and this session started over. Call load_scene with it first, or pass replace: true to write this scene over it.`, { ...target, nodeCount });
|
|
77
122
|
}
|
|
78
123
|
export function registerSaveScene(server, bridge) {
|
|
79
124
|
server.registerTool('save_scene', {
|
|
80
125
|
title: 'Save scene',
|
|
81
126
|
description: 'Save the current scene (or a provided graph) to the SceneStore. Without id or projectId it saves to the project this session is bound to (create_project or load_scene). Defaults to a browser-visible draft save so agents can iterate without creating many project versions. Use saveMode: "checkpoint" for meaningful version history.',
|
|
82
|
-
inputSchema: saveSceneInput,
|
|
83
|
-
outputSchema: saveSceneOutput,
|
|
127
|
+
inputSchema: z.object(saveSceneInput),
|
|
128
|
+
outputSchema: z.object(saveSceneOutput),
|
|
84
129
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
85
130
|
}, async ({ id, name, projectId, expectedVersion, saveMode, publish, thumbnail, includeCurrentScene, graph, replace, }) => {
|
|
86
131
|
// Without a target, the session's scene goes where it came from (create_project, load_scene,
|
|
@@ -94,25 +139,28 @@ export function registerSaveScene(server, bridge) {
|
|
|
94
139
|
projectId = bound.projectId ?? undefined;
|
|
95
140
|
}
|
|
96
141
|
let sceneGraph;
|
|
142
|
+
let notes = [];
|
|
97
143
|
if (includeCurrentScene && !replace)
|
|
98
144
|
await requireSceneLoadedFrom(bridge, { id, projectId });
|
|
99
145
|
if (includeCurrentScene) {
|
|
100
146
|
const validation = bridge.validateScene();
|
|
101
147
|
if (!validation.valid) {
|
|
102
|
-
throwMcpError(
|
|
148
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, 'scene_invalid', {
|
|
149
|
+
errors: validation.errors,
|
|
150
|
+
});
|
|
103
151
|
}
|
|
104
152
|
sceneGraph = bridge.exportSceneGraph();
|
|
105
153
|
}
|
|
106
154
|
else {
|
|
107
155
|
if (!graph) {
|
|
108
|
-
throwMcpError(
|
|
156
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'graph_required: pass `graph` when includeCurrentScene is false');
|
|
109
157
|
}
|
|
110
158
|
// Security: revalidate every node with AnyNode schema (including the
|
|
111
159
|
// AssetUrl allowlist) BEFORE persisting. Without this, the save_scene
|
|
112
160
|
// graph arg is a bypass for the URL hardening in A7. See P4 report.
|
|
113
161
|
const rawNodes = graph.nodes;
|
|
114
162
|
if (!rawNodes || typeof rawNodes !== 'object') {
|
|
115
|
-
throwMcpError(
|
|
163
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'graph.nodes must be an object');
|
|
116
164
|
}
|
|
117
165
|
const migration = migrateLegacyWallAssemblies(rawNodes);
|
|
118
166
|
const errors = [];
|
|
@@ -129,9 +177,28 @@ export function registerSaveScene(server, bridge) {
|
|
|
129
177
|
}
|
|
130
178
|
}
|
|
131
179
|
if (errors.length > 0) {
|
|
132
|
-
throwMcpError(
|
|
180
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'graph_invalid', { errors });
|
|
181
|
+
}
|
|
182
|
+
// The roof-level rule, as apply_patch holds it: what the graph changes in the scene it
|
|
183
|
+
// replaces.
|
|
184
|
+
const scene = await savedOver(bridge, { id, projectId });
|
|
185
|
+
let nodes = migration.nodes;
|
|
186
|
+
if (scene) {
|
|
187
|
+
const writes = writesOver(scene, nodes);
|
|
188
|
+
const written = writes.length;
|
|
189
|
+
try {
|
|
190
|
+
notes = seatWrittenRoofs(writes, scene);
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
if (!isAgentRefusal(error))
|
|
194
|
+
throw error;
|
|
195
|
+
// An index into the graph's writes means nothing to the caller; the ids do.
|
|
196
|
+
const { index: _index, ...details } = error.details;
|
|
197
|
+
return toolError(error.message, { code: error.code, ...details });
|
|
198
|
+
}
|
|
199
|
+
nodes = applySceneWrites(nodes, writes.slice(written));
|
|
133
200
|
}
|
|
134
|
-
sceneGraph = { ...graph, nodes
|
|
201
|
+
sceneGraph = { ...graph, nodes };
|
|
135
202
|
}
|
|
136
203
|
try {
|
|
137
204
|
const meta = await bridge.saveScene({
|
|
@@ -152,6 +219,7 @@ export function registerSaveScene(server, bridge) {
|
|
|
152
219
|
const payload = {
|
|
153
220
|
...sceneMetaPayload(meta, sceneGraph),
|
|
154
221
|
...currentLevelContext(bridge),
|
|
222
|
+
...(notes.length ? { notes } : {}),
|
|
155
223
|
};
|
|
156
224
|
return {
|
|
157
225
|
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
@@ -160,13 +228,13 @@ export function registerSaveScene(server, bridge) {
|
|
|
160
228
|
}
|
|
161
229
|
catch (err) {
|
|
162
230
|
if (err instanceof SceneVersionConflictError) {
|
|
163
|
-
throwMcpError(
|
|
231
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, 'version_conflict', {
|
|
164
232
|
expectedVersion,
|
|
165
233
|
id,
|
|
166
234
|
});
|
|
167
235
|
}
|
|
168
236
|
const msg = err instanceof Error ? err.message : String(err);
|
|
169
|
-
throwMcpError(
|
|
237
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, msg);
|
|
170
238
|
}
|
|
171
239
|
});
|
|
172
240
|
}
|
|
@@ -20,7 +20,7 @@ export declare function createTestSceneOperations(options?: {
|
|
|
20
20
|
* `expectedVersion`.
|
|
21
21
|
*/
|
|
22
22
|
export declare class InMemorySceneStore implements SceneStore {
|
|
23
|
-
readonly backend:
|
|
23
|
+
readonly backend: 'sqlite';
|
|
24
24
|
private readonly data;
|
|
25
25
|
private readonly projects;
|
|
26
26
|
private readonly events;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAEf,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAA;AAG5B,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEnF;AAED,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAClD,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,KAAK,CAAC,EAAE,kBAAkB,CAAA;CAC3B,GAAG;IACF,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,kBAAkB,CAAA;IACzB,UAAU,EAAE,eAAe,CAAA;CAC5B,CAKA;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACnD,QAAQ,CAAC,OAAO,EAAG,QAAQ,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAWtB;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,YAAY,CAAI;IAElB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAEf,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAA;AAG5B,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9D,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEnF;AAED,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAClD,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,KAAK,CAAC,EAAE,kBAAkB,CAAA;CAC3B,GAAG;IACF,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,kBAAkB,CAAA;IACzB,UAAU,EAAE,eAAe,CAAA;CAC5B,CAKA;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACnD,QAAQ,CAAC,OAAO,EAAG,QAAQ,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAWtB;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,YAAY,CAAI;IAElB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAatE;IAEK,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAGhE;IAEK,IAAI,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CA6DrD;IAEK,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOrD;IAEK,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAWxD;IAEK,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAU9E;IAEK,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,SAAS,CAAC,CAiBvF;IAEK,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,UAAU,CAAC,CAWzE;IAEK,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAQ1F;IAED,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,MAAM;IAoBd,OAAO,CAAC,eAAe;CA0BxB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../operations/index.js';
|
|
4
4
|
export declare const setUnitMembersInput: {
|
|
@@ -10,8 +10,8 @@ export declare const setUnitMembersOutput: {
|
|
|
10
10
|
unsaved: z.ZodOptional<z.ZodString>;
|
|
11
11
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
12
12
|
status: z.ZodEnum<{
|
|
13
|
-
unbound: "unbound";
|
|
14
13
|
events_unsupported: "events_unsupported";
|
|
14
|
+
unbound: "unbound";
|
|
15
15
|
}>;
|
|
16
16
|
warning: z.ZodString;
|
|
17
17
|
}, z.core.$strip>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set-unit-members.d.ts","sourceRoot":"","sources":["../../src/tools/set-unit-members.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"set-unit-members.d.ts","sourceRoot":"","sources":["../../src/tools/set-unit-members.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAE7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,mBAAmB;IAC9B,MAAM;IACN,aAAa;CACd,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;CAIhC,CAAA;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAmCvF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ProtocolErrorCode, throwMcpError } from './errors.js';
|
|
4
4
|
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
5
5
|
import { NodeIdSchema } from './schemas.js';
|
|
6
6
|
import { validateUnitMembers } from './unit-members.js';
|
|
@@ -17,19 +17,19 @@ export function registerSetUnitMembers(server, bridge) {
|
|
|
17
17
|
server.registerTool('set_unit_members', {
|
|
18
18
|
title: 'Set unit members',
|
|
19
19
|
description: 'Replace the zones referenced by a unit. Every zone must belong to a level in the same building.',
|
|
20
|
-
inputSchema: setUnitMembersInput,
|
|
21
|
-
outputSchema: setUnitMembersOutput,
|
|
20
|
+
inputSchema: z.object(setUnitMembersInput),
|
|
21
|
+
outputSchema: z.object(setUnitMembersOutput),
|
|
22
22
|
annotations: { ...DESTRUCTIVE_TOOL_ANNOTATIONS, idempotentHint: true },
|
|
23
23
|
}, async ({ unitId, memberZoneIds }) => {
|
|
24
24
|
const unit = bridge.getNode(unitId);
|
|
25
25
|
if (!unit) {
|
|
26
|
-
throwMcpError(
|
|
26
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Unit not found: ${unitId}`);
|
|
27
27
|
}
|
|
28
28
|
if (unit.type !== 'unit') {
|
|
29
|
-
throwMcpError(
|
|
29
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Node ${unitId} is a ${unit.type}, expected unit`);
|
|
30
30
|
}
|
|
31
31
|
if (!unit.parentId) {
|
|
32
|
-
throwMcpError(
|
|
32
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Unit ${unitId} must belong to a building`);
|
|
33
33
|
}
|
|
34
34
|
const members = validateUnitMembers(bridge, unit.parentId, memberZoneIds);
|
|
35
35
|
bridge.updateNode(unit.id, { members });
|
package/dist/tools/set-zone.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../operations/index.js';
|
|
4
4
|
export declare const setZoneInput: {
|
|
@@ -12,8 +12,8 @@ export declare const setZoneOutput: {
|
|
|
12
12
|
unsaved: z.ZodOptional<z.ZodString>;
|
|
13
13
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
14
14
|
status: z.ZodEnum<{
|
|
15
|
-
unbound: "unbound";
|
|
16
15
|
events_unsupported: "events_unsupported";
|
|
16
|
+
unbound: "unbound";
|
|
17
17
|
}>;
|
|
18
18
|
warning: z.ZodString;
|
|
19
19
|
}, z.core.$strip>>;
|
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"set-zone.d.ts","sourceRoot":"","sources":["../../src/tools/set-zone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAI7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,eAAO,MAAM,YAAY;IACvB,OAAO;IACP,OAAO;IACP,KAAK;IACL,UAAU;CACX,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;CAGzB,CAAA;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAwDhF"}
|