@pascal-app/mcp 1.0.3 → 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 +39 -6
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +225 -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/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 +10 -4
- 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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type CompiledGeometryScript, GeometryArtifactMetadata, type GeometryScriptLanguage, type GeometryScriptParamValue } from '@pascal-app/core/schema';
|
|
3
|
+
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* How a host runs `add_object`'s module and keeps the result. Running
|
|
6
|
+
* model-written code is the host's call: it decides the isolation, and where
|
|
7
|
+
* artifacts live for the active scene.
|
|
8
|
+
*/
|
|
9
|
+
export type GeometryScriptHost = {
|
|
10
|
+
compile(input: {
|
|
11
|
+
code: string;
|
|
12
|
+
language: GeometryScriptLanguage;
|
|
13
|
+
params?: Record<string, GeometryScriptParamValue>;
|
|
14
|
+
}): Promise<CompiledGeometryScript & {
|
|
15
|
+
glb: Uint8Array;
|
|
16
|
+
}>;
|
|
17
|
+
storeArtifact(input: {
|
|
18
|
+
sceneId: string;
|
|
19
|
+
sha256: string;
|
|
20
|
+
bytes: Uint8Array;
|
|
21
|
+
mimeType: string;
|
|
22
|
+
nodeId?: string;
|
|
23
|
+
metadata?: GeometryArtifactMetadata;
|
|
24
|
+
}): Promise<string>;
|
|
25
|
+
/** A stored artifact's bytes (an object's script), or null when missing; only for principals who may edit the scene. */
|
|
26
|
+
readArtifact(input: {
|
|
27
|
+
sceneId: string;
|
|
28
|
+
sha256: string;
|
|
29
|
+
}): Promise<Uint8Array | null>;
|
|
30
|
+
/**
|
|
31
|
+
* Compiles and stores in one step, for a host whose compiler keeps the artifacts itself (the
|
|
32
|
+
* hosted MCP's user editor tab); preferred over `compile` + `storeArtifact` when present.
|
|
33
|
+
*/
|
|
34
|
+
build?(input: {
|
|
35
|
+
sceneId: string;
|
|
36
|
+
code: string;
|
|
37
|
+
language: GeometryScriptLanguage;
|
|
38
|
+
params?: Record<string, GeometryScriptParamValue>;
|
|
39
|
+
/** What the script builds, for the host to name it to the user. */
|
|
40
|
+
kind: ScriptedKind;
|
|
41
|
+
nodeId: string;
|
|
42
|
+
metadata?: GeometryArtifactMetadata;
|
|
43
|
+
}): Promise<CompiledGeometryScript>;
|
|
44
|
+
};
|
|
45
|
+
export type ScriptedKind = 'object' | 'window' | 'door' | 'column';
|
|
46
|
+
/** Compiles a module on the host and stores its GLB and text for the scene: the step every scripted tool shares. */
|
|
47
|
+
export declare function compileAndStore(host: GeometryScriptHost, sceneId: string, { code, language, params, }: {
|
|
48
|
+
code: string;
|
|
49
|
+
language: GeometryScriptLanguage;
|
|
50
|
+
params: Record<string, GeometryScriptParamValue> | undefined;
|
|
51
|
+
}, kind: ScriptedKind, context?: {
|
|
52
|
+
nodeId?: string;
|
|
53
|
+
metadata?: GeometryArtifactMetadata;
|
|
54
|
+
}): Promise<CompiledGeometryScript>;
|
|
55
|
+
export declare function readScript(host: GeometryScriptHost, sceneId: string, bridge: SceneOperations, nodeId: string): Promise<string>;
|
|
56
|
+
/** `add_object` on the MCP: the shared contract and operation, with the host's compile in front. */
|
|
57
|
+
export declare function registerAddObject(server: McpServer, bridge: SceneOperations, host: GeometryScriptHost | undefined): void;
|
|
58
|
+
/** `get_source` on the MCP: the object's module text, read back through the host's store. */
|
|
59
|
+
export declare function registerGetSource(server: McpServer, bridge: SceneOperations, host: GeometryScriptHost | undefined): void;
|
|
60
|
+
//# sourceMappingURL=add-object.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-object.d.ts","sourceRoot":"","sources":["../../src/tools/add-object.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAcxE,OAAO,EAEL,KAAK,sBAAsB,EAE3B,wBAAwB,EAExB,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAE9B,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,KAAK,EAAE;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,sBAAsB,CAAA;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;KAClD,GAAG,OAAO,CAAC,sBAAsB,GAAG;QAAE,GAAG,EAAE,UAAU,CAAA;KAAE,CAAC,CAAA;IACzD,aAAa,CAAC,KAAK,EAAE;QACnB,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,UAAU,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,QAAQ,CAAC,EAAE,wBAAwB,CAAA;KACpC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACnB,wHAAwH;IACxH,YAAY,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;IACpF;;;OAGG;IACH,KAAK,CAAC,CAAC,KAAK,EAAE;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,sBAAsB,CAAA;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;QACjD,mEAAmE;QACnE,IAAI,EAAE,YAAY,CAAA;QAClB,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,wBAAwB,CAAA;KACpC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AAElE,oHAAoH;AACpH,wBAAsB,eAAe,CACnC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,MAAM,EACf,EACE,IAAI,EACJ,QAAQ,EACR,MAAM,GACP,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,sBAAsB,CAAA;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,GAAG,SAAS,CAAA;CAC7D,EACD,IAAI,EAAE,YAAY,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,wBAAwB,CAAA;CAAO,GACrE,OAAO,CAAC,sBAAsB,CAAC,CAgCjC;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC,IAAI,CAsEN;AASD,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC,IAAI,CAgCN"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { isScriptedNode, scriptedObjectMeta } from '@pascal-app/core';
|
|
2
|
+
import { achievedChanges, addObject, authoredObject, editedScriptLanguage, editedScriptParams, readSourceResult, requireAddObjectReason, } from '@pascal-app/core/agent-operations';
|
|
3
|
+
import { addObjectTool, getSourceTool, isAgentRefusal, refuse } from '@pascal-app/core/agent-tools';
|
|
4
|
+
import { GEOMETRY_SCRIPT_MIME_TYPES, GeometryArtifactMetadata, GeometryReuseFields, generateId, } from '@pascal-app/core/schema';
|
|
5
|
+
import { DESTRUCTIVE_TOOL_ANNOTATIONS, READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
|
|
6
|
+
import { refusalResult, toolError } from './errors.js';
|
|
7
|
+
import { persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
8
|
+
import { toPatches } from './shared-tools.js';
|
|
9
|
+
/** Compiles a module on the host and stores its GLB and text for the scene: the step every scripted tool shares. */
|
|
10
|
+
export async function compileAndStore(host, sceneId, { code, language, params, }, kind, context = {}) {
|
|
11
|
+
const nodeId = context.nodeId ?? generateId(kind === 'object' ? 'item' : kind);
|
|
12
|
+
const metadata = GeometryArtifactMetadata.parse({
|
|
13
|
+
...context.metadata,
|
|
14
|
+
kind: kind === 'object' ? 'item' : kind,
|
|
15
|
+
});
|
|
16
|
+
if (host.build)
|
|
17
|
+
return {
|
|
18
|
+
...(await host.build({ sceneId, code, language, params, kind, nodeId, metadata })),
|
|
19
|
+
nodeId,
|
|
20
|
+
};
|
|
21
|
+
const { glb, ...compiled } = await host.compile({ code, language, params });
|
|
22
|
+
metadata.mount = compiled.mount;
|
|
23
|
+
const [sha256] = await Promise.all([
|
|
24
|
+
host.storeArtifact({
|
|
25
|
+
sceneId,
|
|
26
|
+
nodeId,
|
|
27
|
+
metadata,
|
|
28
|
+
sha256: compiled.sha256,
|
|
29
|
+
bytes: glb,
|
|
30
|
+
mimeType: 'model/gltf-binary',
|
|
31
|
+
}),
|
|
32
|
+
host.storeArtifact({
|
|
33
|
+
sceneId,
|
|
34
|
+
nodeId,
|
|
35
|
+
metadata,
|
|
36
|
+
sha256: compiled.script,
|
|
37
|
+
bytes: new TextEncoder().encode(code),
|
|
38
|
+
mimeType: GEOMETRY_SCRIPT_MIME_TYPES[language],
|
|
39
|
+
}),
|
|
40
|
+
]);
|
|
41
|
+
return { ...compiled, sha256, nodeId };
|
|
42
|
+
}
|
|
43
|
+
export async function readScript(host, sceneId, bridge, nodeId) {
|
|
44
|
+
const node = authoredObject(bridge.getNodes(), nodeId);
|
|
45
|
+
const bytes = await host.readArtifact({ sceneId, sha256: node.source.script });
|
|
46
|
+
if (!bytes)
|
|
47
|
+
throw new Error(`The script of ${nodeId} could not be read`);
|
|
48
|
+
return new TextDecoder().decode(bytes);
|
|
49
|
+
}
|
|
50
|
+
/** `add_object` on the MCP: the shared contract and operation, with the host's compile in front. */
|
|
51
|
+
export function registerAddObject(server, bridge, host) {
|
|
52
|
+
server.registerTool(addObjectTool.name, {
|
|
53
|
+
title: addObjectTool.title,
|
|
54
|
+
description: addObjectTool.description,
|
|
55
|
+
inputSchema: addObjectTool.input,
|
|
56
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
57
|
+
}, async (input) => {
|
|
58
|
+
if (!host) {
|
|
59
|
+
return toolError('This Pascal server cannot run geometry scripts.', {
|
|
60
|
+
code: 'scripts_unavailable',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const scene = bridge.getActiveScene();
|
|
64
|
+
if (!scene) {
|
|
65
|
+
return toolError('Open or save a scene first: authored objects are stored with a scene.', {
|
|
66
|
+
code: 'no_active_scene',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const args = input;
|
|
70
|
+
let compiled;
|
|
71
|
+
try {
|
|
72
|
+
requireAddObjectReason(args);
|
|
73
|
+
const code = args.code ??
|
|
74
|
+
(args.nodeId
|
|
75
|
+
? await readScript(host, scene.id, bridge, args.nodeId)
|
|
76
|
+
: refuseMissingCode());
|
|
77
|
+
const nodes = bridge.getNodes();
|
|
78
|
+
const previous = args.nodeId ? nodes[args.nodeId] : undefined;
|
|
79
|
+
const language = editedScriptLanguage(previous, args);
|
|
80
|
+
const params = editedScriptParams(previous, args.params);
|
|
81
|
+
compiled = await compileAndStore(host, scene.id, { code, language, params }, 'object', {
|
|
82
|
+
nodeId: args.nodeId,
|
|
83
|
+
metadata: {
|
|
84
|
+
...(isScriptedNode(previous) ? scriptedObjectMeta(previous) : {}),
|
|
85
|
+
...GeometryReuseFields.parse(args),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (isAgentRefusal(error))
|
|
91
|
+
return refusalResult(error);
|
|
92
|
+
return toolError(error instanceof Error ? error.message : String(error), {
|
|
93
|
+
code: 'script_failed',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// A copy: the hosted bridge writes its map in place, and a "before" that grows with the call
|
|
97
|
+
// reads every creation as unchanged.
|
|
98
|
+
const before = { ...bridge.getNodes() };
|
|
99
|
+
let outcome;
|
|
100
|
+
try {
|
|
101
|
+
outcome = addObject(before, { ...args, compiled }, { activeLevelId: null });
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
return refusalResult(error);
|
|
105
|
+
}
|
|
106
|
+
const patches = outcome.changes ? toPatches(outcome.changes) : [];
|
|
107
|
+
if (patches.length)
|
|
108
|
+
bridge.applyPatch(patches);
|
|
109
|
+
const payload = {
|
|
110
|
+
...outcome.result,
|
|
111
|
+
// What the scene holds now, as every write answers.
|
|
112
|
+
achieved: achievedChanges(before, outcome.changes ?? {}),
|
|
113
|
+
...persistencePayload(await publishLiveSceneSnapshot(bridge, addObjectTool.name)),
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
117
|
+
structuredContent: payload,
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function refuseMissingCode() {
|
|
122
|
+
refuse('code_required', 'Pass code to build a new object; params alone rebuild an existing one (nodeId).');
|
|
123
|
+
}
|
|
124
|
+
/** `get_source` on the MCP: the object's module text, read back through the host's store. */
|
|
125
|
+
export function registerGetSource(server, bridge, host) {
|
|
126
|
+
server.registerTool(getSourceTool.name, {
|
|
127
|
+
title: getSourceTool.title,
|
|
128
|
+
description: getSourceTool.description,
|
|
129
|
+
inputSchema: getSourceTool.input,
|
|
130
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
131
|
+
}, async ({ nodeId }) => {
|
|
132
|
+
if (!host) {
|
|
133
|
+
return toolError('This Pascal server cannot read geometry scripts.', {
|
|
134
|
+
code: 'scripts_unavailable',
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const scene = bridge.getActiveScene();
|
|
138
|
+
if (!scene)
|
|
139
|
+
return toolError('Open a scene first.', { code: 'no_active_scene' });
|
|
140
|
+
try {
|
|
141
|
+
const node = authoredObject(bridge.getNodes(), nodeId);
|
|
142
|
+
const payload = readSourceResult(node, await readScript(host, scene.id, bridge, nodeId));
|
|
143
|
+
return {
|
|
144
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
145
|
+
structuredContent: payload,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (isAgentRefusal(error))
|
|
150
|
+
return refusalResult(error);
|
|
151
|
+
return toolError(error instanceof Error ? error.message : String(error), {
|
|
152
|
+
code: 'script_unreadable',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../operations/index.js';
|
|
4
|
+
import './honest-patch-guard.js';
|
|
4
5
|
export declare const applyPatchInput: {
|
|
5
6
|
patches: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
6
7
|
op: z.ZodLiteral<"create">;
|
|
@@ -17,6 +18,8 @@ export declare const applyPatchInput: {
|
|
|
17
18
|
}, z.core.$strip>], "op">>;
|
|
18
19
|
};
|
|
19
20
|
export declare const applyPatchOutput: {
|
|
21
|
+
project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
22
|
+
unsaved: z.ZodOptional<z.ZodString>;
|
|
20
23
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
21
24
|
status: z.ZodEnum<{
|
|
22
25
|
unbound: "unbound";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-patch.d.ts","sourceRoot":"","sources":["../../src/tools/apply-patch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;
|
|
1
|
+
{"version":3,"file":"apply-patch.d.ts","sourceRoot":"","sources":["../../src/tools/apply-patch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAGpD,OAAO,sBAAsB,CAAA;AAK7B,eAAO,MAAM,eAAe;;;;;;;;;;;;;;CAE3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAK5B,CAAA;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA+EnF"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { isAgentRefusal } from '@pascal-app/core/agent-tools';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
3
|
-
import { ErrorCode, throwMcpError } from './errors.js';
|
|
4
|
+
import { ErrorCode, McpError, refusalResult, throwMcpError } from './errors.js';
|
|
5
|
+
import './honest-patch-guard.js';
|
|
4
6
|
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
7
|
+
import { assertPatchKeepsIdentity, PatchRefusedError, runPatchGuards } from './patch-guards.js';
|
|
5
8
|
import { PatchSchema } from './schemas.js';
|
|
6
9
|
export const applyPatchInput = {
|
|
7
10
|
patches: z.array(PatchSchema),
|
|
@@ -15,7 +18,7 @@ export const applyPatchOutput = {
|
|
|
15
18
|
export function registerApplyPatch(server, bridge) {
|
|
16
19
|
server.registerTool('apply_patch', {
|
|
17
20
|
title: 'Apply patch',
|
|
18
|
-
description:
|
|
21
|
+
description: "Apply a batch of create/update/delete operations atomically. All patches are validated before any are applied; the entire batch forms a single undo step. Batch-first is the default: prefer one apply_patch call containing all create/update/delete ops for a build step, in stable order so later ops can reference ids created by earlier ops. A single call is atomic (all or nothing) and pays the snapshot and save cost once; do not loop one-op calls. A create whose id already exists fails the whole patch with node_exists; to replace a node, delete it earlier in the same patch. An update cannot change id or type (identity_change) or object or children (immutable_field); restating the current value is fine. A parentId change must name an existing node that holds children (invalid_parent). An update cannot add schema issues to a node (invalid_update). After a delete or a roof update that regenerates a roof's default gutters, those gutters and their downspouts are addressable only in a later call (regenerated_default). Refusals come back as a tool error whose text is JSON {code, patchIndex, id, message}.",
|
|
19
22
|
inputSchema: applyPatchInput,
|
|
20
23
|
outputSchema: applyPatchOutput,
|
|
21
24
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
@@ -42,6 +45,10 @@ export function registerApplyPatch(server, bridge) {
|
|
|
42
45
|
};
|
|
43
46
|
});
|
|
44
47
|
try {
|
|
48
|
+
runPatchGuards(bridgePatches, bridge.getNodes());
|
|
49
|
+
const planDeletion = bridge
|
|
50
|
+
.planDeletion;
|
|
51
|
+
assertPatchKeepsIdentity(bridgePatches, bridge.getNodes(), bridge.getRootNodeIds(), typeof planDeletion === 'function' ? planDeletion.bind(bridge) : undefined);
|
|
45
52
|
const result = bridge.applyPatch(bridgePatches);
|
|
46
53
|
const persistence = await publishLiveSceneSnapshot(bridge, 'apply_patch');
|
|
47
54
|
const payload = {
|
|
@@ -56,6 +63,25 @@ export function registerApplyPatch(server, bridge) {
|
|
|
56
63
|
};
|
|
57
64
|
}
|
|
58
65
|
catch (err) {
|
|
66
|
+
if (err instanceof PatchRefusedError) {
|
|
67
|
+
// A tool error, not an McpError: the SDK keeps only an McpError's
|
|
68
|
+
// message, and clients need the code, index and id to act on it.
|
|
69
|
+
const refusal = {
|
|
70
|
+
code: err.code,
|
|
71
|
+
patchIndex: err.patchIndex,
|
|
72
|
+
id: err.nodeId,
|
|
73
|
+
message: err.message,
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: 'text', text: JSON.stringify(refusal) }],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// A refusal the store made (an accidental wipe) answers with its code, as the shared tools'.
|
|
81
|
+
if (isAgentRefusal(err))
|
|
82
|
+
return refusalResult(err);
|
|
83
|
+
if (err instanceof McpError)
|
|
84
|
+
throw err;
|
|
59
85
|
const msg = err instanceof Error ? err.message : String(err);
|
|
60
86
|
throwMcpError(ErrorCode.InvalidParams, msg);
|
|
61
87
|
}
|
|
@@ -8,9 +8,13 @@ import type { AssetInput } from '@pascal-app/core/schema';
|
|
|
8
8
|
* common AI-generated residential layouts.
|
|
9
9
|
*/
|
|
10
10
|
export declare const MCP_CATALOG_ITEMS: AssetInput[];
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The items search_assets, place_items and furnish_room draw from. A host passes its own (the hosted
|
|
13
|
+
* app: its published library, as the chat searches); a standalone server keeps the built-in list.
|
|
14
|
+
*/
|
|
15
|
+
export type AssetCatalog = () => Promise<readonly AssetInput[]>;
|
|
16
|
+
export declare const builtInCatalog: AssetCatalog;
|
|
17
|
+
/** A host's catalog, read once by the first call that needs it; a failed read is tried again. */
|
|
18
|
+
export declare function cachedCatalog(load: AssetCatalog): AssetCatalog;
|
|
19
|
+
export declare function findCatalogItem(items: readonly AssetInput[], id: string): AssetInput | undefined;
|
|
16
20
|
//# sourceMappingURL=asset-catalog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-catalog.d.ts","sourceRoot":"","sources":["../../src/tools/asset-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,UAAU,EA6RzC,CAAA;AAED,
|
|
1
|
+
{"version":3,"file":"asset-catalog.d.ts","sourceRoot":"","sources":["../../src/tools/asset-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,UAAU,EA6RzC,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAA;AAE/D,eAAO,MAAM,cAAc,EAAE,YAA4C,CAAA;AAEzE,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAO9D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEhG"}
|
|
@@ -292,17 +292,15 @@ export const MCP_CATALOG_ITEMS = [
|
|
|
292
292
|
scale: [1, 1, 1],
|
|
293
293
|
},
|
|
294
294
|
];
|
|
295
|
-
export
|
|
296
|
-
|
|
295
|
+
export const builtInCatalog = async () => MCP_CATALOG_ITEMS;
|
|
296
|
+
/** A host's catalog, read once by the first call that needs it; a failed read is tried again. */
|
|
297
|
+
export function cachedCatalog(load) {
|
|
298
|
+
let items = null;
|
|
299
|
+
return () => (items ??= load().catch((error) => {
|
|
300
|
+
items = null;
|
|
301
|
+
throw error;
|
|
302
|
+
}));
|
|
297
303
|
}
|
|
298
|
-
export function
|
|
299
|
-
|
|
300
|
-
return MCP_CATALOG_ITEMS.filter((item) => {
|
|
301
|
-
if (args.category && item.category !== args.category)
|
|
302
|
-
return false;
|
|
303
|
-
const haystack = [item.id, item.name, item.category, ...(item.tags ?? [])]
|
|
304
|
-
.join(' ')
|
|
305
|
-
.toLowerCase();
|
|
306
|
-
return terms.every((term) => haystack.includes(term));
|
|
307
|
-
});
|
|
304
|
+
export function findCatalogItem(items, id) {
|
|
305
|
+
return items.find((item) => item.id === id);
|
|
308
306
|
}
|
|
@@ -64,8 +64,8 @@ export declare const checkCollisionsOutput: {
|
|
|
64
64
|
bId: z.ZodString;
|
|
65
65
|
kind: z.ZodString;
|
|
66
66
|
violation: z.ZodEnum<{
|
|
67
|
-
overlap: "overlap";
|
|
68
67
|
clearance: "clearance";
|
|
68
|
+
overlap: "overlap";
|
|
69
69
|
}>;
|
|
70
70
|
minimumClearanceMeters: z.ZodNumber;
|
|
71
71
|
}, z.core.$strip>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-collisions.d.ts","sourceRoot":"","sources":["../../src/tools/check-collisions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;
|
|
1
|
+
{"version":3,"file":"check-collisions.d.ts","sourceRoot":"","sources":["../../src/tools/check-collisions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAOxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AA4BpD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;CA+BhC,CAAA;AAED,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDjC,CAAA;AA6BD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAyKxF"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { findItemItemCollisions, inspectItemPlanFootprint, resolveNodeLevelId, } from '@pascal-app/core/agent-operations';
|
|
1
2
|
import { ItemNode } from '@pascal-app/core/schema';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
|
-
import { inspectItemPlanFootprint, resolveNodeLevelId } from './door-clearance.js';
|
|
5
5
|
import { ErrorCode, throwMcpError } from './errors.js';
|
|
6
|
-
import { findItemItemCollisions } from './layout-clearance.js';
|
|
7
6
|
import { measurement } from './measurement.js';
|
|
8
7
|
import { computeGraphHash } from './scene-lifecycle/metadata.js';
|
|
9
8
|
import { NodeIdSchema } from './schemas.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { SceneOperations } from '../operations/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* `clear_scene`: the scene goes back to the host's default scaffold (a site, a building, a level),
|
|
5
|
+
* then is saved with `allowSceneWipe`, so a store that refuses an accidental wipe takes this one.
|
|
6
|
+
* The project's installed plugins stay, and its undo history goes, as the editor's own clear does.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerClearScene(server: McpServer, operations: SceneOperations): void;
|
|
9
|
+
//# sourceMappingURL=clear-scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear-scene.d.ts","sourceRoot":"","sources":["../../src/tools/clear-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAmDvF"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { clearSceneTool } from '@pascal-app/core/agent-tools';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
|
+
import { refusalResult } from './errors.js';
|
|
5
|
+
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
6
|
+
/**
|
|
7
|
+
* `clear_scene`: the scene goes back to the host's default scaffold (a site, a building, a level),
|
|
8
|
+
* then is saved with `allowSceneWipe`, so a store that refuses an accidental wipe takes this one.
|
|
9
|
+
* The project's installed plugins stay, and its undo history goes, as the editor's own clear does.
|
|
10
|
+
*/
|
|
11
|
+
export function registerClearScene(server, operations) {
|
|
12
|
+
server.registerTool(clearSceneTool.name, {
|
|
13
|
+
title: clearSceneTool.title,
|
|
14
|
+
description: clearSceneTool.description,
|
|
15
|
+
inputSchema: clearSceneTool.input,
|
|
16
|
+
outputSchema: {
|
|
17
|
+
cleared: z.object({ removed: z.number() }),
|
|
18
|
+
version: z.number().nullable(),
|
|
19
|
+
graphHash: z.string().nullable(),
|
|
20
|
+
...liveSyncOutput,
|
|
21
|
+
},
|
|
22
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
23
|
+
}, async () => {
|
|
24
|
+
try {
|
|
25
|
+
const before = Object.keys(operations.getNodes()).length;
|
|
26
|
+
const { installedPlugins } = operations.exportSceneGraph();
|
|
27
|
+
operations.setScene({}, []);
|
|
28
|
+
operations.loadDefault();
|
|
29
|
+
// Resetting drops the plugin state on every host; the scaffold is applied again with it.
|
|
30
|
+
if (installedPlugins)
|
|
31
|
+
operations.loadJSON({
|
|
32
|
+
...operations.exportSceneGraph(),
|
|
33
|
+
collections: {},
|
|
34
|
+
materials: {},
|
|
35
|
+
installedPlugins,
|
|
36
|
+
});
|
|
37
|
+
// Nothing to undo back into: the empty intermediate or the old scene, saved over the clear.
|
|
38
|
+
operations.clearHistory();
|
|
39
|
+
const removed = Math.max(0, before - Object.keys(operations.getNodes()).length);
|
|
40
|
+
const persistence = await publishLiveSceneSnapshot(operations, clearSceneTool.name, {
|
|
41
|
+
allowSceneWipe: true,
|
|
42
|
+
});
|
|
43
|
+
const active = operations.getActiveScene();
|
|
44
|
+
const payload = {
|
|
45
|
+
cleared: { removed },
|
|
46
|
+
version: active?.version ?? null,
|
|
47
|
+
graphHash: active?.graphHash ?? null,
|
|
48
|
+
...persistencePayload(persistence),
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
52
|
+
structuredContent: payload,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return refusalResult(error);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { SceneOperations } from '../operations/index.js';
|
|
3
|
+
export declare function registerCollectionTools(server: McpServer, bridge: SceneOperations): void;
|
|
4
|
+
//# sourceMappingURL=collections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/tools/collections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAWxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAgBpD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA+CxF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { editCollection, listCollections, writeCollections, } from '@pascal-app/core/agent-operations';
|
|
2
|
+
import { editCollectionTool, listCollectionsTool } from '@pascal-app/core/agent-tools';
|
|
3
|
+
import { DESTRUCTIVE_TOOL_ANNOTATIONS, READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
|
+
import { refusalResult } from './errors.js';
|
|
5
|
+
import { persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
6
|
+
// The collection tools share contracts and operations with the chat; they read the scene's
|
|
7
|
+
// collections beside its nodes, which the node-only shared operations never see.
|
|
8
|
+
function sceneOf(bridge) {
|
|
9
|
+
return { nodes: bridge.getNodes(), collections: bridge.getCollections() };
|
|
10
|
+
}
|
|
11
|
+
function reply(payload) {
|
|
12
|
+
return { content: [{ type: 'text', text: JSON.stringify(payload) }] };
|
|
13
|
+
}
|
|
14
|
+
export function registerCollectionTools(server, bridge) {
|
|
15
|
+
server.registerTool(listCollectionsTool.name, {
|
|
16
|
+
title: listCollectionsTool.title,
|
|
17
|
+
description: listCollectionsTool.description,
|
|
18
|
+
inputSchema: listCollectionsTool.input,
|
|
19
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
20
|
+
}, async (input) => {
|
|
21
|
+
try {
|
|
22
|
+
return reply(listCollections(sceneOf(bridge), input).result);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
return refusalResult(error);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
server.registerTool(editCollectionTool.name, {
|
|
29
|
+
title: editCollectionTool.title,
|
|
30
|
+
description: editCollectionTool.description,
|
|
31
|
+
inputSchema: editCollectionTool.input,
|
|
32
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
33
|
+
}, async (input) => {
|
|
34
|
+
let outcome;
|
|
35
|
+
try {
|
|
36
|
+
outcome = editCollection(sceneOf(bridge), input);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return refusalResult(error);
|
|
40
|
+
}
|
|
41
|
+
const { update, collections = {} } = outcome.changes ?? {};
|
|
42
|
+
bridge.runAsSingleHistoryStep(() => {
|
|
43
|
+
if (update?.length)
|
|
44
|
+
bridge.applyPatch(update.map(({ id, data }) => ({ op: 'update', id: id, data })));
|
|
45
|
+
bridge.setCollections(writeCollections(bridge.getCollections(), collections));
|
|
46
|
+
});
|
|
47
|
+
return reply({
|
|
48
|
+
...outcome.result,
|
|
49
|
+
...persistencePayload(await publishLiveSceneSnapshot(bridge, editCollectionTool.name)),
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -16,6 +16,8 @@ export declare const createStoryShellInput: {
|
|
|
16
16
|
ceilingMaterialPreset: z.ZodOptional<z.ZodString>;
|
|
17
17
|
};
|
|
18
18
|
export declare const createStoryShellOutput: {
|
|
19
|
+
project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
|
+
unsaved: z.ZodOptional<z.ZodString>;
|
|
19
21
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
20
22
|
status: z.ZodEnum<{
|
|
21
23
|
unbound: "unbound";
|
|
@@ -25,7 +27,11 @@ export declare const createStoryShellOutput: {
|
|
|
25
27
|
}, z.core.$strip>>;
|
|
26
28
|
levelId: z.ZodString;
|
|
27
29
|
wallIds: z.ZodArray<z.ZodString>;
|
|
30
|
+
/** Zones the reconciler derived for the enclosed faces. */
|
|
31
|
+
zoneIds: z.ZodArray<z.ZodString>;
|
|
32
|
+
/** Derived floor plate. `null` when floors were declined or nothing reconciled. */
|
|
28
33
|
slabId: z.ZodNullable<z.ZodString>;
|
|
34
|
+
/** Derived ceiling. `null` when ceilings were declined or nothing reconciled. */
|
|
29
35
|
ceilingId: z.ZodNullable<z.ZodString>;
|
|
30
36
|
createdIds: z.ZodArray<z.ZodString>;
|
|
31
37
|
};
|
|
@@ -57,6 +63,8 @@ export declare const createRoofInput: {
|
|
|
57
63
|
name: z.ZodOptional<z.ZodString>;
|
|
58
64
|
};
|
|
59
65
|
export declare const createRoofOutput: {
|
|
66
|
+
project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
67
|
+
unsaved: z.ZodOptional<z.ZodString>;
|
|
60
68
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
61
69
|
status: z.ZodEnum<{
|
|
62
70
|
unbound: "unbound";
|
|
@@ -70,46 +78,5 @@ export declare const createRoofOutput: {
|
|
|
70
78
|
roofId: z.ZodString;
|
|
71
79
|
roofSegmentId: z.ZodString;
|
|
72
80
|
};
|
|
73
|
-
export declare const createStairBetweenLevelsInput: {
|
|
74
|
-
fromLevelId: z.ZodString;
|
|
75
|
-
toLevelId: z.ZodString;
|
|
76
|
-
position: z.ZodArray<z.ZodNumber>;
|
|
77
|
-
rotation: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
78
|
-
width: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
79
|
-
runLength: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
80
|
-
totalRise: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
81
|
-
stepCount: z.ZodDefault<z.ZodNumber>;
|
|
82
|
-
railingMode: z.ZodDefault<z.ZodEnum<{
|
|
83
|
-
none: "none";
|
|
84
|
-
both: "both";
|
|
85
|
-
right: "right";
|
|
86
|
-
left: "left";
|
|
87
|
-
}>>;
|
|
88
|
-
destinationSlabId: z.ZodOptional<z.ZodString>;
|
|
89
|
-
sourceCeilingId: z.ZodOptional<z.ZodString>;
|
|
90
|
-
createDestinationSlabOpening: z.ZodDefault<z.ZodBoolean>;
|
|
91
|
-
createSourceCeilingOpening: z.ZodDefault<z.ZodBoolean>;
|
|
92
|
-
openingWidth: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
93
|
-
openingLength: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
94
|
-
openingOffset: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
95
|
-
openingCenter: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
96
|
-
openingRotation: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
|
|
97
|
-
materialPreset: z.ZodOptional<z.ZodString>;
|
|
98
|
-
name: z.ZodOptional<z.ZodString>;
|
|
99
|
-
};
|
|
100
|
-
export declare const createStairBetweenLevelsOutput: {
|
|
101
|
-
persistence: z.ZodOptional<z.ZodObject<{
|
|
102
|
-
status: z.ZodEnum<{
|
|
103
|
-
unbound: "unbound";
|
|
104
|
-
events_unsupported: "events_unsupported";
|
|
105
|
-
}>;
|
|
106
|
-
warning: z.ZodString;
|
|
107
|
-
}, z.core.$strip>>;
|
|
108
|
-
stairId: z.ZodString;
|
|
109
|
-
stairSegmentId: z.ZodString;
|
|
110
|
-
destinationSlabId: z.ZodNullable<z.ZodString>;
|
|
111
|
-
sourceCeilingId: z.ZodNullable<z.ZodString>;
|
|
112
|
-
openingPolygon: z.ZodArray<z.ZodArray<z.ZodNumber>>;
|
|
113
|
-
};
|
|
114
81
|
export declare function registerConstructionTools(server: McpServer, bridge: SceneOperations): void;
|
|
115
82
|
//# sourceMappingURL=construction-tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"construction-tools.d.ts","sourceRoot":"","sources":["../../src/tools/construction-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;
|
|
1
|
+
{"version":3,"file":"construction-tools.d.ts","sourceRoot":"","sources":["../../src/tools/construction-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAKxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAgBpD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CA8BjC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;IAGjC,2DAA2D;;IAE3D,mFAAmF;;IAEnF,iFAAiF;;;CAIlF,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;CAO5B,CAAA;AAgFD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA2O1F"}
|