@jgengine/editor 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +12 -0
- package/dist/AssetBrowser.d.ts +33 -1
- package/dist/AssetBrowser.js +64 -2
- package/dist/AssetDropZone.d.ts +9 -0
- package/dist/AssetDropZone.js +65 -0
- package/dist/CatalogsPanel.d.ts +4 -2
- package/dist/CatalogsPanel.js +162 -9
- package/dist/CityPreview.d.ts +11 -0
- package/dist/CityPreview.js +45 -0
- package/dist/CollectionsPanel.js +5 -5
- package/dist/DebugDraw.d.ts +3 -1
- package/dist/DebugDraw.js +37 -19
- package/dist/EditorApp.d.ts +15 -1
- package/dist/EditorApp.js +147 -35
- package/dist/EditorChrome.d.ts +27 -6
- package/dist/EditorChrome.js +314 -130
- package/dist/InspectorPanel.d.ts +17 -7
- package/dist/InspectorPanel.js +173 -27
- package/dist/LightingPanel.d.ts +11 -0
- package/dist/LightingPanel.js +99 -0
- package/dist/MaterialsWorkspacePanel.d.ts +12 -0
- package/dist/MaterialsWorkspacePanel.js +86 -0
- package/dist/ParentPickerMenu.d.ts +13 -0
- package/dist/ParentPickerMenu.js +33 -0
- package/dist/PerfProbe.js +33 -0
- package/dist/PrefabsPanel.js +5 -5
- package/dist/RuntimePlayBridge.d.ts +5 -3
- package/dist/RuntimePlayBridge.js +6 -13
- package/dist/ScatterPreview.d.ts +3 -1
- package/dist/ScatterPreview.js +10 -7
- package/dist/SchemaInspector.js +21 -8
- package/dist/ScriptingPanel.d.ts +15 -0
- package/dist/ScriptingPanel.js +46 -0
- package/dist/SelectionGizmo.js +114 -30
- package/dist/StandaloneEditor.d.ts +16 -9
- package/dist/StandaloneEditor.js +19 -20
- package/dist/TerrainPanel.d.ts +3 -2
- package/dist/TerrainPanel.js +16 -5
- package/dist/TerrainSculpt.js +98 -59
- package/dist/agent/AgentPanel.d.ts +5 -2
- package/dist/agent/AgentPanel.js +11 -6
- package/dist/agent/toolBridge.js +5 -0
- package/dist/assetImport.d.ts +36 -0
- package/dist/assetImport.js +66 -0
- package/dist/authoredComponentMeta.d.ts +25 -0
- package/dist/authoredComponentMeta.js +65 -0
- package/dist/gizmoPivot.d.ts +4 -0
- package/dist/gizmoPivot.js +34 -0
- package/dist/handlers/catalogs.d.ts +3 -0
- package/dist/handlers/catalogs.js +137 -0
- package/dist/handlers/collections.d.ts +3 -0
- package/dist/handlers/collections.js +57 -0
- package/dist/handlers/context.d.ts +36 -0
- package/dist/handlers/context.js +1 -0
- package/dist/handlers/document.d.ts +3 -0
- package/dist/handlers/document.js +350 -0
- package/dist/handlers/grids.d.ts +3 -0
- package/dist/handlers/grids.js +142 -0
- package/dist/handlers/hierarchy.d.ts +3 -0
- package/dist/handlers/hierarchy.js +55 -0
- package/dist/handlers/index.d.ts +8 -0
- package/dist/handlers/index.js +25 -0
- package/dist/handlers/minimap.d.ts +9 -0
- package/dist/handlers/minimap.js +32 -0
- package/dist/handlers/runtime.d.ts +3 -0
- package/dist/handlers/runtime.js +191 -0
- package/dist/handlers/streets.d.ts +3 -0
- package/dist/handlers/streets.js +159 -0
- package/dist/handlers/terrain.d.ts +3 -0
- package/dist/handlers/terrain.js +204 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/listDocumentTriggers.d.ts +42 -0
- package/dist/listDocumentTriggers.js +49 -0
- package/dist/materialAssignments.d.ts +63 -0
- package/dist/materialAssignments.js +84 -0
- package/dist/mcp/fieldSpec.d.ts +32 -0
- package/dist/mcp/fieldSpec.js +174 -0
- package/dist/mcp/rpcRequest.d.ts +8 -5
- package/dist/mcp/rpcRequest.js +72 -93
- package/dist/mcp/tools.js +105 -912
- package/dist/networkSnapshot.d.ts +82 -0
- package/dist/networkSnapshot.js +73 -0
- package/dist/parentCandidates.d.ts +12 -0
- package/dist/parentCandidates.js +25 -0
- package/dist/session.d.ts +91 -4
- package/dist/session.js +36 -1017
- package/dist/shell/AnimationPanel.d.ts +17 -0
- package/dist/shell/AnimationPanel.js +134 -0
- package/dist/shell/AssetThumbnail.d.ts +12 -0
- package/dist/shell/AssetThumbnail.js +23 -0
- package/dist/shell/BottomDock.d.ts +25 -0
- package/dist/shell/BottomDock.js +40 -0
- package/dist/shell/CommandPalette.d.ts +12 -0
- package/dist/shell/CommandPalette.js +56 -0
- package/dist/shell/ConsolePanel.d.ts +8 -0
- package/dist/shell/ConsolePanel.js +45 -0
- package/dist/shell/ContentBrowser.d.ts +21 -0
- package/dist/shell/ContentBrowser.js +130 -0
- package/dist/shell/HierarchyPanel.d.ts +26 -0
- package/dist/shell/HierarchyPanel.js +387 -0
- package/dist/shell/NetworkWorkspacePanel.d.ts +11 -0
- package/dist/shell/NetworkWorkspacePanel.js +49 -0
- package/dist/shell/PlayModeBar.d.ts +12 -0
- package/dist/shell/PlayModeBar.js +27 -0
- package/dist/shell/ProfilerPanel.d.ts +10 -0
- package/dist/shell/ProfilerPanel.js +41 -0
- package/dist/shell/SceneToolbar.d.ts +43 -0
- package/dist/shell/SceneToolbar.js +122 -0
- package/dist/shell/StatusBar.d.ts +18 -0
- package/dist/shell/StatusBar.js +41 -0
- package/dist/shell/TopAppBar.d.ts +35 -0
- package/dist/shell/TopAppBar.js +64 -0
- package/dist/shell/ViewportOverlays.d.ts +23 -0
- package/dist/shell/ViewportOverlays.js +136 -0
- package/dist/shell/WorkspaceRail.d.ts +20 -0
- package/dist/shell/WorkspaceRail.js +31 -0
- package/dist/shell/cameraTelemetry.d.ts +27 -0
- package/dist/shell/cameraTelemetry.js +24 -0
- package/dist/shell/commandRegistry.d.ts +58 -0
- package/dist/shell/commandRegistry.js +133 -0
- package/dist/shell/consoleSink.d.ts +11 -0
- package/dist/shell/consoleSink.js +17 -0
- package/dist/shell/consoleStore.d.ts +27 -0
- package/dist/shell/consoleStore.js +43 -0
- package/dist/shell/fields.d.ts +39 -0
- package/dist/shell/fields.js +104 -0
- package/dist/shell/formatSavedRelative.d.ts +2 -0
- package/dist/shell/formatSavedRelative.js +14 -0
- package/dist/shell/glbThumbnailCache.d.ts +45 -0
- package/dist/shell/glbThumbnailCache.js +241 -0
- package/dist/shell/hierarchyA11y.d.ts +21 -0
- package/dist/shell/hierarchyA11y.js +35 -0
- package/dist/shell/icons.d.ts +13 -0
- package/dist/shell/icons.js +85 -0
- package/dist/shell/layoutStore.d.ts +68 -0
- package/dist/shell/layoutStore.js +156 -0
- package/dist/shell/pathFlythrough.d.ts +37 -0
- package/dist/shell/pathFlythrough.js +54 -0
- package/dist/shell/perfHistory.d.ts +70 -0
- package/dist/shell/perfHistory.js +130 -0
- package/dist/shell/renameObject.d.ts +3 -0
- package/dist/shell/renameObject.js +25 -0
- package/dist/shell/theme.d.ts +36 -0
- package/dist/shell/theme.js +37 -0
- package/dist/shell/ui.d.ts +84 -0
- package/dist/shell/ui.js +90 -0
- package/dist/shell/useGlbThumbnail.d.ts +8 -0
- package/dist/shell/useGlbThumbnail.js +19 -0
- package/dist/uiStore.d.ts +27 -0
- package/dist/uiStore.js +10 -0
- package/dist/viewportContextMenu.d.ts +4 -2
- package/dist/viewportContextMenu.js +5 -1
- package/package.json +4 -4
- package/skills/jgengine/SKILL.md +8 -4
- package/skills/jgengine/api.md +182 -81
- package/skills/jgengine/capabilities.md +104 -2
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-editor/SKILL.md +18 -3
- package/skills/jgengine-editor/api.md +403 -20
- package/skills/jgengine-editor/capabilities.md +46 -0
- package/skills/jgengine-editor/reference.md +87 -0
- package/skills/level-design/SKILL.md +54 -0
- package/skills/level-design/agents/openai.yaml +4 -0
- package/skills/level-design/references/application-playbook.md +192 -0
- package/skills/level-design/references/field-guide.md +337 -0
- package/skills/level-design/references/live-editor-loop.md +179 -0
- package/dist/OutlinerPanel.d.ts +0 -14
- package/dist/OutlinerPanel.js +0 -84
- package/skills/jgengine/reference-cartridge.md +0 -72
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// Terse builders so the per-method table below reads as a schema, not a wall of object literals.
|
|
2
|
+
const s = (name, oneOf) => (oneOf === undefined ? { name, kind: "string" } : { name, kind: "string", oneOf });
|
|
3
|
+
const sn = (name) => ({ name, kind: "string", nullable: true });
|
|
4
|
+
const n = (name) => ({ name, kind: "number" });
|
|
5
|
+
const b = (name) => ({ name, kind: "boolean" });
|
|
6
|
+
const sa = (name) => ({ name, kind: "string[]" });
|
|
7
|
+
const o = (name) => ({ name, kind: "object" });
|
|
8
|
+
const oa = (name, of) => (of === undefined ? { name, kind: "object[]" } : { name, kind: "object[]", of });
|
|
9
|
+
const v3 = (name) => ({ name, kind: "vec3" });
|
|
10
|
+
const val = (name) => ({ name, kind: "value" });
|
|
11
|
+
/** Marks a field mandatory for MCP schema generation; presence itself is still checked by `handle`. */
|
|
12
|
+
const req = (spec) => ({ ...spec, required: true });
|
|
13
|
+
const SHAPE = ["circle", "square"];
|
|
14
|
+
const AXES = ["xz", "xy"];
|
|
15
|
+
/**
|
|
16
|
+
* Per-method field type table — the single source of truth for the RPC boundary. A field listed here
|
|
17
|
+
* is type-checked when present (see `decodeEditorBridgeRequest`); existence is left to
|
|
18
|
+
* `EditorHostApi.handle` (whose per-method guards return honest `ok:false` diagnostics for
|
|
19
|
+
* missing/unknown targets). Type-checking presented fields is what keeps a fuzzed value — a string
|
|
20
|
+
* where a number belongs, a scalar where an object belongs — from reaching a live session uncoerced.
|
|
21
|
+
* Unknown extra fields are ignored so a superset payload stays forward-compatible.
|
|
22
|
+
*
|
|
23
|
+
* The same table generates the MCP tool `inputSchema`s (see `mcp/tools.ts`), so `required`/`oneOf`/
|
|
24
|
+
* `of` here also shape what agents are told a tool accepts. The `Record<EditorBridgeRequest["method"],
|
|
25
|
+
* …>` type is the lockstep guarantee: adding a method to the union in `session.ts` fails to compile
|
|
26
|
+
* here until it gets a schema, and a stale entry is a compile error too.
|
|
27
|
+
*/
|
|
28
|
+
export const RPC_FIELD_SCHEMAS = {
|
|
29
|
+
editor_status: [],
|
|
30
|
+
set_mode: [req(s("mode", ["edit", "walk", "play", "hud"]))],
|
|
31
|
+
perf_report: [],
|
|
32
|
+
list_layers: [],
|
|
33
|
+
list_catalogs: [],
|
|
34
|
+
get_catalog_entry: [req(s("catalogId")), req(s("entryId"))],
|
|
35
|
+
set_catalog_entry: [req(s("catalogId")), req(s("entryId")), req(o("patch")), s("label")],
|
|
36
|
+
add_catalog_entry: [req(s("catalogId")), req(s("entryId")), o("meta"), s("label")],
|
|
37
|
+
remove_catalog_entry: [req(s("catalogId")), req(s("entryId"))],
|
|
38
|
+
add_catalog: [req(s("catalogId")), s("label"), o("schema")],
|
|
39
|
+
remove_catalog: [req(s("catalogId"))],
|
|
40
|
+
set_catalog_schema: [req(s("catalogId")), req(o("schema")), s("label")],
|
|
41
|
+
list_selection: [],
|
|
42
|
+
get_marker: [req(s("id"))],
|
|
43
|
+
get_volume: [req(s("id"))],
|
|
44
|
+
set_transform: [req(s("id")), n("x"), n("y"), n("z"), n("rotationY")],
|
|
45
|
+
set_volume: [req(s("id")), n("radius"), n("height"), n("x"), n("y"), n("z")],
|
|
46
|
+
set_path: [req(s("id")), s("kind"), n("width"), s("color"), s("label"), o("meta")],
|
|
47
|
+
set_marker: [req(s("id")), s("kind"), s("color"), s("label"), n("rotationY"), o("meta")],
|
|
48
|
+
set_note: [req(s("id")), s("text"), o("meta")],
|
|
49
|
+
set_meta: [req(s("id")), req(o("patch"))],
|
|
50
|
+
apply_preset: [req(s("id")), req(s("preset"))],
|
|
51
|
+
select: [req(sa("ids"))],
|
|
52
|
+
clear_selection: [],
|
|
53
|
+
camera_goto: [s("id"), n("x"), n("y"), n("z")],
|
|
54
|
+
camera_frame: [],
|
|
55
|
+
scene_summary: [],
|
|
56
|
+
export_document: [],
|
|
57
|
+
import_document: [req(s("json"))],
|
|
58
|
+
dispatch: [req(o("command"))],
|
|
59
|
+
undo: [],
|
|
60
|
+
redo: [],
|
|
61
|
+
list_assets: [],
|
|
62
|
+
place_asset: [req(s("id")), s("kind"), n("x"), n("y"), n("z")],
|
|
63
|
+
create_terrain: [n("width"), n("depth"), n("cellSize"), n("centerX"), n("centerZ")],
|
|
64
|
+
sculpt_terrain: [req(s("mode", ["raise", "lower", "smooth", "flatten", "noise", "ramp"])), req(n("x")), req(n("z")), n("radius"), n("strength"), n("target"), n("toX"), n("toZ"), n("seed"), s("shape", SHAPE)],
|
|
65
|
+
terrain_summary: [],
|
|
66
|
+
paint_terrain: [req(s("surface")), req(n("x")), req(n("z")), n("radius"), s("shape", SHAPE)],
|
|
67
|
+
fill_terrain: [req(sn("surface"))],
|
|
68
|
+
auto_paint: [req(s("surface")), n("minSlope"), n("maxSlope"), n("minHeight"), n("maxHeight")],
|
|
69
|
+
terrain_materials: [],
|
|
70
|
+
terrain_layers: [],
|
|
71
|
+
set_terrain_layers: [req(oa("layers", [req(s("id")), req(s("surface")), n("roughness"), n("tiling"), b("triplanar"), s("tint"), n("opacity")]))],
|
|
72
|
+
blend_terrain: [req(s("surface")), req(n("x")), req(n("z")), n("radius"), n("strength"), s("shape", SHAPE)],
|
|
73
|
+
convert_scatter: [req(s("pathId"))],
|
|
74
|
+
generate_streets: [s("volumeId"), v3("center"), n("halfX"), n("halfZ"), s("seed"), s("mode", ["net", "circuit"]), s("kind"), o("params")],
|
|
75
|
+
bake_minimap: [n("padding"), n("resolution"), n("waterLevel")],
|
|
76
|
+
add_foliage: [req(oa("points", [req(n("x")), req(n("z"))])), n("density"), s("item"), s("seed"), n("minSpacing")],
|
|
77
|
+
scatter_summary: [],
|
|
78
|
+
set_parent: [req(sa("ids")), req(sn("parentId"))],
|
|
79
|
+
hierarchy: [],
|
|
80
|
+
list_prefabs: [],
|
|
81
|
+
create_prefab: [req(s("id")), req(s("name")), req(sa("ids"))],
|
|
82
|
+
insert_prefab: [req(s("prefabId")), n("x"), n("y"), n("z")],
|
|
83
|
+
detach_prefab_instance: [req(s("instanceId"))],
|
|
84
|
+
delete_prefab: [req(s("prefabId"))],
|
|
85
|
+
list_collections: [],
|
|
86
|
+
create_collection: [req(s("id")), req(s("name")), sa("memberIds")],
|
|
87
|
+
rename_collection: [req(s("id")), req(s("name"))],
|
|
88
|
+
delete_collection: [req(s("id"))],
|
|
89
|
+
set_collection_members: [req(s("id")), req(sa("memberIds"))],
|
|
90
|
+
add_to_collection: [req(s("id")), req(sa("ids"))],
|
|
91
|
+
remove_from_collection: [req(s("id")), req(sa("ids"))],
|
|
92
|
+
set_collection_flags: [req(s("id")), s("color"), b("locked"), b("visible")],
|
|
93
|
+
select_collection: [req(s("id"))],
|
|
94
|
+
set_object_flags: [req(sa("ids")), b("locked"), b("hidden")],
|
|
95
|
+
batch_set_properties: [req(sa("ids")), s("color"), s("label"), o("meta")],
|
|
96
|
+
assign_material: [req(sa("ids")), req(s("materialId"))],
|
|
97
|
+
list_grids: [],
|
|
98
|
+
get_grid_cell: [req(s("id")), req(n("col")), req(n("row"))],
|
|
99
|
+
add_grid_layer: [req(s("id")), req(s("kind")), req(n("cols")), req(n("rows")), s("label"), n("cellSize"), v3("origin"), s("axes", AXES), s("empty"), oa("palette")],
|
|
100
|
+
remove_grid_layer: [req(s("id"))],
|
|
101
|
+
set_grid_layer: [req(s("id")), s("label"), s("kind"), b("visible"), s("empty"), n("cellSize"), v3("origin"), s("axes", AXES), oa("palette")],
|
|
102
|
+
paint_grid_cells: [req(s("id")), req(oa("cells", [req(n("col")), req(n("row")), req(s("value"))]))],
|
|
103
|
+
fill_grid_rect: [req(s("id")), req(n("col0")), req(n("row0")), req(n("col1")), req(n("row1")), req(s("value"))],
|
|
104
|
+
flood_fill_grid: [req(s("id")), req(n("col")), req(n("row")), req(s("value"))],
|
|
105
|
+
resize_grid_layer: [req(s("id")), req(n("cols")), req(n("rows"))],
|
|
106
|
+
import_grid: [req(s("id")), req(s("kind")), req(s("format", ["ascii", "csv"])), req(s("text")), s("empty"), n("cellSize"), v3("origin"), o("glyphMap"), oa("palette")],
|
|
107
|
+
push_document_patch: [req(o("patch")), b("force")],
|
|
108
|
+
pull_document_patches: [n("sinceRevision")],
|
|
109
|
+
document_revision: [b("includeDocument")],
|
|
110
|
+
push_runtime_delta: [n("at"), oa("entities"), sa("removeIds"), o("tunables")],
|
|
111
|
+
pull_runtime_deltas: [n("sinceSeq"), b("includeSnapshot")],
|
|
112
|
+
runtime_snapshot: [],
|
|
113
|
+
runtime_summary: [],
|
|
114
|
+
runtime_get: [req(s("id")), s("path")],
|
|
115
|
+
runtime_set: [req(s("id")), s("path"), val("value"), o("position"), n("rotationY"), o("values"), b("writeBack")],
|
|
116
|
+
runtime_pause: [],
|
|
117
|
+
runtime_resume: [],
|
|
118
|
+
runtime_step: [n("frames")],
|
|
119
|
+
set_runtime_override: [req(o("entity"))],
|
|
120
|
+
clear_runtime_override: [req(s("id"))],
|
|
121
|
+
write_back_override: [req(s("id"))],
|
|
122
|
+
};
|
|
123
|
+
/** The set of known RPC method names — exported for meta/manifest tooling and tests. @internal */
|
|
124
|
+
export const EDITOR_BRIDGE_METHOD_NAMES = Object.keys(RPC_FIELD_SCHEMAS).sort();
|
|
125
|
+
/** JSON-Schema fragment for one field spec (no `required` — that is aggregated by the object builder). */
|
|
126
|
+
function fieldToJsonSchema(spec) {
|
|
127
|
+
switch (spec.kind) {
|
|
128
|
+
case "string":
|
|
129
|
+
return spec.oneOf !== undefined
|
|
130
|
+
? { type: "string", enum: [...spec.oneOf] }
|
|
131
|
+
: spec.nullable === true
|
|
132
|
+
? { type: ["string", "null"] }
|
|
133
|
+
: { type: "string" };
|
|
134
|
+
case "number":
|
|
135
|
+
return { type: "number" };
|
|
136
|
+
case "boolean":
|
|
137
|
+
return { type: "boolean" };
|
|
138
|
+
case "string[]":
|
|
139
|
+
return { type: "array", items: { type: "string" } };
|
|
140
|
+
case "object":
|
|
141
|
+
return spec.of !== undefined ? objectSchema(spec.of) : { type: "object" };
|
|
142
|
+
case "object[]":
|
|
143
|
+
return { type: "array", items: spec.of !== undefined ? objectSchema(spec.of) : { type: "object" } };
|
|
144
|
+
case "vec3":
|
|
145
|
+
return {
|
|
146
|
+
type: "object",
|
|
147
|
+
properties: { x: { type: "number" }, y: { type: "number" }, z: { type: "number" } },
|
|
148
|
+
required: ["x", "y", "z"],
|
|
149
|
+
additionalProperties: false,
|
|
150
|
+
};
|
|
151
|
+
case "value":
|
|
152
|
+
return {};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** Assembles a closed object schema (properties + required + additionalProperties:false) from field specs. */
|
|
156
|
+
function objectSchema(specs) {
|
|
157
|
+
const properties = {};
|
|
158
|
+
const required = [];
|
|
159
|
+
for (const spec of specs) {
|
|
160
|
+
properties[spec.name] = fieldToJsonSchema(spec);
|
|
161
|
+
if (spec.required === true)
|
|
162
|
+
required.push(spec.name);
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
type: "object",
|
|
166
|
+
properties,
|
|
167
|
+
...(required.length > 0 ? { required } : {}),
|
|
168
|
+
additionalProperties: false,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/** Generates the MCP tool `inputSchema` for a method from its {@link RPC_FIELD_SCHEMAS} entry. */
|
|
172
|
+
export function buildInputSchema(method) {
|
|
173
|
+
return objectSchema(RPC_FIELD_SCHEMAS[method]);
|
|
174
|
+
}
|
package/dist/mcp/rpcRequest.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EditorBridgeRequest } from "../session.js";
|
|
2
|
+
export { EDITOR_BRIDGE_METHOD_NAMES } from "./fieldSpec.js";
|
|
2
3
|
/** One field-level failure surfaced while decoding an untrusted RPC request. */
|
|
3
4
|
export interface RpcRequestDiagnostic {
|
|
4
5
|
path: string;
|
|
@@ -13,10 +14,12 @@ export type DecodeRpcRequestResult = {
|
|
|
13
14
|
errors: RpcRequestDiagnostic[];
|
|
14
15
|
};
|
|
15
16
|
/**
|
|
16
|
-
* Validates an untrusted JSON-decoded RPC payload (from `--rpc
|
|
17
|
-
* reaches `EditorHostApi.handle`: confirms it is a plain object carrying a known
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* Validates an untrusted JSON-decoded RPC payload (from `--rpc`, the HTTP bridge, or an agent tool
|
|
18
|
+
* call) before it reaches `EditorHostApi.handle`: confirms it is a plain object carrying a known
|
|
19
|
+
* `method`, then type-checks every field the method understands against {@link RPC_FIELD_SCHEMAS}.
|
|
20
|
+
* A garbled method, or a field whose value is the wrong type (a string where a number belongs, a
|
|
21
|
+
* scalar where an object belongs), is rejected here with a path-specific diagnostic instead of
|
|
22
|
+
* flowing into a live session on a blind cast. Missing fields and unknown extra fields are left for
|
|
23
|
+
* `handle` to interpret so the boundary stays forward-compatible.
|
|
21
24
|
*/
|
|
22
25
|
export declare function decodeEditorBridgeRequest(raw: unknown): DecodeRpcRequestResult;
|
package/dist/mcp/rpcRequest.js
CHANGED
|
@@ -1,107 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"runtime_pause",
|
|
59
|
-
"runtime_resume",
|
|
60
|
-
"runtime_set",
|
|
61
|
-
"runtime_snapshot",
|
|
62
|
-
"runtime_step",
|
|
63
|
-
"runtime_summary",
|
|
64
|
-
"scatter_summary",
|
|
65
|
-
"scene_summary",
|
|
66
|
-
"sculpt_terrain",
|
|
67
|
-
"select",
|
|
68
|
-
"select_collection",
|
|
69
|
-
"set_catalog_entry",
|
|
70
|
-
"set_collection_flags",
|
|
71
|
-
"set_collection_members",
|
|
72
|
-
"set_marker",
|
|
73
|
-
"set_meta",
|
|
74
|
-
"set_mode",
|
|
75
|
-
"set_note",
|
|
76
|
-
"set_parent",
|
|
77
|
-
"set_path",
|
|
78
|
-
"set_runtime_override",
|
|
79
|
-
"set_terrain_layers",
|
|
80
|
-
"set_transform",
|
|
81
|
-
"set_volume",
|
|
82
|
-
"terrain_layers",
|
|
83
|
-
"terrain_materials",
|
|
84
|
-
"terrain_summary",
|
|
85
|
-
"undo",
|
|
86
|
-
"write_back_override",
|
|
87
|
-
]);
|
|
1
|
+
import { RPC_FIELD_SCHEMAS } from "./fieldSpec.js";
|
|
2
|
+
export { EDITOR_BRIDGE_METHOD_NAMES } from "./fieldSpec.js";
|
|
3
|
+
/** Every `method` an {@link EditorBridgeRequest} may carry, derived from the schema table's keys. */
|
|
4
|
+
const EDITOR_BRIDGE_METHODS = new Set(Object.keys(RPC_FIELD_SCHEMAS));
|
|
5
|
+
function isPlainObject(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function isVec3(value) {
|
|
9
|
+
return isPlainObject(value) && typeof value.x === "number" && typeof value.y === "number" && typeof value.z === "number";
|
|
10
|
+
}
|
|
11
|
+
function validateField(value, spec, errors) {
|
|
12
|
+
if (value === undefined)
|
|
13
|
+
return; // presence is enforced by handle's per-method guards, not here
|
|
14
|
+
const path = `$.${spec.name}`;
|
|
15
|
+
if (value === null) {
|
|
16
|
+
if (spec.nullable !== true)
|
|
17
|
+
errors.push({ path, message: `expected a ${spec.kind}` });
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
switch (spec.kind) {
|
|
21
|
+
case "string":
|
|
22
|
+
if (typeof value !== "string")
|
|
23
|
+
errors.push({ path, message: "expected a string" });
|
|
24
|
+
else if (spec.oneOf !== undefined && !spec.oneOf.includes(value)) {
|
|
25
|
+
errors.push({ path, message: `expected one of ${spec.oneOf.join(" | ")}` });
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
case "number":
|
|
29
|
+
if (typeof value !== "number" || Number.isNaN(value))
|
|
30
|
+
errors.push({ path, message: "expected a number" });
|
|
31
|
+
return;
|
|
32
|
+
case "boolean":
|
|
33
|
+
if (typeof value !== "boolean")
|
|
34
|
+
errors.push({ path, message: "expected a boolean" });
|
|
35
|
+
return;
|
|
36
|
+
case "string[]":
|
|
37
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
38
|
+
errors.push({ path, message: "expected an array of strings" });
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
case "object":
|
|
42
|
+
if (!isPlainObject(value))
|
|
43
|
+
errors.push({ path, message: "expected an object" });
|
|
44
|
+
return;
|
|
45
|
+
case "object[]":
|
|
46
|
+
if (!Array.isArray(value) || value.some((entry) => !isPlainObject(entry))) {
|
|
47
|
+
errors.push({ path, message: "expected an array of objects" });
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
case "vec3":
|
|
51
|
+
if (!isVec3(value))
|
|
52
|
+
errors.push({ path, message: "expected {x,y,z} numbers" });
|
|
53
|
+
return;
|
|
54
|
+
case "value":
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
88
58
|
/**
|
|
89
|
-
* Validates an untrusted JSON-decoded RPC payload (from `--rpc
|
|
90
|
-
* reaches `EditorHostApi.handle`: confirms it is a plain object carrying a known
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
59
|
+
* Validates an untrusted JSON-decoded RPC payload (from `--rpc`, the HTTP bridge, or an agent tool
|
|
60
|
+
* call) before it reaches `EditorHostApi.handle`: confirms it is a plain object carrying a known
|
|
61
|
+
* `method`, then type-checks every field the method understands against {@link RPC_FIELD_SCHEMAS}.
|
|
62
|
+
* A garbled method, or a field whose value is the wrong type (a string where a number belongs, a
|
|
63
|
+
* scalar where an object belongs), is rejected here with a path-specific diagnostic instead of
|
|
64
|
+
* flowing into a live session on a blind cast. Missing fields and unknown extra fields are left for
|
|
65
|
+
* `handle` to interpret so the boundary stays forward-compatible.
|
|
94
66
|
*/
|
|
95
67
|
export function decodeEditorBridgeRequest(raw) {
|
|
96
68
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
97
69
|
return { ok: false, errors: [{ path: "$", message: "expected an RPC request object" }] };
|
|
98
70
|
}
|
|
99
|
-
const
|
|
71
|
+
const record = raw;
|
|
72
|
+
const method = record.method;
|
|
100
73
|
if (typeof method !== "string") {
|
|
101
74
|
return { ok: false, errors: [{ path: "$.method", message: "expected a string" }] };
|
|
102
75
|
}
|
|
103
76
|
if (!EDITOR_BRIDGE_METHODS.has(method)) {
|
|
104
77
|
return { ok: false, errors: [{ path: "$.method", message: `unknown method "${method}"` }] };
|
|
105
78
|
}
|
|
79
|
+
const errors = [];
|
|
80
|
+
for (const spec of RPC_FIELD_SCHEMAS[method]) {
|
|
81
|
+
validateField(record[spec.name], spec, errors);
|
|
82
|
+
}
|
|
83
|
+
if (errors.length > 0)
|
|
84
|
+
return { ok: false, errors };
|
|
106
85
|
return { ok: true, request: raw };
|
|
107
86
|
}
|