@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-project.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/create-project.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,kBAAkB,CAAA;AAKvD,eAAO,MAAM,kBAAkB;;;;CAI9B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;CAsB/B,CAAA;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"create-project.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/create-project.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,kBAAkB,CAAA;AAKvD,eAAO,MAAM,kBAAkB;;;;CAI9B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;CAsB/B,CAAA;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CA4E1F"}
|
|
@@ -42,6 +42,7 @@ export function registerCreateProject(server, operations) {
|
|
|
42
42
|
throwMcpError(ErrorCode.InvalidRequest, 'create_project_unavailable: this MCP store cannot create hosted projects');
|
|
43
43
|
}
|
|
44
44
|
try {
|
|
45
|
+
const bound = operations.getActiveScene();
|
|
45
46
|
const status = await operations.createProject({
|
|
46
47
|
name,
|
|
47
48
|
...(id !== undefined ? { id } : {}),
|
|
@@ -55,8 +56,32 @@ export function registerCreateProject(server, operations) {
|
|
|
55
56
|
thumbnailUrl: status.thumbnailUrl,
|
|
56
57
|
version: status.version,
|
|
57
58
|
});
|
|
59
|
+
// A session bound to another project starts the new one empty: carried over, that
|
|
60
|
+
// project's scene was saved into the new one. Work bound to no project, a saved scene of
|
|
61
|
+
// none included, is kept: it is what the new project is for. Emptied once bound to the new
|
|
62
|
+
// project, so nothing that follows the scene can write the empty scene to the old one.
|
|
63
|
+
if (bound?.projectId && bound.projectId !== status.projectId) {
|
|
64
|
+
operations.loadJSON({ nodes: {}, rootNodeIds: [] });
|
|
65
|
+
operations.loadDefault();
|
|
66
|
+
operations.clearHistory();
|
|
67
|
+
}
|
|
68
|
+
// A scene from the first call: its first draft is what this session holds (the empty
|
|
69
|
+
// scene, or the unbound work it was made for), so any session can load it at once. Unsaved,
|
|
70
|
+
// another session's load_scene answered scene_not_found until a first save.
|
|
71
|
+
operations.setActiveScene(await operations.saveScene({
|
|
72
|
+
id: status.id,
|
|
73
|
+
name: status.name,
|
|
74
|
+
projectId: status.projectId,
|
|
75
|
+
ownerId: status.ownerId,
|
|
76
|
+
thumbnailUrl: status.thumbnailUrl,
|
|
77
|
+
graph: operations.exportSceneGraph(),
|
|
78
|
+
saveMode: 'draft',
|
|
79
|
+
publish: false,
|
|
80
|
+
operation: 'create_project',
|
|
81
|
+
}));
|
|
82
|
+
const saved = (await operations.getProjectStatus(status.id)) ?? status;
|
|
58
83
|
const payload = {
|
|
59
|
-
...projectStatusPayload(
|
|
84
|
+
...projectStatusPayload(saved, 'The project is now bound to this MCP session. Open editorUrl now; semantic tools will update the browser-visible draft. Call save_scene with saveMode: "checkpoint" only when you want a meaningful version.'),
|
|
60
85
|
...currentLevelContext(operations),
|
|
61
86
|
};
|
|
62
87
|
return {
|
|
@@ -7,6 +7,8 @@ export declare const deleteSceneInput: {
|
|
|
7
7
|
};
|
|
8
8
|
export declare const deleteSceneOutput: {
|
|
9
9
|
deleted: z.ZodBoolean;
|
|
10
|
+
hidden: z.ZodBoolean;
|
|
11
|
+
message: z.ZodOptional<z.ZodString>;
|
|
10
12
|
};
|
|
11
13
|
export declare function registerDeleteScene(server: McpServer, operations: SceneOperations): void;
|
|
12
14
|
//# sourceMappingURL=delete-scene.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delete-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/delete-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,kBAAkB,CAAA;AAKvD,eAAO,MAAM,gBAAgB;;;CAG5B,CAAA;AAED,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"delete-scene.d.ts","sourceRoot":"","sources":["../../../src/tools/scene-lifecycle/delete-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,kBAAkB,CAAA;AAKvD,eAAO,MAAM,gBAAgB;;;CAG5B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;CAI7B,CAAA;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAmCxF"}
|
|
@@ -8,20 +8,21 @@ export const deleteSceneInput = {
|
|
|
8
8
|
};
|
|
9
9
|
export const deleteSceneOutput = {
|
|
10
10
|
deleted: z.boolean(),
|
|
11
|
+
hidden: z.boolean(),
|
|
12
|
+
message: z.string().optional(),
|
|
11
13
|
};
|
|
12
14
|
export function registerDeleteScene(server, operations) {
|
|
13
15
|
server.registerTool('delete_scene', {
|
|
14
16
|
title: 'Delete scene',
|
|
15
|
-
description:
|
|
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.",
|
|
16
18
|
inputSchema: deleteSceneInput,
|
|
17
19
|
outputSchema: deleteSceneOutput,
|
|
18
20
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
19
21
|
}, async ({ id, expectedVersion }) => {
|
|
20
22
|
try {
|
|
21
|
-
const
|
|
23
|
+
const payload = await operations.deleteStoredScene(id, {
|
|
22
24
|
...(expectedVersion !== undefined ? { expectedVersion } : {}),
|
|
23
25
|
});
|
|
24
|
-
const payload = { deleted };
|
|
25
26
|
return {
|
|
26
27
|
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
27
28
|
structuredContent: payload,
|
|
@@ -6,6 +6,7 @@ export declare const saveSceneInput: {
|
|
|
6
6
|
name: z.ZodString;
|
|
7
7
|
projectId: z.ZodOptional<z.ZodString>;
|
|
8
8
|
expectedVersion: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
replace: z.ZodOptional<z.ZodBoolean>;
|
|
9
10
|
saveMode: z.ZodDefault<z.ZodEnum<{
|
|
10
11
|
draft: "draft";
|
|
11
12
|
checkpoint: "checkpoint";
|
|
@@ -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,yCAAyC,CAAA;
|
|
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,yCAAyC,CAAA;AAIxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAOvD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;CAkC1B,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;CAmB3B,CAAA;AAgCD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAgHlF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { migrateLegacyWallAssemblies } from '@pascal-app/core/scene-migrations';
|
|
1
2
|
import { AnyNode } from '@pascal-app/core/schema';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { SceneVersionConflictError } from '../../storage/types.js';
|
|
@@ -10,14 +11,18 @@ export const saveSceneInput = {
|
|
|
10
11
|
name: z.string().min(1).max(200),
|
|
11
12
|
projectId: z.string().optional(),
|
|
12
13
|
expectedVersion: z.number().int().positive().optional(),
|
|
14
|
+
replace: z
|
|
15
|
+
.boolean()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Write this session's scene over a project or scene it was not loaded from, replacing what that one holds."),
|
|
13
18
|
saveMode: z
|
|
14
19
|
.enum(['draft', 'checkpoint'])
|
|
15
20
|
.default('draft')
|
|
16
|
-
.describe('`draft` updates the browser-visible working model without polluting version history. `checkpoint` creates a meaningful saved version.'),
|
|
21
|
+
.describe('`draft` updates the browser-visible working model without polluting version history. `checkpoint` creates a meaningful saved version; it does not publish.'),
|
|
17
22
|
publish: z
|
|
18
23
|
.boolean()
|
|
19
24
|
.optional()
|
|
20
|
-
.describe(
|
|
25
|
+
.describe("Hosted Pascal: also publish this checkpoint, making it the version the project's viewers see. Only when the user asks to publish."),
|
|
21
26
|
thumbnail: z.string().url().optional(),
|
|
22
27
|
includeCurrentScene: z
|
|
23
28
|
.boolean()
|
|
@@ -48,15 +53,49 @@ export const saveSceneOutput = {
|
|
|
48
53
|
levelIds: z.array(z.string()),
|
|
49
54
|
defaultLevelId: z.string().nullable(),
|
|
50
55
|
};
|
|
56
|
+
/** A saved scene that is more than the default site, building and level. */
|
|
57
|
+
const HOLDS_CONTENT = 3;
|
|
58
|
+
/**
|
|
59
|
+
* The session's scene goes over a project or scene only when it was loaded from it (or created
|
|
60
|
+
* for it). After a server reload a session starts over on a blank scene, and saving it by id wrote
|
|
61
|
+
* it over the project's draft (2026-10-03: 8 levels and 10 imported plans lost).
|
|
62
|
+
*/
|
|
63
|
+
async function requireSceneLoadedFrom(bridge, target) {
|
|
64
|
+
if (target.id === undefined && target.projectId === undefined)
|
|
65
|
+
return;
|
|
66
|
+
const active = bridge.getActiveScene();
|
|
67
|
+
if (target.id !== undefined ? active?.id === target.id : active?.projectId === target.projectId)
|
|
68
|
+
return;
|
|
69
|
+
const nodeCount = target.projectId !== undefined && bridge.canGetProjectStatus
|
|
70
|
+
? ((await bridge.getProjectStatus(target.projectId))?.nodeCount ?? 0)
|
|
71
|
+
: target.id !== undefined
|
|
72
|
+
? Object.keys((await bridge.loadStoredScene(target.id))?.graph.nodes ?? {}).length
|
|
73
|
+
: 0;
|
|
74
|
+
if (nodeCount <= HOLDS_CONTENT)
|
|
75
|
+
return;
|
|
76
|
+
throwMcpError(ErrorCode.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
|
+
}
|
|
51
78
|
export function registerSaveScene(server, bridge) {
|
|
52
79
|
server.registerTool('save_scene', {
|
|
53
80
|
title: 'Save scene',
|
|
54
|
-
description: 'Save the current scene (or a provided graph) to the SceneStore. Defaults to a browser-visible draft save so agents can iterate without creating many project versions. Use saveMode: "checkpoint" for meaningful version history.',
|
|
81
|
+
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.',
|
|
55
82
|
inputSchema: saveSceneInput,
|
|
56
83
|
outputSchema: saveSceneOutput,
|
|
57
84
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
58
|
-
}, async ({ id, name, projectId, expectedVersion, saveMode, publish, thumbnail, includeCurrentScene, graph, }) => {
|
|
85
|
+
}, async ({ id, name, projectId, expectedVersion, saveMode, publish, thumbnail, includeCurrentScene, graph, replace, }) => {
|
|
86
|
+
// Without a target, the session's scene goes where it came from (create_project, load_scene,
|
|
87
|
+
// an earlier save). An agent was refused "Call create_project first" on its first save, right
|
|
88
|
+
// after create_project bound the session to its project.
|
|
89
|
+
const bound = includeCurrentScene && id === undefined && projectId === undefined
|
|
90
|
+
? bridge.getActiveScene()
|
|
91
|
+
: null;
|
|
92
|
+
if (bound) {
|
|
93
|
+
id = bound.id;
|
|
94
|
+
projectId = bound.projectId ?? undefined;
|
|
95
|
+
}
|
|
59
96
|
let sceneGraph;
|
|
97
|
+
if (includeCurrentScene && !replace)
|
|
98
|
+
await requireSceneLoadedFrom(bridge, { id, projectId });
|
|
60
99
|
if (includeCurrentScene) {
|
|
61
100
|
const validation = bridge.validateScene();
|
|
62
101
|
if (!validation.valid) {
|
|
@@ -75,8 +114,9 @@ export function registerSaveScene(server, bridge) {
|
|
|
75
114
|
if (!rawNodes || typeof rawNodes !== 'object') {
|
|
76
115
|
throwMcpError(ErrorCode.InvalidParams, 'graph.nodes must be an object');
|
|
77
116
|
}
|
|
117
|
+
const migration = migrateLegacyWallAssemblies(rawNodes);
|
|
78
118
|
const errors = [];
|
|
79
|
-
for (const [nodeId, node] of Object.entries(
|
|
119
|
+
for (const [nodeId, node] of Object.entries(migration.nodes)) {
|
|
80
120
|
const res = AnyNode.safeParse(node);
|
|
81
121
|
if (!res.success) {
|
|
82
122
|
for (const issue of res.error.issues) {
|
|
@@ -91,7 +131,7 @@ export function registerSaveScene(server, bridge) {
|
|
|
91
131
|
if (errors.length > 0) {
|
|
92
132
|
throwMcpError(ErrorCode.InvalidParams, 'graph_invalid', { errors });
|
|
93
133
|
}
|
|
94
|
-
sceneGraph = graph;
|
|
134
|
+
sceneGraph = { ...graph, nodes: migration.nodes };
|
|
95
135
|
}
|
|
96
136
|
try {
|
|
97
137
|
const meta = await bridge.saveScene({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SceneBridge } from '../../bridge/scene-bridge.js';
|
|
2
2
|
import { type SceneOperations } from '../../operations/index.js';
|
|
3
|
-
import { type ProjectCreateOptions, type ProjectStatus, type SceneEvent, type SceneEventAppendOptions, type SceneEventListOptions, type SceneListOptions, type SceneMeta, type SceneMutateOptions, type SceneSaveOptions, type SceneStore, type SceneWithGraph } from '../../storage/types.js';
|
|
3
|
+
import { type ProjectCreateOptions, type ProjectStatus, type SceneDeleteResult, type SceneEvent, type SceneEventAppendOptions, type SceneEventListOptions, type SceneListOptions, type SceneMeta, type SceneMutateOptions, type SceneSaveOptions, type SceneStore, type SceneWithGraph } from '../../storage/types.js';
|
|
4
4
|
export type StoredTextContent = {
|
|
5
5
|
type: string;
|
|
6
6
|
text: string;
|
|
@@ -32,7 +32,7 @@ export declare class InMemorySceneStore implements SceneStore {
|
|
|
32
32
|
save(opts: SceneSaveOptions): Promise<SceneMeta>;
|
|
33
33
|
load(id: string): Promise<SceneWithGraph | null>;
|
|
34
34
|
list(opts?: SceneListOptions): Promise<SceneMeta[]>;
|
|
35
|
-
delete(id: string, opts?: SceneMutateOptions): Promise<
|
|
35
|
+
delete(id: string, opts?: SceneMutateOptions): Promise<SceneDeleteResult>;
|
|
36
36
|
rename(id: string, newName: string, opts?: SceneMutateOptions): Promise<SceneMeta>;
|
|
37
37
|
appendSceneEvent(opts: SceneEventAppendOptions): Promise<SceneEvent>;
|
|
38
38
|
listSceneEvents(sceneId: string, opts?: SceneEventListOptions): Promise<SceneEvent[]>;
|
|
@@ -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,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;IAejE,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAK3D,IAAI,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC;IA+DhD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAShD,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAanD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,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;IAejE,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAK3D,IAAI,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC;IA+DhD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAShD,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAanD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAYzE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,SAAS,CAAC;IAmBlF,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,UAAU,CAAC;IAapE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAU3F,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,MAAM;IAoBd,OAAO,CAAC,eAAe;CA0BxB"}
|
|
@@ -130,7 +130,8 @@ export class InMemorySceneStore {
|
|
|
130
130
|
if (opts?.expectedVersion !== undefined && rec.version !== opts.expectedVersion) {
|
|
131
131
|
throw new SceneVersionConflictError(`Expected version ${opts.expectedVersion}, have ${rec.version}`);
|
|
132
132
|
}
|
|
133
|
-
|
|
133
|
+
this.data.delete(id);
|
|
134
|
+
return { deleted: true, hidden: false };
|
|
134
135
|
}
|
|
135
136
|
async rename(id, newName, opts) {
|
|
136
137
|
const rec = this.data.get(id);
|
|
@@ -6,6 +6,8 @@ export declare const setUnitMembersInput: {
|
|
|
6
6
|
memberZoneIds: z.ZodArray<z.ZodString>;
|
|
7
7
|
};
|
|
8
8
|
export declare const setUnitMembersOutput: {
|
|
9
|
+
project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
10
|
+
unsaved: z.ZodOptional<z.ZodString>;
|
|
9
11
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
10
12
|
status: z.ZodEnum<{
|
|
11
13
|
unbound: "unbound";
|
|
@@ -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,yCAAyC,CAAA;AAExE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,mBAAmB;;;CAG/B,CAAA;AAED,eAAO,MAAM,oBAAoB
|
|
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,yCAAyC,CAAA;AAExE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,mBAAmB;;;CAG/B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;CAIhC,CAAA;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAgCvF"}
|
package/dist/tools/set-zone.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export declare const setZoneInput: {
|
|
|
8
8
|
properties: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
9
9
|
};
|
|
10
10
|
export declare const setZoneOutput: {
|
|
11
|
+
project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
12
|
+
unsaved: z.ZodOptional<z.ZodString>;
|
|
11
13
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
12
14
|
status: z.ZodEnum<{
|
|
13
15
|
unbound: "unbound";
|
|
@@ -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,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,eAAO,MAAM,YAAY;;;;;CAKxB,CAAA;AAED,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"set-zone.d.ts","sourceRoot":"","sources":["../../src/tools/set-zone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,eAAO,MAAM,YAAY;;;;;CAKxB,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;CAGzB,CAAA;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAiDhF"}
|
package/dist/tools/set-zone.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { newZone } from '@pascal-app/core';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { ADDITIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
4
|
import { ErrorCode, throwMcpError } from './errors.js';
|
|
@@ -35,7 +35,7 @@ export function registerSetZone(server, bridge) {
|
|
|
35
35
|
parent.metadata.role === 'roof') {
|
|
36
36
|
throwMcpError(ErrorCode.InvalidParams, `Roof support level ${levelId} is not an occupied story; create zones on an occupied level instead`);
|
|
37
37
|
}
|
|
38
|
-
const zone =
|
|
38
|
+
const zone = newZone({
|
|
39
39
|
name: label,
|
|
40
40
|
polygon: polygon,
|
|
41
41
|
metadata: properties ?? {},
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type AgentOperation, type SceneChanges } from '@pascal-app/core/agent-operations';
|
|
3
|
+
import { type AgentToolAnnotations, type AgentToolContract } from '@pascal-app/core/agent-tools';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import type { Patch } from '../bridge/scene-bridge.js';
|
|
6
|
+
import type { SceneOperations } from '../operations/index.js';
|
|
7
|
+
import { type AssetCatalog } from './asset-catalog.js';
|
|
8
|
+
/**
|
|
9
|
+
* A tool the server runs as a core-style operation: parse with the contract, plan with the
|
|
10
|
+
* operation, apply its changes through the bridge in one history step, answer with what the scene
|
|
11
|
+
* then holds. `annotations` are the host's to choose from its own review of the operation; a
|
|
12
|
+
* plugin contract's `annotations` are only its hints.
|
|
13
|
+
*/
|
|
14
|
+
export type OperationTool = {
|
|
15
|
+
contract: AgentToolContract;
|
|
16
|
+
operation: AgentOperation;
|
|
17
|
+
annotations: AgentToolAnnotations;
|
|
18
|
+
outputSchema?: Record<string, z.ZodType>;
|
|
19
|
+
envelope?: (bridge: SceneOperations) => Record<string, unknown>;
|
|
20
|
+
/** Reads the host's item library: only these calls wait for it (the hosted one is a query). */
|
|
21
|
+
catalog?: true;
|
|
22
|
+
};
|
|
23
|
+
export declare function toPatches(changes: SceneChanges): Patch[];
|
|
24
|
+
export declare function registerSharedTools(server: McpServer, bridge: SceneOperations, catalog?: AssetCatalog): void;
|
|
25
|
+
/**
|
|
26
|
+
* Registers one operation tool, as the shared tools are: a host adds a plugin's `'operation'`
|
|
27
|
+
* tools with it, from the plugin's `./agent-tools` contract and `./agent-operations` operation.
|
|
28
|
+
*/
|
|
29
|
+
export declare function registerOperationTool(server: McpServer, bridge: SceneOperations, tool: OperationTool, catalog?: AssetCatalog): void;
|
|
30
|
+
//# sourceMappingURL=shared-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-tools.d.ts","sourceRoot":"","sources":["../../src/tools/shared-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,EAGL,KAAK,cAAc,EAGnB,KAAK,YAAY,EAElB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EAsBvB,MAAM,8BAA8B,CAAA;AAOrC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,iBAAiB,CAAA;AASnE;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,SAAS,EAAE,cAAc,CAAA;IACzB,WAAW,EAAE,oBAAoB,CAAA;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;IACxC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/D,+FAA+F;IAC/F,OAAO,CAAC,EAAE,IAAI,CAAA;CACf,CAAA;AAmRD,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,KAAK,EAAE,CAmBxD;AAUD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,YAA6B,GACrC,IAAI,CAGN;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,YAA6B,GACrC,IAAI,CAkEN"}
|