@pascal-app/mcp 1.0.3 → 1.0.5
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 +181 -56
- package/dist/bin/pascal-mcp.js +9 -3
- 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 +42 -6
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +232 -45
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -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 +41 -3
- package/dist/operations/scene-operations.d.ts.map +1 -1
- package/dist/operations/scene-operations.js +42 -1
- 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 +3 -3
- 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 +13 -6
- 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 +62 -33
- package/dist/resources/catalog-items.d.ts +5 -6
- package/dist/resources/catalog-items.d.ts.map +1 -1
- package/dist/resources/catalog-items.js +7 -9
- 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 +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 +4 -2
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +5 -2
- 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 +25 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +71 -25
- 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 +3 -3
- 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 +36 -7
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +12 -0
- 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 +5 -0
- package/dist/tools/add-column.d.ts.map +1 -0
- package/dist/tools/add-column.js +59 -0
- package/dist/tools/add-object.d.ts +76 -0
- package/dist/tools/add-object.d.ts.map +1 -0
- package/dist/tools/add-object.js +187 -0
- package/dist/tools/annotations.d.ts.map +1 -1
- package/dist/tools/apply-patch.d.ts +9 -2
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +36 -5
- 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 +33 -12
- 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 +7 -7
- package/dist/tools/check-collisions.d.ts.map +1 -1
- package/dist/tools/check-collisions.js +7 -8
- 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 +53 -0
- package/dist/tools/construction-tools.d.ts +12 -88
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +122 -381
- package/dist/tools/create-unit.d.ts +5 -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 +15 -4
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +14 -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/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 +2 -1
- package/dist/tools/get-scene.d.ts.map +1 -1
- package/dist/tools/get-scene.js +5 -3
- 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 +40 -0
- package/dist/tools/index.d.ts +12 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +18 -32
- 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 +25 -6
- package/dist/tools/live-sync.d.ts.map +1 -1
- package/dist/tools/live-sync.js +48 -27
- 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 +7 -1
- package/dist/tools/measure.d.ts.map +1 -1
- package/dist/tools/measure.js +38 -70
- 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 +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.js +22 -3
- package/dist/tools/patch-guards.d.ts +60 -0
- package/dist/tools/patch-guards.d.ts.map +1 -0
- package/dist/tools/patch-guards.js +256 -0
- 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 +10 -9
- 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 +4 -2
- package/dist/tools/redo.d.ts.map +1 -1
- package/dist/tools/redo.js +4 -4
- 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 +36 -98
- package/dist/tools/room-tools.d.ts.map +1 -1
- package/dist/tools/room-tools.js +130 -565
- 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 +31 -6
- package/dist/tools/scene-lifecycle/delete-scene.d.ts +3 -1
- package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.js +10 -9
- 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 +6 -3
- package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/save-scene.js +124 -16
- package/dist/tools/scene-lifecycle/test-utils.d.ts +3 -3
- 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 +4 -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 +4 -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 +40 -0
- package/dist/tools/shared-tools.d.ts.map +1 -0
- package/dist/tools/shared-tools.js +574 -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/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 +4 -2
- package/dist/tools/undo.d.ts.map +1 -1
- package/dist/tools/undo.js +4 -4
- 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/variants/mutations.js +1 -1
- package/dist/tools/view-scene.d.ts +44 -0
- package/dist/tools/view-scene.d.ts.map +1 -0
- package/dist/tools/view-scene.js +75 -0
- 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/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +17 -3
- package/examples/coordinate-conventions-demo.md +12 -13
- package/examples/embed-in-agent.ts +6 -7
- package/examples/generate-apartment.md +13 -15
- package/examples/photo-to-scene.md +3 -4
- package/examples/renovate-from-photos.md +6 -9
- package/package.json +19 -9
- 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/describe-node.d.ts +0 -17
- package/dist/tools/describe-node.d.ts.map +0 -1
- package/dist/tools/describe-node.js +0 -97
- 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/find-nodes.d.ts +0 -32
- package/dist/tools/find-nodes.d.ts.map +0 -1
- package/dist/tools/find-nodes.js +0 -107
- 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
- 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
package/dist/tools/errors.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server';
|
|
2
|
+
import { isAgentRefusal } from '@pascal-app/core/agent-tools';
|
|
2
3
|
/**
|
|
3
|
-
* Throw a structured MCP error. The SDK translates `
|
|
4
|
+
* Throw a structured MCP error. The SDK translates `ProtocolError` into a
|
|
4
5
|
* JSON-RPC error response automatically.
|
|
5
6
|
*/
|
|
6
7
|
export function throwMcpError(code, message, data) {
|
|
7
|
-
throw new
|
|
8
|
+
throw new ProtocolError(code, message, data);
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* Return a non-throwing tool error payload — used for structured failures that
|
|
@@ -22,4 +23,13 @@ export function toolError(message, data) {
|
|
|
22
23
|
isError: true,
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
+
/**
|
|
27
|
+
* A core operation's refusal (`AgentRefusal`) as the same `{ error, code, ...details }` answer the
|
|
28
|
+
* hosted chat returns; anything else is a real failure and is rethrown.
|
|
29
|
+
*/
|
|
30
|
+
export function refusalResult(error) {
|
|
31
|
+
if (isAgentRefusal(error))
|
|
32
|
+
return toolError(error.message, { code: error.code, ...error.details });
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
export { ProtocolError, ProtocolErrorCode };
|
|
@@ -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 exportGlbInput: {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export-glb.d.ts","sourceRoot":"","sources":["../../src/tools/export-glb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"export-glb.d.ts","sourceRoot":"","sources":["../../src/tools/export-glb.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,eAAe,CAAA;AAGpD,eAAO,MAAM,cAAc,IAAK,CAAA;AAEhC,eAAO,MAAM,eAAe;IAC1B,MAAM;IACN,MAAM;CACP,CAAA;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAuBnF"}
|
package/dist/tools/export-glb.js
CHANGED
|
@@ -9,8 +9,8 @@ export function registerExportGlb(server, _bridge) {
|
|
|
9
9
|
server.registerTool('export_glb', {
|
|
10
10
|
title: 'Export GLB',
|
|
11
11
|
description: 'GLB export is not available in headless mode — it requires the Three.js renderer, which is browser-only. Returns a structured `not_implemented` tool error.',
|
|
12
|
-
inputSchema: exportGlbInput,
|
|
13
|
-
outputSchema: exportGlbOutput,
|
|
12
|
+
inputSchema: z.object(exportGlbInput),
|
|
13
|
+
outputSchema: z.object(exportGlbOutput),
|
|
14
14
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
15
15
|
}, async () => {
|
|
16
16
|
const payload = {
|
|
@@ -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 exportJsonInput: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export-json.d.ts","sourceRoot":"","sources":["../../src/tools/export-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"export-json.d.ts","sourceRoot":"","sources":["../../src/tools/export-json.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,eAAe,CAAA;AAGpD,eAAO,MAAM,eAAe;IAC1B,MAAM;CACP,CAAA;AAED,eAAO,MAAM,gBAAgB;IAC3B,IAAI;CACL,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqBnF"}
|
|
@@ -10,8 +10,8 @@ export function registerExportJson(server, bridge) {
|
|
|
10
10
|
server.registerTool('export_json', {
|
|
11
11
|
title: 'Export JSON',
|
|
12
12
|
description: 'Return the scene as a serialized JSON string. Pass `pretty: true` to indent with 2 spaces.',
|
|
13
|
-
inputSchema: exportJsonInput,
|
|
14
|
-
outputSchema: exportJsonOutput,
|
|
13
|
+
inputSchema: z.object(exportJsonInput),
|
|
14
|
+
outputSchema: z.object(exportJsonOutput),
|
|
15
15
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
16
16
|
}, async ({ pretty }) => {
|
|
17
17
|
const scene = bridge.exportJSON();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry-script-worker.d.ts","sourceRoot":"","sources":["../../src/tools/geometry-script-worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Console } from 'node:console';
|
|
2
|
+
import { compileGeometryScript } from '@pascal-app/geometry-script/compile';
|
|
3
|
+
const stdout = process.stdout;
|
|
4
|
+
// stdout carries only the result; a script's own logging goes to stderr.
|
|
5
|
+
globalThis.console = new Console({ stdout: process.stderr, stderr: process.stderr });
|
|
6
|
+
const chunks = [];
|
|
7
|
+
for await (const chunk of process.stdin)
|
|
8
|
+
chunks.push(chunk);
|
|
9
|
+
const input = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
10
|
+
for (const name of ['fetch', 'WebSocket', 'EventSource', 'XMLHttpRequest', 'Request', 'Response']) {
|
|
11
|
+
Reflect.deleteProperty(globalThis, name);
|
|
12
|
+
}
|
|
13
|
+
for (const name of ['getBuiltinModule', 'binding', 'dlopen'])
|
|
14
|
+
Reflect.deleteProperty(process, name);
|
|
15
|
+
try {
|
|
16
|
+
const { glb, ...compiled } = await compileGeometryScript(input);
|
|
17
|
+
stdout.write(JSON.stringify({ ok: true, compiled, glb: Buffer.from(glb).toString('base64') }));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
stdout.write(JSON.stringify({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
21
|
+
}
|
|
@@ -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 getSceneInput: {};
|
|
@@ -6,6 +6,7 @@ export declare const getSceneOutput: {
|
|
|
6
6
|
nodes: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
7
7
|
rootNodeIds: z.ZodArray<z.ZodString>;
|
|
8
8
|
collections: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
9
|
+
installedPlugins: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
9
10
|
};
|
|
10
11
|
export declare function registerGetScene(server: McpServer, bridge: SceneOperations): void;
|
|
11
12
|
//# sourceMappingURL=get-scene.d.ts.map
|
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"get-scene.d.ts","sourceRoot":"","sources":["../../src/tools/get-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,eAAe,CAAA;AAGpD,eAAO,MAAM,aAAa,IAAK,CAAA;AAE/B,eAAO,MAAM,cAAc;IACzB,KAAK;IACL,WAAW;IACX,WAAW;IACX,gBAAgB;CACjB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAyBjF"}
|
package/dist/tools/get-scene.js
CHANGED
|
@@ -5,13 +5,14 @@ export const getSceneOutput = {
|
|
|
5
5
|
nodes: z.record(z.string(), z.unknown()),
|
|
6
6
|
rootNodeIds: z.array(z.string()),
|
|
7
7
|
collections: z.record(z.string(), z.unknown()).optional(),
|
|
8
|
+
installedPlugins: z.array(z.string()).optional(),
|
|
8
9
|
};
|
|
9
10
|
export function registerGetScene(server, bridge) {
|
|
10
11
|
server.registerTool('get_scene', {
|
|
11
12
|
title: 'Get scene',
|
|
12
|
-
description: 'Returns the full scene graph: flat node dictionary, root node IDs, and
|
|
13
|
-
inputSchema: getSceneInput,
|
|
14
|
-
outputSchema: getSceneOutput,
|
|
13
|
+
description: 'Returns the full scene graph: flat node dictionary, root node IDs, collections, and explicit installed plugin IDs when present.',
|
|
14
|
+
inputSchema: z.object(getSceneInput),
|
|
15
|
+
outputSchema: z.object(getSceneOutput),
|
|
15
16
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
16
17
|
}, async () => {
|
|
17
18
|
const scene = bridge.exportJSON();
|
|
@@ -19,6 +20,7 @@ export function registerGetScene(server, bridge) {
|
|
|
19
20
|
nodes: scene.nodes,
|
|
20
21
|
rootNodeIds: scene.rootNodeIds,
|
|
21
22
|
collections: (scene.collections ?? {}),
|
|
23
|
+
...(scene.installedPlugins ? { installedPlugins: scene.installedPlugins } : {}),
|
|
22
24
|
};
|
|
23
25
|
return {
|
|
24
26
|
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"honest-patch-guard.d.ts","sourceRoot":"","sources":["../../src/tools/honest-patch-guard.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { honestNodePatch } from '@pascal-app/core/agent-operations';
|
|
2
|
+
import { isAgentRefusal } from '@pascal-app/core/agent-tools';
|
|
3
|
+
import { PatchRefusedError, registerPatchGuard } from './patch-guards.js';
|
|
4
|
+
/**
|
|
5
|
+
* Each update checked to do what it says, in the batch's order (a node an earlier op created is
|
|
6
|
+
* the one updated): a field the node would drop, a material the library lacks or a field a set
|
|
7
|
+
* one hides is refused, naming it; `null` clears. The cleaned data is what is written.
|
|
8
|
+
*/
|
|
9
|
+
function honestUpdates(patches, scene) {
|
|
10
|
+
const nodes = { ...scene };
|
|
11
|
+
for (const [index, patch] of patches.entries()) {
|
|
12
|
+
if (patch.op === 'create')
|
|
13
|
+
nodes[patch.node.id] = patch.node;
|
|
14
|
+
else if (patch.op === 'delete')
|
|
15
|
+
delete nodes[patch.id];
|
|
16
|
+
else if (patch.op === 'update') {
|
|
17
|
+
const current = nodes[patch.id];
|
|
18
|
+
if (!current)
|
|
19
|
+
continue;
|
|
20
|
+
try {
|
|
21
|
+
patch.data = honestNodePatch(current, patch.data);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (!isAgentRefusal(error))
|
|
25
|
+
throw error;
|
|
26
|
+
throw new PatchRefusedError(error.code, index, patch.id, error.message);
|
|
27
|
+
}
|
|
28
|
+
nodes[patch.id] = { ...current, ...patch.data };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
registerPatchGuard({ name: 'honest-updates', order: 20, run: honestUpdates });
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
+
import { type HostedServiceExecutor } from '@pascal-app/core/agent-operations';
|
|
3
|
+
export declare function registerHostedServiceTools(server: McpServer, execute: HostedServiceExecutor): void;
|
|
4
|
+
//# sourceMappingURL=hosted-services.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted-services.d.ts","sourceRoot":"","sources":["../../src/tools/hosted-services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,mCAAmC,CAAA;AAQ1C,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CA8CN"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { executeHostedServiceTool, } from '@pascal-app/core/agent-operations';
|
|
2
|
+
import { HOSTED_SERVICE_TOOL_CONTRACTS, isAgentRefusal, refusalPayload, } from '@pascal-app/core/agent-tools';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export function registerHostedServiceTools(server, execute) {
|
|
5
|
+
for (const contract of HOSTED_SERVICE_TOOL_CONTRACTS) {
|
|
6
|
+
server.registerTool(contract.name, {
|
|
7
|
+
title: contract.title,
|
|
8
|
+
description: contract.description,
|
|
9
|
+
inputSchema: z.object(contract.input).strict(),
|
|
10
|
+
annotations: contract.annotations,
|
|
11
|
+
}, async (input, ctx) => {
|
|
12
|
+
try {
|
|
13
|
+
const result = await executeHostedServiceTool(contract.name, input, execute, ctx.mcpReq.signal);
|
|
14
|
+
// A render's preview, inline in the result, is the picture the client shows the model.
|
|
15
|
+
const { preview, ...rest } = (result ?? {});
|
|
16
|
+
const picture = typeof preview === 'string' ? /^data:(image\/[a-z]+);base64,(.+)$/.exec(preview) : null;
|
|
17
|
+
if (!picture)
|
|
18
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{ type: 'text', text: JSON.stringify(rest) },
|
|
22
|
+
{ type: 'image', data: picture[2], mimeType: picture[1] },
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
const result = isAgentRefusal(error)
|
|
28
|
+
? refusalPayload(error)
|
|
29
|
+
: {
|
|
30
|
+
error: 'Pascal could not complete this service request. Check its retained result before repeating paid work.',
|
|
31
|
+
code: 'service_error',
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
isError: true,
|
|
35
|
+
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { SceneOperations } from '../operations/index.js';
|
|
3
|
+
import { type GeometryScriptHost } from './add-object.js';
|
|
4
|
+
import type { AssetCatalog } from './asset-catalog.js';
|
|
5
|
+
import { type PlanReadingHosts } from './shared-tools.js';
|
|
6
|
+
import { type SceneViewHost } from './view-scene.js';
|
|
3
7
|
/**
|
|
4
8
|
* Register every non-vision MCP tool against the given server.
|
|
5
9
|
* Vision tools (analyze_floorplan_image, analyze_room_photo) are registered
|
|
@@ -8,5 +12,11 @@ import type { SceneOperations } from '../operations/index.js';
|
|
|
8
12
|
* Scene-lifecycle tools (save/load/list/delete/rename scene) are registered
|
|
9
13
|
* when persistence operations are available.
|
|
10
14
|
*/
|
|
11
|
-
|
|
15
|
+
/** What the host lends the tools: its item library, script compiles, a view. */
|
|
16
|
+
export type ToolHosts = PlanReadingHosts & {
|
|
17
|
+
catalog?: AssetCatalog;
|
|
18
|
+
geometryScripts?: GeometryScriptHost;
|
|
19
|
+
sceneViews?: SceneViewHost;
|
|
20
|
+
};
|
|
21
|
+
export declare function registerTools(server: McpServer, operations: SceneOperations, { catalog, geometryScripts, sceneViews, assetViews }?: ToolHosts): void;
|
|
12
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAEpD,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAiBnD,OAAO,EAAE,KAAK,gBAAgB,EAAuB,MAAM,gBAAgB,CAAA;AAI3E,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAEpE;;;;;;;GAOG;AACH,gFAAgF;AAChF,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG;IACzC,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,eAAe,CAAC,EAAE,kBAAkB,CAAA;IACpC,UAAU,CAAC,EAAE,aAAa,CAAA;CAC3B,CAAA;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,eAAe,EAC3B,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,GAAE,SAAc,GACnE,IAAI,CA+BN"}
|
package/dist/tools/index.js
CHANGED
|
@@ -1,65 +1,51 @@
|
|
|
1
|
+
import { registerAddColumn } from './add-column.js';
|
|
2
|
+
import { compileObjectOnHost, registerAddObject, registerGetSource, } from './add-object.js';
|
|
1
3
|
import { registerApplyPatch } from './apply-patch.js';
|
|
4
|
+
import { registerAuthorScene } from './author-scene.js';
|
|
2
5
|
import { registerCheckCollisions } from './check-collisions.js';
|
|
6
|
+
import { registerClearScene } from './clear-scene.js';
|
|
3
7
|
import { registerConstructionTools } from './construction-tools.js';
|
|
4
|
-
import { registerCreateLevel } from './create-level.js';
|
|
5
8
|
import { registerCreateUnit } from './create-unit.js';
|
|
6
|
-
import { registerCreateWall } from './create-wall.js';
|
|
7
|
-
import { registerCutOpening } from './cut-opening.js';
|
|
8
|
-
import { registerDeleteNode } from './delete-node.js';
|
|
9
|
-
import { registerDescribeNode } from './describe-node.js';
|
|
10
|
-
import { registerDuplicateLevel } from './duplicate-level.js';
|
|
11
9
|
import { registerExportGlb } from './export-glb.js';
|
|
12
10
|
import { registerExportJson } from './export-json.js';
|
|
13
|
-
import { registerFindNodes } from './find-nodes.js';
|
|
14
|
-
import { registerGetNode } from './get-node.js';
|
|
15
11
|
import { registerGetScene } from './get-scene.js';
|
|
16
12
|
import { registerListUnits } from './list-units.js';
|
|
17
13
|
import { registerMeasure } from './measure.js';
|
|
18
14
|
import { registerPhotoToSceneTool } from './photo-to-scene/index.js';
|
|
19
|
-
import { registerPlaceItem } from './place-item.js';
|
|
20
15
|
import { registerRedo } from './redo.js';
|
|
21
16
|
import { registerRoomTools } from './room-tools.js';
|
|
22
17
|
import { registerSceneLifecycleTools } from './scene-lifecycle/index.js';
|
|
23
|
-
import { registerSceneQueryTools } from './scene-query.js';
|
|
24
18
|
import { registerSetUnitMembers } from './set-unit-members.js';
|
|
25
19
|
import { registerSetZone } from './set-zone.js';
|
|
20
|
+
import { registerSharedTools } from './shared-tools.js';
|
|
26
21
|
import { registerTemplateTools } from './templates/index.js';
|
|
27
22
|
import { registerUndo } from './undo.js';
|
|
28
|
-
import { registerValidateScene } from './validate-scene.js';
|
|
29
23
|
import { registerVariantTools } from './variants/index.js';
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* Vision tools (analyze_floorplan_image, analyze_room_photo) are registered
|
|
33
|
-
* separately via `registerVisionTools` (Agent E).
|
|
34
|
-
*
|
|
35
|
-
* Scene-lifecycle tools (save/load/list/delete/rename scene) are registered
|
|
36
|
-
* when persistence operations are available.
|
|
37
|
-
*/
|
|
38
|
-
export function registerTools(server, operations) {
|
|
24
|
+
import { registerViewScene } from './view-scene.js';
|
|
25
|
+
export function registerTools(server, operations, { catalog, geometryScripts, sceneViews, assetViews } = {}) {
|
|
39
26
|
registerGetScene(server, operations);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
registerSharedTools(server, operations, catalog, {
|
|
28
|
+
assetViews,
|
|
29
|
+
buildObject: (input) => compileObjectOnHost(geometryScripts, operations, input),
|
|
30
|
+
});
|
|
31
|
+
registerAddColumn(server, operations, geometryScripts);
|
|
32
|
+
registerAddObject(server, operations, geometryScripts);
|
|
33
|
+
registerAuthorScene(server, operations, geometryScripts);
|
|
34
|
+
registerGetSource(server, operations, geometryScripts);
|
|
44
35
|
registerMeasure(server, operations);
|
|
36
|
+
registerViewScene(server, operations, sceneViews);
|
|
45
37
|
registerConstructionTools(server, operations);
|
|
46
|
-
registerRoomTools(server, operations);
|
|
38
|
+
registerRoomTools(server, operations, geometryScripts);
|
|
47
39
|
registerApplyPatch(server, operations);
|
|
48
|
-
|
|
40
|
+
registerClearScene(server, operations);
|
|
49
41
|
registerCreateUnit(server, operations);
|
|
50
42
|
registerSetUnitMembers(server, operations);
|
|
51
43
|
registerListUnits(server, operations);
|
|
52
|
-
registerCreateWall(server, operations);
|
|
53
|
-
registerPlaceItem(server, operations);
|
|
54
|
-
registerCutOpening(server, operations);
|
|
55
44
|
registerSetZone(server, operations);
|
|
56
|
-
registerDuplicateLevel(server, operations);
|
|
57
|
-
registerDeleteNode(server, operations);
|
|
58
45
|
registerUndo(server, operations);
|
|
59
46
|
registerRedo(server, operations);
|
|
60
47
|
registerExportJson(server, operations);
|
|
61
48
|
registerExportGlb(server, operations);
|
|
62
|
-
registerValidateScene(server, operations);
|
|
63
49
|
registerCheckCollisions(server, operations);
|
|
64
50
|
registerTemplateTools(server, operations);
|
|
65
51
|
if (operations.hasStore) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"level-height-guard.d.ts","sourceRoot":"","sources":["../../src/tools/level-height-guard.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { fillLevelHeights } from '@pascal-app/core/agent-operations';
|
|
2
|
+
import { registerPatchGuard } from './patch-guards.js';
|
|
3
|
+
/**
|
|
4
|
+
* A level is written with a height: a create without one, or an update clearing it, gets the height
|
|
5
|
+
* the editor's load would derive, said in the answer's notes. After the honest-update check, which
|
|
6
|
+
* turns a `null` into a cleared field.
|
|
7
|
+
*/
|
|
8
|
+
function levelHeights(patches, scene) {
|
|
9
|
+
return fillLevelHeights(patches, scene);
|
|
10
|
+
}
|
|
11
|
+
registerPatchGuard({ name: 'level-heights', order: 30, run: levelHeights });
|
|
@@ -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 listUnitsInput: {
|
|
@@ -10,9 +10,9 @@ export declare const listUnitsOutput: {
|
|
|
10
10
|
name: z.ZodString;
|
|
11
11
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
12
12
|
apartment: "apartment";
|
|
13
|
-
"hotel-room": "hotel-room";
|
|
14
13
|
commercial: "commercial";
|
|
15
14
|
common: "common";
|
|
15
|
+
"hotel-room": "hotel-room";
|
|
16
16
|
}>>;
|
|
17
17
|
color: z.ZodString;
|
|
18
18
|
members: z.ZodArray<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-units.d.ts","sourceRoot":"","sources":["../../src/tools/list-units.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"list-units.d.ts","sourceRoot":"","sources":["../../src/tools/list-units.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD,eAAO,MAAM,cAAc;IACzB,UAAU;CACX,CAAA;AAED,eAAO,MAAM,eAAe;IAC1B,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBN,CAAA;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAgClF"}
|
package/dist/tools/list-units.js
CHANGED
|
@@ -34,8 +34,8 @@ export function registerListUnits(server, bridge) {
|
|
|
34
34
|
server.registerTool('list_units', {
|
|
35
35
|
title: 'List units',
|
|
36
36
|
description: 'List units with their member zones and current area reports, optionally filtered by building.',
|
|
37
|
-
inputSchema: listUnitsInput,
|
|
38
|
-
outputSchema: listUnitsOutput,
|
|
37
|
+
inputSchema: z.object(listUnitsInput),
|
|
38
|
+
outputSchema: z.object(listUnitsOutput),
|
|
39
39
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
40
40
|
}, async ({ buildingId }) => {
|
|
41
41
|
if (buildingId !== undefined)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { SceneGraph } from '@pascal-app/core/clone-scene-graph';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
-
export declare function syncDerivedStairOpenings(operations: SceneOperations): number;
|
|
5
4
|
export type LiveSyncStatus = 'published' | 'unbound' | 'events_unsupported';
|
|
5
|
+
/** Where a write went: the project it reached, or none (a scratch scene). */
|
|
6
|
+
export type LiveSync = {
|
|
7
|
+
status: LiveSyncStatus;
|
|
8
|
+
project: string | null;
|
|
9
|
+
};
|
|
6
10
|
type LiveSyncSkip = Exclude<LiveSyncStatus, 'published'>;
|
|
7
11
|
/**
|
|
8
12
|
* Output-schema fragment for every tool that mutates the scene. Spread into
|
|
@@ -10,24 +14,35 @@ type LiveSyncSkip = Exclude<LiveSyncStatus, 'published'>;
|
|
|
10
14
|
* structured-content validation.
|
|
11
15
|
*/
|
|
12
16
|
export declare const liveSyncOutput: {
|
|
17
|
+
project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
18
|
+
unsaved: z.ZodOptional<z.ZodString>;
|
|
13
19
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
14
20
|
status: z.ZodEnum<{
|
|
15
|
-
unbound: "unbound";
|
|
16
21
|
events_unsupported: "events_unsupported";
|
|
22
|
+
unbound: "unbound";
|
|
17
23
|
}>;
|
|
18
24
|
warning: z.ZodString;
|
|
19
25
|
}, z.core.$strip>>;
|
|
20
26
|
};
|
|
21
27
|
/**
|
|
22
|
-
* Payload fragment matching `liveSyncOutput`:
|
|
23
|
-
*
|
|
28
|
+
* Payload fragment matching `liveSyncOutput`: the project the write reached, or `null` and a note
|
|
29
|
+
* when none is bound; a `persistence` warning when the mutation stayed in-memory.
|
|
24
30
|
*/
|
|
25
|
-
export declare function persistencePayload(status:
|
|
31
|
+
export declare function persistencePayload({ status, project }: LiveSync): {
|
|
32
|
+
project: string | null;
|
|
33
|
+
unsaved?: string;
|
|
26
34
|
persistence?: {
|
|
27
35
|
status: LiveSyncSkip;
|
|
28
36
|
warning: string;
|
|
29
37
|
};
|
|
30
38
|
};
|
|
39
|
+
/** Where the session's writes go, for a call that publishes nothing (an undo with nothing to undo). */
|
|
40
|
+
export declare function currentLiveSync(operations: SceneOperations): LiveSync;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a tool call failed because the stored scene changed after the session
|
|
43
|
+
* loaded it. The store refuses before writing, so nothing from the call persisted.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isLiveSyncVersionConflict(error: unknown): boolean;
|
|
31
46
|
/**
|
|
32
47
|
* Persist the bridge's current graph to the active scene and append a live
|
|
33
48
|
* event for browser subscribers. Skips persistence — reporting why — when the
|
|
@@ -35,7 +50,11 @@ export declare function persistencePayload(status: LiveSyncStatus): {
|
|
|
35
50
|
* append scene events; callers surface that through `persistencePayload` so
|
|
36
51
|
* the skip is never silent (#725).
|
|
37
52
|
*/
|
|
38
|
-
export declare function publishLiveSceneSnapshot(operations: SceneOperations, kind: string
|
|
53
|
+
export declare function publishLiveSceneSnapshot(operations: SceneOperations, kind: string,
|
|
54
|
+
/** `allowSceneWipe`: the write empties the project on purpose (clear_scene). */
|
|
55
|
+
options?: {
|
|
56
|
+
allowSceneWipe?: boolean;
|
|
57
|
+
}): Promise<LiveSync>;
|
|
39
58
|
export declare function appendLiveSceneEvent(operations: SceneOperations, sceneId: string, version: number, kind: string, graph: SceneGraph): Promise<void>;
|
|
40
59
|
export {};
|
|
41
60
|
//# sourceMappingURL=live-sync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-sync.d.ts","sourceRoot":"","sources":["../../src/tools/live-sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"live-sync.d.ts","sourceRoot":"","sources":["../../src/tools/live-sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAIpD,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,SAAS,GAAG,oBAAoB,CAAA;AAE3E,6EAA6E;AAC7E,MAAM,MAAM,QAAQ,GAAG;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAA;AAEzE,KAAK,YAAY,GAAG,OAAO,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;AAExD;;;;GAIG;AACH,eAAO,MAAM,cAAc;IACzB,OAAO;IACP,OAAO;IACP,WAAW;;;;;;;CAMZ,CAAA;AASD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,GAAG;IACjE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CACxD,CAOA;AAED,uGAAuG;AACvG,wBAAgB,eAAe,CAAC,UAAU,EAAE,eAAe,GAAG,QAAQ,CAGrE;AAID;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEjE;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,eAAe,EAC3B,IAAI,EAAE,MAAM;AACZ,gFAAgF;AAChF,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACzC,OAAO,CAAC,QAAQ,CAAC,CAsDnB;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"}
|
package/dist/tools/live-sync.js
CHANGED
|
@@ -1,24 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { refuse, writeTarget } from '@pascal-app/core/agent-tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { SceneVersionConflictError } from '../storage/types.js';
|
|
4
|
-
import {
|
|
5
|
-
export function syncDerivedStairOpenings(operations) {
|
|
6
|
-
const updates = syncAutoStairOpenings(operations.getNodes());
|
|
7
|
-
if (updates.length === 0)
|
|
8
|
-
return 0;
|
|
9
|
-
operations.applyPatch(updates.map((update) => ({
|
|
10
|
-
op: 'update',
|
|
11
|
-
id: update.id,
|
|
12
|
-
data: update.data,
|
|
13
|
-
})));
|
|
14
|
-
return updates.length;
|
|
15
|
-
}
|
|
3
|
+
import { SceneVersionConflictError, SceneWipeBlockedError } from '../storage/types.js';
|
|
4
|
+
import { ProtocolError, ProtocolErrorCode, throwMcpError } from './errors.js';
|
|
16
5
|
/**
|
|
17
6
|
* Output-schema fragment for every tool that mutates the scene. Spread into
|
|
18
7
|
* the tool's `outputSchema` so `persistencePayload` fields survive the SDK's
|
|
19
8
|
* structured-content validation.
|
|
20
9
|
*/
|
|
21
10
|
export const liveSyncOutput = {
|
|
11
|
+
project: z.string().nullable().optional(),
|
|
12
|
+
unsaved: z.string().optional(),
|
|
22
13
|
persistence: z
|
|
23
14
|
.object({
|
|
24
15
|
status: z.enum(['unbound', 'events_unsupported']),
|
|
@@ -31,13 +22,29 @@ const LIVE_SYNC_WARNINGS = {
|
|
|
31
22
|
events_unsupported: 'The change was applied to the in-memory session only: the attached scene store does not support live scene events, so nothing was persisted.',
|
|
32
23
|
};
|
|
33
24
|
/**
|
|
34
|
-
* Payload fragment matching `liveSyncOutput`:
|
|
35
|
-
*
|
|
25
|
+
* Payload fragment matching `liveSyncOutput`: the project the write reached, or `null` and a note
|
|
26
|
+
* when none is bound; a `persistence` warning when the mutation stayed in-memory.
|
|
27
|
+
*/
|
|
28
|
+
export function persistencePayload({ status, project }) {
|
|
29
|
+
return {
|
|
30
|
+
...writeTarget(project),
|
|
31
|
+
...(status === 'published'
|
|
32
|
+
? {}
|
|
33
|
+
: { persistence: { status, warning: LIVE_SYNC_WARNINGS[status] } }),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Where the session's writes go, for a call that publishes nothing (an undo with nothing to undo). */
|
|
37
|
+
export function currentLiveSync(operations) {
|
|
38
|
+
const project = operations.getActiveScene()?.projectId ?? null;
|
|
39
|
+
return { status: project ? 'published' : 'unbound', project };
|
|
40
|
+
}
|
|
41
|
+
const LIVE_SYNC_VERSION_CONFLICT = 'live_sync_version_conflict';
|
|
42
|
+
/**
|
|
43
|
+
* Whether a tool call failed because the stored scene changed after the session
|
|
44
|
+
* loaded it. The store refuses before writing, so nothing from the call persisted.
|
|
36
45
|
*/
|
|
37
|
-
export function
|
|
38
|
-
|
|
39
|
-
return {};
|
|
40
|
-
return { persistence: { status, warning: LIVE_SYNC_WARNINGS[status] } };
|
|
46
|
+
export function isLiveSyncVersionConflict(error) {
|
|
47
|
+
return error instanceof ProtocolError && error.message.endsWith(LIVE_SYNC_VERSION_CONFLICT);
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
43
50
|
* Persist the bridge's current graph to the active scene and append a live
|
|
@@ -46,13 +53,15 @@ export function persistencePayload(status) {
|
|
|
46
53
|
* append scene events; callers surface that through `persistencePayload` so
|
|
47
54
|
* the skip is never silent (#725).
|
|
48
55
|
*/
|
|
49
|
-
export async function publishLiveSceneSnapshot(operations, kind
|
|
50
|
-
|
|
56
|
+
export async function publishLiveSceneSnapshot(operations, kind,
|
|
57
|
+
/** `allowSceneWipe`: the write empties the project on purpose (clear_scene). */
|
|
58
|
+
options = {}) {
|
|
51
59
|
const active = operations.getActiveScene();
|
|
52
60
|
if (!active)
|
|
53
|
-
return 'unbound';
|
|
61
|
+
return { status: 'unbound', project: null };
|
|
62
|
+
const project = active.projectId ?? active.id;
|
|
54
63
|
if (!operations.canAppendSceneEvents)
|
|
55
|
-
return 'events_unsupported';
|
|
64
|
+
return { status: 'events_unsupported', project };
|
|
56
65
|
const graph = operations.exportSceneGraph();
|
|
57
66
|
try {
|
|
58
67
|
const meta = await operations.saveScene({
|
|
@@ -63,9 +72,11 @@ export async function publishLiveSceneSnapshot(operations, kind) {
|
|
|
63
72
|
thumbnailUrl: active.thumbnailUrl,
|
|
64
73
|
graph,
|
|
65
74
|
expectedVersion: active.version,
|
|
75
|
+
...(active.graphHash !== undefined ? { expectedGraphHash: active.graphHash } : {}),
|
|
66
76
|
saveMode: 'draft',
|
|
67
77
|
publish: false,
|
|
68
78
|
operation: kind,
|
|
79
|
+
...(options.allowSceneWipe ? { allowSceneWipe: true } : {}),
|
|
69
80
|
});
|
|
70
81
|
operations.setActiveScene(meta);
|
|
71
82
|
await operations.appendSceneEvent({
|
|
@@ -76,16 +87,26 @@ export async function publishLiveSceneSnapshot(operations, kind) {
|
|
|
76
87
|
});
|
|
77
88
|
}
|
|
78
89
|
catch (error) {
|
|
90
|
+
if (error instanceof SceneWipeBlockedError) {
|
|
91
|
+
// The store kept what it held; the session goes back to it, so the agent's next write builds
|
|
92
|
+
// on the project as stored rather than on the refused one (deleting the only room, say).
|
|
93
|
+
const stored = await operations.loadStoredScene(active.id).catch(() => null);
|
|
94
|
+
if (stored)
|
|
95
|
+
operations.loadJSON(stored.graph);
|
|
96
|
+
refuse('scene_wipe_blocked', stored
|
|
97
|
+
? 'This write would leave the project empty, so it was blocked and nothing changed. To empty the project on purpose, call clear_scene. To remove only part of it, such as its only room, build what replaces it first, then remove it.'
|
|
98
|
+
: 'This write would leave the project empty, so it was blocked and not saved. Call load_scene before writing again. To empty the project on purpose, call clear_scene.', { sceneId: active.id, mutationApplied: false, sessionRestored: !!stored });
|
|
99
|
+
}
|
|
79
100
|
if (error instanceof SceneVersionConflictError) {
|
|
80
|
-
throwMcpError(
|
|
101
|
+
throwMcpError(ProtocolErrorCode.InvalidRequest, LIVE_SYNC_VERSION_CONFLICT, {
|
|
81
102
|
sceneId: active.id,
|
|
82
103
|
expectedVersion: active.version,
|
|
83
104
|
});
|
|
84
105
|
}
|
|
85
106
|
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
-
throwMcpError(
|
|
107
|
+
throwMcpError(ProtocolErrorCode.InternalError, `live_sync_failed: ${message}`);
|
|
87
108
|
}
|
|
88
|
-
return 'published';
|
|
109
|
+
return { status: 'published', project };
|
|
89
110
|
}
|
|
90
111
|
export async function appendLiveSceneEvent(operations, sceneId, version, kind, graph) {
|
|
91
112
|
if (!operations.canAppendSceneEvents)
|