@uemcp/server 1.2.0 → 1.3.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.
Files changed (3) hide show
  1. package/README.md +130 -0
  2. package/dist/index.mjs +3419 -651
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -2972,6 +2972,1603 @@ function createBridgeGetCreateClassStatusRequest(createClassJobId, requestId = r
2972
2972
  version: 2
2973
2973
  });
2974
2974
  }
2975
+ const BRIDGE_LIST_ASSET_FACTORIES_REQUEST_TYPE = "list_asset_factories";
2976
+ const BRIDGE_CREATE_ASSET_REQUEST_TYPE = "create_asset";
2977
+ const BRIDGE_DUPLICATE_ASSET_REQUEST_TYPE = "duplicate_asset";
2978
+ const BRIDGE_RENAME_ASSET_REQUEST_TYPE = "rename_asset";
2979
+ const BRIDGE_MOVE_ASSET_REQUEST_TYPE = "move_asset";
2980
+ const BRIDGE_DELETE_ASSET_REQUEST_TYPE = "delete_asset";
2981
+ const BRIDGE_SAVE_ASSET_REQUEST_TYPE = "save_asset";
2982
+ const BRIDGE_CREATE_FOLDER_REQUEST_TYPE = "create_folder";
2983
+ const BRIDGE_GET_ASSET_METADATA_REQUEST_TYPE = "get_asset_metadata";
2984
+ const BRIDGE_LIST_GRAPH_NODES_REQUEST_TYPE = "list_graph_nodes";
2985
+ const BRIDGE_ADD_GRAPH_NODE_REQUEST_TYPE = "add_graph_node";
2986
+ const BRIDGE_REMOVE_GRAPH_NODE_REQUEST_TYPE = "remove_graph_node";
2987
+ const BRIDGE_CONNECT_PINS_REQUEST_TYPE = "connect_pins";
2988
+ const BRIDGE_DISCONNECT_PINS_REQUEST_TYPE = "disconnect_pins";
2989
+ const BRIDGE_SET_PIN_DEFAULT_REQUEST_TYPE = "set_pin_default";
2990
+ const BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE = "list_available_nodes";
2991
+ const BRIDGE_SET_VIEWPORT_CAMERA_REQUEST_TYPE = "set_viewport_camera";
2992
+ const BRIDGE_FOCUS_ACTORS_REQUEST_TYPE = "focus_actors";
2993
+ const BRIDGE_SET_VIEW_MODE_REQUEST_TYPE = "set_view_mode";
2994
+ const BRIDGE_TOGGLE_SHOW_FLAGS_REQUEST_TYPE = "toggle_show_flags";
2995
+ const BRIDGE_HIGH_RES_SCREENSHOT_REQUEST_TYPE = "high_res_screenshot";
2996
+ const BRIDGE_DUPLICATE_ACTOR_REQUEST_TYPE = "duplicate_actor";
2997
+ const BRIDGE_ATTACH_ACTOR_REQUEST_TYPE = "attach_actor";
2998
+ const BRIDGE_ADD_ACTOR_COMPONENT_REQUEST_TYPE = "add_actor_component";
2999
+ const BRIDGE_SET_ACTOR_TAGS_REQUEST_TYPE = "set_actor_tags";
3000
+ const BRIDGE_MOVE_TO_FOLDER_REQUEST_TYPE = "move_to_folder";
3001
+ const BRIDGE_PLACE_ASSET_REQUEST_TYPE = "place_asset";
3002
+ const BRIDGE_REPLACE_ACTORS_REQUEST_TYPE = "replace_actors";
3003
+ const BRIDGE_START_EDITOR_BUILD_REQUEST_TYPE = "start_editor_build";
3004
+ const BRIDGE_GET_BUILD_JOB_STATUS_REQUEST_TYPE = "get_build_job_status";
3005
+ const BRIDGE_CREATE_GAMEPLAY_TAG_REQUEST_TYPE = "create_gameplay_tag";
3006
+ const BRIDGE_LIST_GAMEPLAY_TAGS_REQUEST_TYPE = "list_gameplay_tags";
3007
+ const BRIDGE_CREATE_LANDSCAPE_REQUEST_TYPE = "create_landscape";
3008
+ const BRIDGE_SCULPT_LANDSCAPE_REQUEST_TYPE = "sculpt_landscape";
3009
+ const BRIDGE_PAINT_LANDSCAPE_LAYER_REQUEST_TYPE = "paint_landscape_layer";
3010
+ const BRIDGE_RUN_GEOMETRY_SCRIPT_REQUEST_TYPE = "run_geometry_script";
3011
+ const BRIDGE_LIST_DATA_LAYERS_REQUEST_TYPE = "list_data_layers";
3012
+ const BRIDGE_SET_DATA_LAYER_STATE_REQUEST_TYPE = "set_data_layer_state";
3013
+ const BRIDGE_LOAD_WP_REGION_REQUEST_TYPE = "load_wp_region";
3014
+ const BRIDGE_CREATIVE_EDIT_STATES = ["applied", "unsupported"];
3015
+ const BRIDGE_FACTORY_OPTION_VALUE_MAX_CHARS = 1024;
3016
+ const BRIDGE_DELETE_ASSET_STATES = [
3017
+ "deleted",
3018
+ "blocked",
3019
+ "unsupported"
3020
+ ];
3021
+ const BRIDGE_CREATE_FOLDER_STATES = [
3022
+ "created",
3023
+ "exists",
3024
+ "unsupported"
3025
+ ];
3026
+ const BRIDGE_ASSET_METADATA_STATES = ["reported", "unsupported"];
3027
+ const BRIDGE_GRAPH_PIN_VALUE_MAX_CHARS = 4096;
3028
+ const BRIDGE_GRAPH_NODE_POSITION_LIMIT = 1e6;
3029
+ const BRIDGE_GRAPH_NODE_KINDS = [
3030
+ "class",
3031
+ "function",
3032
+ "variable_get",
3033
+ "variable_set"
3034
+ ];
3035
+ const BRIDGE_VIEWPORT_VIEW_TYPES = [
3036
+ "perspective",
3037
+ "ortho_top",
3038
+ "ortho_bottom",
3039
+ "ortho_left",
3040
+ "ortho_right",
3041
+ "ortho_front",
3042
+ "ortho_back"
3043
+ ];
3044
+ const BRIDGE_VIEW_MODES = [
3045
+ "lit",
3046
+ "unlit",
3047
+ "wireframe",
3048
+ "brush_wireframe",
3049
+ "lit_lightmap_density",
3050
+ "detail_lighting",
3051
+ "lighting_only",
3052
+ "light_complexity",
3053
+ "shader_complexity",
3054
+ "stationary_light_overlap",
3055
+ "lightmap_density",
3056
+ "reflections",
3057
+ "collision_pawn",
3058
+ "collision_visibility",
3059
+ "quad_overdraw",
3060
+ "primitive_distance_accuracy",
3061
+ "mesh_uv_density_accuracy",
3062
+ "material_texture_scale_accuracy",
3063
+ "required_texture_resolution",
3064
+ "path_tracing",
3065
+ "ray_tracing_debug",
3066
+ "visualize_buffer",
3067
+ "visualize_nanite",
3068
+ "visualize_lumen",
3069
+ "visualize_virtual_shadow_map"
3070
+ ];
3071
+ const BRIDGE_SCREENSHOT_STATES = ["requested", "unsupported"];
3072
+ const BRIDGE_ATTACHMENT_RULES = [
3073
+ "keep_relative",
3074
+ "keep_world",
3075
+ "snap_to_target"
3076
+ ];
3077
+ const BRIDGE_ACTOR_TAG_MODES = [
3078
+ "set",
3079
+ "add",
3080
+ "remove"
3081
+ ];
3082
+ const BRIDGE_EDITOR_BUILD_KINDS = [
3083
+ "lighting",
3084
+ "navigation",
3085
+ "hlod",
3086
+ "reflection_captures",
3087
+ "geometry",
3088
+ "texture_streaming",
3089
+ "virtual_textures",
3090
+ "precomputed_visibility"
3091
+ ];
3092
+ const BRIDGE_LIGHTING_QUALITIES = [
3093
+ "preview",
3094
+ "medium",
3095
+ "high",
3096
+ "production"
3097
+ ];
3098
+ const BRIDGE_HLOD_ACTIONS = [
3099
+ "build_clusters",
3100
+ "build_meshes",
3101
+ "build_all",
3102
+ "delete_clusters"
3103
+ ];
3104
+ const BRIDGE_EDITOR_BUILD_ACCEPT_STATES = [
3105
+ "accepted",
3106
+ "busy",
3107
+ "unsupported"
3108
+ ];
3109
+ const BRIDGE_EDITOR_BUILD_JOB_STATES = [
3110
+ "running",
3111
+ "succeeded",
3112
+ "failed",
3113
+ "cancelled",
3114
+ "unknown_job"
3115
+ ];
3116
+ const BRIDGE_CREATE_GAMEPLAY_TAG_STATES = [
3117
+ "created",
3118
+ "exists",
3119
+ "unsupported"
3120
+ ];
3121
+ const BRIDGE_LANDSCAPE_SCULPT_MODES = [
3122
+ "flatten",
3123
+ "ramp",
3124
+ "noise",
3125
+ "heightmap_file"
3126
+ ];
3127
+ const BRIDGE_LANDSCAPE_RAMP_AXES = ["x", "y"];
3128
+ const BRIDGE_LANDSCAPE_MAX_VERTEX_COORDINATE = 1e6;
3129
+ const BRIDGE_LANDSCAPE_MIN_HEIGHT = -1e6;
3130
+ const BRIDGE_LANDSCAPE_MAX_HEIGHT = 1e6;
3131
+ const BRIDGE_FILE_PATH_MAX_CHARS = 1024;
3132
+ const BRIDGE_GEOMETRY_OPERATIONS = [
3133
+ "append_box",
3134
+ "append_sphere",
3135
+ "append_cylinder",
3136
+ "append_cone",
3137
+ "append_torus",
3138
+ "subtract_box",
3139
+ "subtract_sphere",
3140
+ "subtract_cylinder",
3141
+ "subtract_cone",
3142
+ "subtract_torus",
3143
+ "intersect_box",
3144
+ "intersect_sphere",
3145
+ "intersect_cylinder",
3146
+ "intersect_cone",
3147
+ "intersect_torus",
3148
+ "translate",
3149
+ "rotate",
3150
+ "scale",
3151
+ "recompute_normals",
3152
+ "apply_displace_noise",
3153
+ "simplify_to_triangle_count"
3154
+ ];
3155
+ const BRIDGE_GEOMETRY_OUTPUTS = ["static_mesh", "dynamic_mesh_actor"];
3156
+ const BRIDGE_DATA_LAYER_RUNTIME_STATES = [
3157
+ "unloaded",
3158
+ "loaded",
3159
+ "activated"
3160
+ ];
3161
+ const BRIDGE_WP_REGION_ACTIONS = [
3162
+ "pin",
3163
+ "unpin",
3164
+ "unpin_all"
3165
+ ];
3166
+ const BRIDGE_WP_REGION_COORDINATE_LIMIT = 21e6;
3167
+ const creativeEditStateSchema = z.enum(BRIDGE_CREATIVE_EDIT_STATES);
3168
+ const contentPathSchema = z.string().trim().min(1).max(512).refine((value) => value.startsWith("/"), { message: "Content paths must start with '/', e.g. '/Game/Materials'." });
3169
+ const assetNameSchema = z.string().trim().min(1).max(256).refine((value) => !value.includes("/") && !value.includes("."), { message: "An asset name must be a single path segment; use a destination path to move the asset." });
3170
+ const factoryOptionsSchema = z.record(z.string().trim().min(1).max(128), z.string().max(BRIDGE_FACTORY_OPTION_VALUE_MAX_CHARS)).refine((value) => Object.keys(value).length <= 32, { message: `A create_asset request carries at most ${String(32)} factory options.` });
3171
+ const assetFactoryMaxResultsSchema = z.number().int().min(1).max(100);
3172
+ const saveAssetPathBatchSchema = z.array(assetPathSchema).min(1).max(64);
3173
+ const deleteAssetStateSchema = z.enum(BRIDGE_DELETE_ASSET_STATES);
3174
+ const createFolderStateSchema = z.enum(BRIDGE_CREATE_FOLDER_STATES);
3175
+ const assetMetadataStateSchema = z.enum(BRIDGE_ASSET_METADATA_STATES);
3176
+ const graphNameSchema = z.string().trim().min(1).max(256);
3177
+ const graphNodeGuidSchema = z.string().trim().min(1).max(64);
3178
+ const graphPinNameSchema = z.string().trim().min(1).max(256);
3179
+ const graphPinValueSchema = z.string().max(BRIDGE_GRAPH_PIN_VALUE_MAX_CHARS);
3180
+ const graphNodeKindSchema = z.enum(BRIDGE_GRAPH_NODE_KINDS);
3181
+ const graphNodeMaxResultsSchema = z.number().int().min(1).max(100);
3182
+ const availableNodeMaxResultsSchema = z.number().int().min(1).max(100);
3183
+ const graphNodePositionSchema = z.object({
3184
+ x: z.number().int().min(-1e6).max(BRIDGE_GRAPH_NODE_POSITION_LIMIT).default(0),
3185
+ y: z.number().int().min(-1e6).max(BRIDGE_GRAPH_NODE_POSITION_LIMIT).default(0)
3186
+ });
3187
+ const viewportViewTypeSchema = z.enum(BRIDGE_VIEWPORT_VIEW_TYPES);
3188
+ const viewModeSchema = z.enum(BRIDGE_VIEW_MODES);
3189
+ const viewportFovSchema = z.number().min(5).max(170);
3190
+ const screenshotStateSchema = z.enum(BRIDGE_SCREENSHOT_STATES);
3191
+ const showFlagNameSchema = z.string().trim().min(1).max(128);
3192
+ const showFlagEntrySchema = z.object({
3193
+ enabled: z.boolean(),
3194
+ name: showFlagNameSchema
3195
+ });
3196
+ const attachmentRuleSchema = z.enum(BRIDGE_ATTACHMENT_RULES);
3197
+ const actorTagModeSchema = z.enum(BRIDGE_ACTOR_TAG_MODES);
3198
+ const actorFolderSchema = z.string().trim().max(512);
3199
+ const editorBuildKindSchema = z.enum(BRIDGE_EDITOR_BUILD_KINDS);
3200
+ const lightingQualitySchema = z.enum(BRIDGE_LIGHTING_QUALITIES);
3201
+ const hlodActionSchema = z.enum(BRIDGE_HLOD_ACTIONS);
3202
+ const editorBuildAcceptStateSchema = z.enum(BRIDGE_EDITOR_BUILD_ACCEPT_STATES);
3203
+ const editorBuildJobStateSchema = z.enum(BRIDGE_EDITOR_BUILD_JOB_STATES);
3204
+ const buildJobIdSchema = z.string().trim().min(1);
3205
+ const gameplayTagNameSchema = z.string().trim().min(1).max(256).regex(/^[A-Za-z0-9_]+(\.[A-Za-z0-9_]+)*$/, { message: "A gameplay tag name is dot-separated, with each segment made of letters, digits or underscores." });
3206
+ const gameplayTagPrefixSchema = z.string().trim().min(1).max(256);
3207
+ const gameplayTagMaxResultsSchema = z.number().int().min(1).max(200);
3208
+ const createGameplayTagStateSchema = z.enum(BRIDGE_CREATE_GAMEPLAY_TAG_STATES);
3209
+ const landscapeQuadsPerSectionSchema = z.union([
3210
+ z.literal(7),
3211
+ z.literal(15),
3212
+ z.literal(31),
3213
+ z.literal(63),
3214
+ z.literal(127),
3215
+ z.literal(255)
3216
+ ]);
3217
+ const landscapeSectionsPerComponentSchema = z.union([z.literal(1), z.literal(4)]);
3218
+ const landscapeComponentCountSchema = z.number().int().min(1).max(32);
3219
+ const landscapeSculptModeSchema = z.enum(BRIDGE_LANDSCAPE_SCULPT_MODES);
3220
+ const landscapeRampAxisSchema = z.enum(BRIDGE_LANDSCAPE_RAMP_AXES);
3221
+ const landscapeCoordinateSchema = z.number().int().min(-1e6).max(BRIDGE_LANDSCAPE_MAX_VERTEX_COORDINATE);
3222
+ const landscapeHeightSchema = z.number().min(BRIDGE_LANDSCAPE_MIN_HEIGHT).max(BRIDGE_LANDSCAPE_MAX_HEIGHT);
3223
+ const landscapeWeightSchema = z.number().min(0).max(1);
3224
+ const filePathSchema = z.string().trim().min(1).max(BRIDGE_FILE_PATH_MAX_CHARS);
3225
+ const landscapeRegionSchema = z.object({
3226
+ maxX: landscapeCoordinateSchema,
3227
+ maxY: landscapeCoordinateSchema,
3228
+ minX: landscapeCoordinateSchema,
3229
+ minY: landscapeCoordinateSchema
3230
+ }).refine((value) => value.maxX >= value.minX && value.maxY >= value.minY, { message: "A landscape region must have maxX >= minX and maxY >= minY." });
3231
+ const geometryOperationKindSchema = z.enum(BRIDGE_GEOMETRY_OPERATIONS);
3232
+ const geometryOutputSchema = z.enum(BRIDGE_GEOMETRY_OUTPUTS);
3233
+ const geometryParamsSchema = z.record(z.string().trim().min(1).max(64), z.number()).refine((value) => Object.keys(value).length <= 16, { message: `A geometry operation carries at most ${String(16)} params.` });
3234
+ const geometryOperationSchema = z.object({
3235
+ kind: geometryOperationKindSchema,
3236
+ params: geometryParamsSchema.default({}),
3237
+ transform: transformInputSchema.optional()
3238
+ });
3239
+ const dataLayerRuntimeStateSchema = z.enum(BRIDGE_DATA_LAYER_RUNTIME_STATES);
3240
+ const dataLayerMaxResultsSchema = z.number().int().min(1).max(100);
3241
+ const wpRegionActionSchema = z.enum(BRIDGE_WP_REGION_ACTIONS);
3242
+ const wpRegionIdSchema = z.string().trim().min(1).max(64);
3243
+ const wpCoordinateSchema = z.number().min(-21e6).max(BRIDGE_WP_REGION_COORDINATE_LIMIT);
3244
+ const wpRegionBoxSchema = z.object({
3245
+ maxX: wpCoordinateSchema,
3246
+ maxY: wpCoordinateSchema,
3247
+ maxZ: wpCoordinateSchema,
3248
+ minX: wpCoordinateSchema,
3249
+ minY: wpCoordinateSchema,
3250
+ minZ: wpCoordinateSchema
3251
+ }).refine((value) => value.maxX >= value.minX && value.maxY >= value.minY && value.maxZ >= value.minZ, { message: "A World Partition region must have every max component >= its min component." });
3252
+ const bridgeListAssetFactoriesRequestSchema = z.object({
3253
+ cursor: assetCursorSchema.optional(),
3254
+ maxResults: assetFactoryMaxResultsSchema.optional(),
3255
+ nameFilter: boundedStringSchema.optional(),
3256
+ requestId: requestIdSchema,
3257
+ type: z.literal(BRIDGE_LIST_ASSET_FACTORIES_REQUEST_TYPE),
3258
+ version: z.literal(2)
3259
+ });
3260
+ const bridgeCreateAssetRequestSchema = z.object({
3261
+ assetClass: assetPathSchema,
3262
+ assetName: assetNameSchema,
3263
+ factoryClass: assetPathSchema.optional(),
3264
+ options: factoryOptionsSchema.optional(),
3265
+ packagePath: contentPathSchema,
3266
+ requestId: requestIdSchema,
3267
+ type: z.literal(BRIDGE_CREATE_ASSET_REQUEST_TYPE),
3268
+ version: z.literal(2)
3269
+ });
3270
+ const bridgeDuplicateAssetRequestSchema = z.object({
3271
+ destinationName: assetNameSchema,
3272
+ destinationPath: contentPathSchema,
3273
+ requestId: requestIdSchema,
3274
+ sourceAssetPath: assetPathSchema,
3275
+ type: z.literal(BRIDGE_DUPLICATE_ASSET_REQUEST_TYPE),
3276
+ version: z.literal(2)
3277
+ });
3278
+ const bridgeRenameAssetRequestSchema = z.object({
3279
+ assetPath: assetPathSchema,
3280
+ newName: assetNameSchema,
3281
+ requestId: requestIdSchema,
3282
+ type: z.literal(BRIDGE_RENAME_ASSET_REQUEST_TYPE),
3283
+ version: z.literal(2)
3284
+ });
3285
+ const bridgeMoveAssetRequestSchema = z.object({
3286
+ assetPath: assetPathSchema,
3287
+ destinationPath: contentPathSchema,
3288
+ newName: assetNameSchema.optional(),
3289
+ requestId: requestIdSchema,
3290
+ type: z.literal(BRIDGE_MOVE_ASSET_REQUEST_TYPE),
3291
+ version: z.literal(2)
3292
+ });
3293
+ const bridgeDeleteAssetRequestSchema = z.object({
3294
+ assetPath: assetPathSchema,
3295
+ force: z.boolean().optional(),
3296
+ requestId: requestIdSchema,
3297
+ type: z.literal(BRIDGE_DELETE_ASSET_REQUEST_TYPE),
3298
+ version: z.literal(2)
3299
+ });
3300
+ const bridgeSaveAssetRequestSchema = z.object({
3301
+ assetPaths: saveAssetPathBatchSchema,
3302
+ requestId: requestIdSchema,
3303
+ type: z.literal(BRIDGE_SAVE_ASSET_REQUEST_TYPE),
3304
+ version: z.literal(2)
3305
+ });
3306
+ const bridgeCreateFolderRequestSchema = z.object({
3307
+ folderPath: contentPathSchema,
3308
+ requestId: requestIdSchema,
3309
+ type: z.literal(BRIDGE_CREATE_FOLDER_REQUEST_TYPE),
3310
+ version: z.literal(2)
3311
+ });
3312
+ const bridgeGetAssetMetadataRequestSchema = z.object({
3313
+ assetPath: assetPathSchema,
3314
+ requestId: requestIdSchema,
3315
+ type: z.literal(BRIDGE_GET_ASSET_METADATA_REQUEST_TYPE),
3316
+ version: z.literal(2)
3317
+ });
3318
+ const bridgeListGraphNodesRequestSchema = z.object({
3319
+ assetPath: assetPathSchema,
3320
+ cursor: assetCursorSchema.optional(),
3321
+ graphName: graphNameSchema,
3322
+ loadIfNeeded: z.boolean().optional(),
3323
+ maxResults: graphNodeMaxResultsSchema.optional(),
3324
+ requestId: requestIdSchema,
3325
+ type: z.literal(BRIDGE_LIST_GRAPH_NODES_REQUEST_TYPE),
3326
+ version: z.literal(2)
3327
+ });
3328
+ const bridgeAddGraphNodeRequestFieldsSchema = z.object({
3329
+ assetPath: assetPathSchema,
3330
+ graphName: graphNameSchema,
3331
+ nodeClass: assetPathSchema.optional(),
3332
+ kind: graphNodeKindSchema,
3333
+ memberName: boundedStringSchema.optional(),
3334
+ memberParentClass: assetPathSchema.optional(),
3335
+ pinDefaults: z.record(graphPinNameSchema, graphPinValueSchema).refine((value) => Object.keys(value).length <= 64, { message: `An add_graph_node request carries at most ${String(64)} pin defaults.` }).optional(),
3336
+ position: graphNodePositionSchema.optional(),
3337
+ requestId: requestIdSchema,
3338
+ type: z.literal(BRIDGE_ADD_GRAPH_NODE_REQUEST_TYPE),
3339
+ version: z.literal(2)
3340
+ });
3341
+ const bridgeAddGraphNodeRequestSchema = bridgeAddGraphNodeRequestFieldsSchema.refine((value) => value.kind === "class" ? value.nodeClass !== void 0 : value.memberName !== void 0, {
3342
+ message: "kind 'class' requires nodeClass; every other kind requires memberName.",
3343
+ path: ["nodeClass"]
3344
+ });
3345
+ const bridgeRemoveGraphNodeRequestSchema = z.object({
3346
+ assetPath: assetPathSchema,
3347
+ graphName: graphNameSchema,
3348
+ nodeGuid: graphNodeGuidSchema,
3349
+ requestId: requestIdSchema,
3350
+ type: z.literal(BRIDGE_REMOVE_GRAPH_NODE_REQUEST_TYPE),
3351
+ version: z.literal(2)
3352
+ });
3353
+ const graphPinPairFields = {
3354
+ assetPath: assetPathSchema,
3355
+ graphName: graphNameSchema,
3356
+ requestId: requestIdSchema,
3357
+ sourceNodeGuid: graphNodeGuidSchema,
3358
+ sourcePinName: graphPinNameSchema,
3359
+ targetNodeGuid: graphNodeGuidSchema,
3360
+ targetPinName: graphPinNameSchema,
3361
+ version: z.literal(2)
3362
+ };
3363
+ const bridgeConnectPinsRequestSchema = z.object({
3364
+ ...graphPinPairFields,
3365
+ type: z.literal(BRIDGE_CONNECT_PINS_REQUEST_TYPE)
3366
+ });
3367
+ const bridgeDisconnectPinsRequestSchema = z.object({
3368
+ ...graphPinPairFields,
3369
+ type: z.literal(BRIDGE_DISCONNECT_PINS_REQUEST_TYPE)
3370
+ });
3371
+ const bridgeSetPinDefaultRequestSchema = z.object({
3372
+ assetPath: assetPathSchema,
3373
+ graphName: graphNameSchema,
3374
+ nodeGuid: graphNodeGuidSchema,
3375
+ pinName: graphPinNameSchema,
3376
+ requestId: requestIdSchema,
3377
+ type: z.literal(BRIDGE_SET_PIN_DEFAULT_REQUEST_TYPE),
3378
+ value: graphPinValueSchema,
3379
+ version: z.literal(2)
3380
+ });
3381
+ const bridgeListAvailableNodesRequestSchema = z.object({
3382
+ assetPath: assetPathSchema,
3383
+ cursor: assetCursorSchema.optional(),
3384
+ graphName: graphNameSchema,
3385
+ maxResults: availableNodeMaxResultsSchema.optional(),
3386
+ nameFilter: boundedStringSchema.optional(),
3387
+ requestId: requestIdSchema,
3388
+ type: z.literal(BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE),
3389
+ version: z.literal(2)
3390
+ });
3391
+ const bridgeSetViewportCameraRequestSchema = z.object({
3392
+ fov: viewportFovSchema.optional(),
3393
+ location: vectorInputSchema.optional(),
3394
+ orthoWidth: z.number().min(1).optional(),
3395
+ requestId: requestIdSchema,
3396
+ rotation: rotatorInputSchema.optional(),
3397
+ type: z.literal(BRIDGE_SET_VIEWPORT_CAMERA_REQUEST_TYPE),
3398
+ version: z.literal(2),
3399
+ viewType: viewportViewTypeSchema.optional()
3400
+ });
3401
+ const bridgeFocusActorsRequestSchema = z.object({
3402
+ actorPaths: actorPathBatchSchema,
3403
+ instant: z.boolean().optional(),
3404
+ requestId: requestIdSchema,
3405
+ type: z.literal(BRIDGE_FOCUS_ACTORS_REQUEST_TYPE),
3406
+ version: z.literal(2)
3407
+ });
3408
+ const bridgeSetViewModeRequestSchema = z.object({
3409
+ requestId: requestIdSchema,
3410
+ type: z.literal(BRIDGE_SET_VIEW_MODE_REQUEST_TYPE),
3411
+ version: z.literal(2),
3412
+ viewMode: viewModeSchema
3413
+ });
3414
+ const bridgeToggleShowFlagsRequestSchema = z.object({
3415
+ flags: z.array(showFlagEntrySchema).min(1).max(32),
3416
+ requestId: requestIdSchema,
3417
+ type: z.literal(BRIDGE_TOGGLE_SHOW_FLAGS_REQUEST_TYPE),
3418
+ version: z.literal(2)
3419
+ });
3420
+ const bridgeHighResScreenshotRequestSchema = z.object({
3421
+ fileName: z.string().trim().min(1).max(128).refine((value) => !/[/\\:]/.test(value) && !value.includes(".."), { message: "Screenshot names may not contain '/', '\\', ':' or '..'." }).optional(),
3422
+ includeUi: z.boolean().optional(),
3423
+ multiplier: z.number().min(1).max(8).optional(),
3424
+ requestId: requestIdSchema,
3425
+ type: z.literal(BRIDGE_HIGH_RES_SCREENSHOT_REQUEST_TYPE),
3426
+ version: z.literal(2)
3427
+ });
3428
+ const bridgeDuplicateActorEntrySchema = z.object({
3429
+ actorPath: actorPathSchema,
3430
+ offset: vectorInputSchema.optional()
3431
+ });
3432
+ const bridgeDuplicateActorRequestSchema = z.object({
3433
+ actors: z.array(bridgeDuplicateActorEntrySchema).min(1).max(64),
3434
+ dryRun: z.boolean().optional(),
3435
+ requestId: requestIdSchema,
3436
+ type: z.literal(BRIDGE_DUPLICATE_ACTOR_REQUEST_TYPE),
3437
+ version: z.literal(2)
3438
+ });
3439
+ const bridgeAttachActorEntrySchema = z.object({
3440
+ childActorPath: actorPathSchema,
3441
+ locationRule: attachmentRuleSchema.optional(),
3442
+ parentActorPath: z.string().trim().max(512),
3443
+ rotationRule: attachmentRuleSchema.optional(),
3444
+ scaleRule: attachmentRuleSchema.optional(),
3445
+ socketName: boundedStringSchema.optional(),
3446
+ weldSimulatedBodies: z.boolean().optional()
3447
+ });
3448
+ const bridgeAttachActorRequestSchema = z.object({
3449
+ attachments: z.array(bridgeAttachActorEntrySchema).min(1).max(64),
3450
+ dryRun: z.boolean().optional(),
3451
+ requestId: requestIdSchema,
3452
+ type: z.literal(BRIDGE_ATTACH_ACTOR_REQUEST_TYPE),
3453
+ version: z.literal(2)
3454
+ });
3455
+ const bridgeAddActorComponentEntrySchema = z.object({
3456
+ actorPath: actorPathSchema,
3457
+ attachParent: boundedStringSchema.optional(),
3458
+ componentClass: assetPathSchema,
3459
+ componentName: boundedStringSchema.optional()
3460
+ });
3461
+ const bridgeAddActorComponentRequestSchema = z.object({
3462
+ components: z.array(bridgeAddActorComponentEntrySchema).min(1).max(64),
3463
+ dryRun: z.boolean().optional(),
3464
+ requestId: requestIdSchema,
3465
+ type: z.literal(BRIDGE_ADD_ACTOR_COMPONENT_REQUEST_TYPE),
3466
+ version: z.literal(2)
3467
+ });
3468
+ const bridgeSetActorTagsEntrySchema = z.object({
3469
+ actorPath: actorPathSchema,
3470
+ mode: actorTagModeSchema,
3471
+ tags: actorTagArraySchema
3472
+ });
3473
+ const bridgeSetActorTagsRequestSchema = z.object({
3474
+ dryRun: z.boolean().optional(),
3475
+ entries: z.array(bridgeSetActorTagsEntrySchema).min(1).max(64),
3476
+ requestId: requestIdSchema,
3477
+ type: z.literal(BRIDGE_SET_ACTOR_TAGS_REQUEST_TYPE),
3478
+ version: z.literal(2)
3479
+ });
3480
+ const bridgeMoveToFolderEntrySchema = z.object({
3481
+ actorPath: actorPathSchema,
3482
+ folderPath: actorFolderSchema
3483
+ });
3484
+ const bridgeMoveToFolderRequestSchema = z.object({
3485
+ dryRun: z.boolean().optional(),
3486
+ entries: z.array(bridgeMoveToFolderEntrySchema).min(1).max(64),
3487
+ requestId: requestIdSchema,
3488
+ type: z.literal(BRIDGE_MOVE_TO_FOLDER_REQUEST_TYPE),
3489
+ version: z.literal(2)
3490
+ });
3491
+ const bridgePlaceAssetEntrySchema = z.object({
3492
+ assetPath: assetPathSchema,
3493
+ folderPath: actorFolderSchema.optional(),
3494
+ label: boundedStringSchema.optional(),
3495
+ transform: transformInputSchema.optional()
3496
+ });
3497
+ const bridgePlaceAssetRequestSchema = z.object({
3498
+ dryRun: z.boolean().optional(),
3499
+ placements: z.array(bridgePlaceAssetEntrySchema).min(1).max(64),
3500
+ requestId: requestIdSchema,
3501
+ type: z.literal(BRIDGE_PLACE_ASSET_REQUEST_TYPE),
3502
+ version: z.literal(2)
3503
+ });
3504
+ const bridgeReplaceActorsRequestFieldsSchema = z.object({
3505
+ actorPaths: actorPathBatchSchema,
3506
+ dryRun: z.boolean().optional(),
3507
+ replacementAssetPath: assetPathSchema.optional(),
3508
+ replacementClass: assetPathSchema.optional(),
3509
+ requestId: requestIdSchema,
3510
+ type: z.literal(BRIDGE_REPLACE_ACTORS_REQUEST_TYPE),
3511
+ version: z.literal(2)
3512
+ });
3513
+ const bridgeReplaceActorsRequestSchema = bridgeReplaceActorsRequestFieldsSchema.refine((value) => value.replacementAssetPath === void 0 !== (value.replacementClass === void 0), {
3514
+ message: "A replace_actors request needs exactly one of replacementAssetPath or replacementClass.",
3515
+ path: ["replacementAssetPath"]
3516
+ });
3517
+ const bridgeStartEditorBuildRequestSchema = z.object({
3518
+ buildKind: editorBuildKindSchema,
3519
+ hlodAction: hlodActionSchema.optional(),
3520
+ quality: lightingQualitySchema.optional(),
3521
+ requestId: requestIdSchema,
3522
+ type: z.literal(BRIDGE_START_EDITOR_BUILD_REQUEST_TYPE),
3523
+ version: z.literal(2)
3524
+ });
3525
+ const bridgeGetBuildJobStatusRequestSchema = z.object({
3526
+ buildJobId: buildJobIdSchema,
3527
+ requestId: requestIdSchema,
3528
+ type: z.literal(BRIDGE_GET_BUILD_JOB_STATUS_REQUEST_TYPE),
3529
+ version: z.literal(2)
3530
+ });
3531
+ const bridgeCreateGameplayTagRequestSchema = z.object({
3532
+ comment: z.string().trim().max(512).optional(),
3533
+ requestId: requestIdSchema,
3534
+ source: z.string().trim().min(1).max(128).optional(),
3535
+ tagName: gameplayTagNameSchema,
3536
+ type: z.literal(BRIDGE_CREATE_GAMEPLAY_TAG_REQUEST_TYPE),
3537
+ version: z.literal(2)
3538
+ });
3539
+ const bridgeListGameplayTagsRequestSchema = z.object({
3540
+ cursor: assetCursorSchema.optional(),
3541
+ maxResults: gameplayTagMaxResultsSchema.optional(),
3542
+ prefix: gameplayTagPrefixSchema.optional(),
3543
+ requestId: requestIdSchema,
3544
+ type: z.literal(BRIDGE_LIST_GAMEPLAY_TAGS_REQUEST_TYPE),
3545
+ version: z.literal(2)
3546
+ });
3547
+ const bridgeCreateLandscapeRequestSchema = z.object({
3548
+ componentCountX: landscapeComponentCountSchema,
3549
+ componentCountY: landscapeComponentCountSchema,
3550
+ heightmapFilePath: filePathSchema.optional(),
3551
+ label: boundedStringSchema.optional(),
3552
+ location: vectorInputSchema.optional(),
3553
+ quadsPerSection: landscapeQuadsPerSectionSchema,
3554
+ requestId: requestIdSchema,
3555
+ rotation: rotatorInputSchema.optional(),
3556
+ scale: vectorInputSchema.optional(),
3557
+ sectionsPerComponent: landscapeSectionsPerComponentSchema,
3558
+ type: z.literal(BRIDGE_CREATE_LANDSCAPE_REQUEST_TYPE),
3559
+ version: z.literal(2)
3560
+ });
3561
+ const bridgeSculptLandscapeRequestFieldsSchema = z.object({
3562
+ actorPath: actorPathSchema,
3563
+ height: landscapeHeightSchema.optional(),
3564
+ heightmapFilePath: filePathSchema.optional(),
3565
+ mode: landscapeSculptModeSchema,
3566
+ noiseAmplitude: landscapeHeightSchema.optional(),
3567
+ noiseFrequency: z.number().min(0).max(1).optional(),
3568
+ noiseSeed: z.number().int().min(0).optional(),
3569
+ rampAxis: landscapeRampAxisSchema.optional(),
3570
+ rampEndHeight: landscapeHeightSchema.optional(),
3571
+ rampStartHeight: landscapeHeightSchema.optional(),
3572
+ region: landscapeRegionSchema,
3573
+ requestId: requestIdSchema,
3574
+ type: z.literal(BRIDGE_SCULPT_LANDSCAPE_REQUEST_TYPE),
3575
+ version: z.literal(2)
3576
+ });
3577
+ const bridgeSculptLandscapeRequestSchema = bridgeSculptLandscapeRequestFieldsSchema.superRefine((value, ctx) => {
3578
+ if (value.mode === "flatten" && value.height === void 0) ctx.addIssue({
3579
+ code: z.ZodIssueCode.custom,
3580
+ message: "mode 'flatten' requires height.",
3581
+ path: ["height"]
3582
+ });
3583
+ if (value.mode === "heightmap_file" && value.heightmapFilePath === void 0) ctx.addIssue({
3584
+ code: z.ZodIssueCode.custom,
3585
+ message: "mode 'heightmap_file' requires heightmapFilePath.",
3586
+ path: ["heightmapFilePath"]
3587
+ });
3588
+ if (value.mode === "ramp" && (value.rampStartHeight === void 0 || value.rampEndHeight === void 0)) ctx.addIssue({
3589
+ code: z.ZodIssueCode.custom,
3590
+ message: "mode 'ramp' requires rampStartHeight and rampEndHeight.",
3591
+ path: ["rampStartHeight"]
3592
+ });
3593
+ if (value.mode === "noise" && value.noiseAmplitude === void 0) ctx.addIssue({
3594
+ code: z.ZodIssueCode.custom,
3595
+ message: "mode 'noise' requires noiseAmplitude.",
3596
+ path: ["noiseAmplitude"]
3597
+ });
3598
+ });
3599
+ const bridgePaintLandscapeLayerRequestSchema = z.object({
3600
+ actorPath: actorPathSchema,
3601
+ layerName: boundedStringSchema,
3602
+ region: landscapeRegionSchema,
3603
+ requestId: requestIdSchema,
3604
+ type: z.literal(BRIDGE_PAINT_LANDSCAPE_LAYER_REQUEST_TYPE),
3605
+ version: z.literal(2),
3606
+ weight: landscapeWeightSchema
3607
+ });
3608
+ const bridgeRunGeometryScriptRequestFieldsSchema = z.object({
3609
+ actorTransform: transformInputSchema.optional(),
3610
+ assetName: assetNameSchema.optional(),
3611
+ assetPath: contentPathSchema.optional(),
3612
+ label: boundedStringSchema.optional(),
3613
+ operations: z.array(geometryOperationSchema).min(1).max(32),
3614
+ output: geometryOutputSchema,
3615
+ requestId: requestIdSchema,
3616
+ type: z.literal(BRIDGE_RUN_GEOMETRY_SCRIPT_REQUEST_TYPE),
3617
+ version: z.literal(2)
3618
+ });
3619
+ const bridgeRunGeometryScriptRequestSchema = bridgeRunGeometryScriptRequestFieldsSchema.refine((value) => value.output !== "static_mesh" || value.assetName !== void 0 && value.assetPath !== void 0, {
3620
+ message: "output 'static_mesh' requires assetName and assetPath.",
3621
+ path: ["assetName"]
3622
+ });
3623
+ const bridgeListDataLayersRequestSchema = z.object({
3624
+ cursor: assetCursorSchema.optional(),
3625
+ maxResults: dataLayerMaxResultsSchema.optional(),
3626
+ requestId: requestIdSchema,
3627
+ type: z.literal(BRIDGE_LIST_DATA_LAYERS_REQUEST_TYPE),
3628
+ version: z.literal(2)
3629
+ });
3630
+ const bridgeSetDataLayerStateEntrySchema = z.object({
3631
+ dataLayerAsset: assetPathSchema,
3632
+ loadedInEditor: z.boolean().optional(),
3633
+ runtimeState: dataLayerRuntimeStateSchema.optional(),
3634
+ visible: z.boolean().optional()
3635
+ });
3636
+ const bridgeSetDataLayerStateRequestSchema = z.object({
3637
+ entries: z.array(bridgeSetDataLayerStateEntrySchema).min(1).max(32),
3638
+ requestId: requestIdSchema,
3639
+ type: z.literal(BRIDGE_SET_DATA_LAYER_STATE_REQUEST_TYPE),
3640
+ version: z.literal(2)
3641
+ });
3642
+ const bridgeLoadWpRegionRequestFieldsSchema = z.object({
3643
+ action: wpRegionActionSchema,
3644
+ region: wpRegionBoxSchema.optional(),
3645
+ regionId: wpRegionIdSchema.optional(),
3646
+ requestId: requestIdSchema,
3647
+ type: z.literal(BRIDGE_LOAD_WP_REGION_REQUEST_TYPE),
3648
+ version: z.literal(2)
3649
+ });
3650
+ const bridgeLoadWpRegionRequestSchema = bridgeLoadWpRegionRequestFieldsSchema.superRefine((value, ctx) => {
3651
+ if (value.action === "pin" && value.region === void 0) ctx.addIssue({
3652
+ code: z.ZodIssueCode.custom,
3653
+ message: "action 'pin' requires region.",
3654
+ path: ["region"]
3655
+ });
3656
+ if (value.action === "unpin" && value.regionId === void 0) ctx.addIssue({
3657
+ code: z.ZodIssueCode.custom,
3658
+ message: "action 'unpin' requires regionId.",
3659
+ path: ["regionId"]
3660
+ });
3661
+ });
3662
+ const bridgeAssetFactorySchema = z.object({
3663
+ assetClass: z.string(),
3664
+ assetClassPath: z.string(),
3665
+ description: z.string().optional(),
3666
+ factoryClass: z.string(),
3667
+ menuCategory: z.string(),
3668
+ requiredOptions: z.array(z.string()).max(32)
3669
+ });
3670
+ const bridgeListAssetFactoriesSuccessResponseSchema = z.object({
3671
+ factories: z.array(bridgeAssetFactorySchema).max(100),
3672
+ nextCursor: assetCursorSchema.optional(),
3673
+ ok: z.literal(true),
3674
+ requestId: requestIdSchema,
3675
+ totalCount: z.number().int().min(0),
3676
+ truncated: z.boolean(),
3677
+ type: z.literal(BRIDGE_LIST_ASSET_FACTORIES_REQUEST_TYPE),
3678
+ version: z.literal(2)
3679
+ });
3680
+ const createdAssetResponseFields = {
3681
+ message: nonEmptyStringSchema.optional(),
3682
+ objectPath: z.string(),
3683
+ ok: z.literal(true),
3684
+ packageName: z.string(),
3685
+ requestId: requestIdSchema,
3686
+ state: creativeEditStateSchema,
3687
+ version: z.literal(2)
3688
+ };
3689
+ const bridgeCreateAssetSuccessResponseSchema = z.object({
3690
+ ...createdAssetResponseFields,
3691
+ factoryClass: z.string(),
3692
+ type: z.literal(BRIDGE_CREATE_ASSET_REQUEST_TYPE)
3693
+ });
3694
+ const bridgeDuplicateAssetSuccessResponseSchema = z.object({
3695
+ ...createdAssetResponseFields,
3696
+ type: z.literal(BRIDGE_DUPLICATE_ASSET_REQUEST_TYPE)
3697
+ });
3698
+ const relocatedAssetResponseFields = {
3699
+ message: nonEmptyStringSchema.optional(),
3700
+ objectPath: z.string(),
3701
+ ok: z.literal(true),
3702
+ packageName: z.string(),
3703
+ previousObjectPath: z.string(),
3704
+ requestId: requestIdSchema,
3705
+ state: creativeEditStateSchema,
3706
+ version: z.literal(2)
3707
+ };
3708
+ const bridgeRenameAssetSuccessResponseSchema = z.object({
3709
+ ...relocatedAssetResponseFields,
3710
+ type: z.literal(BRIDGE_RENAME_ASSET_REQUEST_TYPE)
3711
+ });
3712
+ const bridgeMoveAssetSuccessResponseSchema = z.object({
3713
+ ...relocatedAssetResponseFields,
3714
+ type: z.literal(BRIDGE_MOVE_ASSET_REQUEST_TYPE)
3715
+ });
3716
+ const bridgeDeleteAssetSuccessResponseSchema = z.object({
3717
+ assetPath: z.string(),
3718
+ deleted: z.boolean(),
3719
+ message: nonEmptyStringSchema.optional(),
3720
+ ok: z.literal(true),
3721
+ referencerCount: z.number().int().min(0),
3722
+ referencers: z.array(z.string()).max(25),
3723
+ requestId: requestIdSchema,
3724
+ state: deleteAssetStateSchema,
3725
+ type: z.literal(BRIDGE_DELETE_ASSET_REQUEST_TYPE),
3726
+ version: z.literal(2)
3727
+ }).refine((value) => value.state !== "blocked" || value.referencerCount > 0, {
3728
+ message: "A 'blocked' delete_asset response must report at least one referencer.",
3729
+ path: ["referencerCount"]
3730
+ }).refine((value) => value.deleted === (value.state === "deleted"), {
3731
+ message: "delete_asset must report deleted true exactly when state is 'deleted'.",
3732
+ path: ["deleted"]
3733
+ });
3734
+ const bridgeSaveAssetItemResultSchema = z.object({
3735
+ assetPath: z.string(),
3736
+ error: z.string().optional(),
3737
+ index: z.number().int().min(0),
3738
+ ok: z.boolean(),
3739
+ saved: z.boolean()
3740
+ });
3741
+ const bridgeSaveAssetSuccessResponseSchema = z.object({
3742
+ failureCount: z.number().int().min(0),
3743
+ message: nonEmptyStringSchema.optional(),
3744
+ ok: z.literal(true),
3745
+ requestId: requestIdSchema,
3746
+ results: z.array(bridgeSaveAssetItemResultSchema).max(64),
3747
+ state: creativeEditStateSchema,
3748
+ successCount: z.number().int().min(0),
3749
+ type: z.literal(BRIDGE_SAVE_ASSET_REQUEST_TYPE),
3750
+ version: z.literal(2)
3751
+ });
3752
+ const bridgeCreateFolderSuccessResponseSchema = z.object({
3753
+ folderPath: z.string(),
3754
+ message: nonEmptyStringSchema.optional(),
3755
+ ok: z.literal(true),
3756
+ requestId: requestIdSchema,
3757
+ state: createFolderStateSchema,
3758
+ type: z.literal(BRIDGE_CREATE_FOLDER_REQUEST_TYPE),
3759
+ version: z.literal(2)
3760
+ });
3761
+ const bridgeAssetMetadataTagSchema = z.object({
3762
+ key: z.string(),
3763
+ value: z.string()
3764
+ });
3765
+ const bridgeGetAssetMetadataSuccessResponseSchema = z.object({
3766
+ assetName: z.string(),
3767
+ className: z.string(),
3768
+ classPath: z.string(),
3769
+ diskSizeBytes: z.number().int().min(0).optional(),
3770
+ loaded: z.boolean(),
3771
+ message: nonEmptyStringSchema.optional(),
3772
+ objectPath: z.string(),
3773
+ ok: z.literal(true),
3774
+ packageName: z.string(),
3775
+ packagePath: z.string(),
3776
+ requestId: requestIdSchema,
3777
+ state: assetMetadataStateSchema,
3778
+ tagCount: z.number().int().min(0),
3779
+ tags: z.array(bridgeAssetMetadataTagSchema).max(100),
3780
+ type: z.literal(BRIDGE_GET_ASSET_METADATA_REQUEST_TYPE),
3781
+ version: z.literal(2)
3782
+ });
3783
+ const bridgeListGraphNodesSuccessResponseSchema = z.object({
3784
+ assetPath: z.string(),
3785
+ graphName: z.string(),
3786
+ nextCursor: assetCursorSchema.optional(),
3787
+ nodeCount: z.number().int().min(0),
3788
+ nodes: z.array(bridgeBlueprintNodeSchema).max(100),
3789
+ ok: z.literal(true),
3790
+ requestId: requestIdSchema,
3791
+ truncated: z.boolean(),
3792
+ type: z.literal(BRIDGE_LIST_GRAPH_NODES_REQUEST_TYPE),
3793
+ version: z.literal(2)
3794
+ });
3795
+ const bridgeAddGraphNodeSuccessResponseSchema = z.object({
3796
+ assetPath: z.string(),
3797
+ graphName: z.string(),
3798
+ message: nonEmptyStringSchema.optional(),
3799
+ node: bridgeBlueprintNodeSchema,
3800
+ ok: z.literal(true),
3801
+ requestId: requestIdSchema,
3802
+ state: creativeEditStateSchema,
3803
+ type: z.literal(BRIDGE_ADD_GRAPH_NODE_REQUEST_TYPE),
3804
+ version: z.literal(2)
3805
+ });
3806
+ const bridgeRemoveGraphNodeSuccessResponseSchema = z.object({
3807
+ assetPath: z.string(),
3808
+ graphName: z.string(),
3809
+ message: nonEmptyStringSchema.optional(),
3810
+ nodeGuid: z.string(),
3811
+ ok: z.literal(true),
3812
+ removed: z.boolean(),
3813
+ requestId: requestIdSchema,
3814
+ state: creativeEditStateSchema,
3815
+ type: z.literal(BRIDGE_REMOVE_GRAPH_NODE_REQUEST_TYPE),
3816
+ version: z.literal(2)
3817
+ });
3818
+ const graphPinPairResponseFields = {
3819
+ assetPath: z.string(),
3820
+ graphName: z.string(),
3821
+ message: nonEmptyStringSchema.optional(),
3822
+ ok: z.literal(true),
3823
+ requestId: requestIdSchema,
3824
+ sourceNodeGuid: z.string(),
3825
+ sourcePinName: z.string(),
3826
+ state: creativeEditStateSchema,
3827
+ targetNodeGuid: z.string(),
3828
+ targetPinName: z.string(),
3829
+ version: z.literal(2)
3830
+ };
3831
+ const bridgeConnectPinsSuccessResponseSchema = z.object({
3832
+ ...graphPinPairResponseFields,
3833
+ connected: z.boolean(),
3834
+ type: z.literal(BRIDGE_CONNECT_PINS_REQUEST_TYPE)
3835
+ });
3836
+ const bridgeDisconnectPinsSuccessResponseSchema = z.object({
3837
+ ...graphPinPairResponseFields,
3838
+ disconnected: z.boolean(),
3839
+ type: z.literal(BRIDGE_DISCONNECT_PINS_REQUEST_TYPE)
3840
+ });
3841
+ const bridgeSetPinDefaultSuccessResponseSchema = z.object({
3842
+ assetPath: z.string(),
3843
+ graphName: z.string(),
3844
+ message: nonEmptyStringSchema.optional(),
3845
+ nodeGuid: z.string(),
3846
+ ok: z.literal(true),
3847
+ pinName: z.string(),
3848
+ requestId: requestIdSchema,
3849
+ state: creativeEditStateSchema,
3850
+ type: z.literal(BRIDGE_SET_PIN_DEFAULT_REQUEST_TYPE),
3851
+ value: z.string(),
3852
+ version: z.literal(2)
3853
+ });
3854
+ const bridgeGraphActionSchema = z.object({
3855
+ category: z.string(),
3856
+ keywords: z.string().optional(),
3857
+ memberName: z.string().optional(),
3858
+ memberParentClass: z.string().optional(),
3859
+ nodeClass: z.string(),
3860
+ nodeKind: graphNodeKindSchema,
3861
+ title: z.string(),
3862
+ tooltip: z.string().optional()
3863
+ });
3864
+ const bridgeListAvailableNodesSuccessResponseSchema = z.object({
3865
+ actions: z.array(bridgeGraphActionSchema).max(100),
3866
+ assetPath: z.string(),
3867
+ graphName: z.string(),
3868
+ nextCursor: assetCursorSchema.optional(),
3869
+ ok: z.literal(true),
3870
+ requestId: requestIdSchema,
3871
+ totalCount: z.number().int().min(0),
3872
+ truncated: z.boolean(),
3873
+ type: z.literal(BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE),
3874
+ version: z.literal(2)
3875
+ });
3876
+ const bridgeSetViewportCameraSuccessResponseSchema = z.object({
3877
+ fov: z.number(),
3878
+ location: bridgeVectorSchema,
3879
+ message: nonEmptyStringSchema.optional(),
3880
+ ok: z.literal(true),
3881
+ orthoWidth: z.number().optional(),
3882
+ requestId: requestIdSchema,
3883
+ rotation: bridgeRotatorSchema,
3884
+ state: creativeEditStateSchema,
3885
+ type: z.literal(BRIDGE_SET_VIEWPORT_CAMERA_REQUEST_TYPE),
3886
+ version: z.literal(2),
3887
+ viewType: viewportViewTypeSchema
3888
+ });
3889
+ const bridgeFocusActorsSuccessResponseSchema = z.object({
3890
+ focusedCount: z.number().int().min(0),
3891
+ location: bridgeVectorSchema,
3892
+ message: nonEmptyStringSchema.optional(),
3893
+ ok: z.literal(true),
3894
+ requestId: requestIdSchema,
3895
+ rotation: bridgeRotatorSchema,
3896
+ state: creativeEditStateSchema,
3897
+ type: z.literal(BRIDGE_FOCUS_ACTORS_REQUEST_TYPE),
3898
+ version: z.literal(2)
3899
+ });
3900
+ const bridgeSetViewModeSuccessResponseSchema = z.object({
3901
+ message: nonEmptyStringSchema.optional(),
3902
+ ok: z.literal(true),
3903
+ requestId: requestIdSchema,
3904
+ state: creativeEditStateSchema,
3905
+ type: z.literal(BRIDGE_SET_VIEW_MODE_REQUEST_TYPE),
3906
+ version: z.literal(2),
3907
+ viewMode: viewModeSchema
3908
+ });
3909
+ const bridgeShowFlagResultSchema = z.object({
3910
+ enabled: z.boolean().optional(),
3911
+ error: z.string().optional(),
3912
+ index: z.number().int().min(0),
3913
+ name: z.string(),
3914
+ ok: z.boolean(),
3915
+ suggestions: z.array(z.string()).max(5)
3916
+ });
3917
+ const bridgeToggleShowFlagsSuccessResponseSchema = z.object({
3918
+ failureCount: z.number().int().min(0),
3919
+ message: nonEmptyStringSchema.optional(),
3920
+ ok: z.literal(true),
3921
+ requestId: requestIdSchema,
3922
+ results: z.array(bridgeShowFlagResultSchema).max(32),
3923
+ state: creativeEditStateSchema,
3924
+ successCount: z.number().int().min(0),
3925
+ type: z.literal(BRIDGE_TOGGLE_SHOW_FLAGS_REQUEST_TYPE),
3926
+ version: z.literal(2)
3927
+ });
3928
+ const bridgeHighResScreenshotSuccessResponseSchema = z.object({
3929
+ filePath: z.string(),
3930
+ message: nonEmptyStringSchema.optional(),
3931
+ multiplier: z.number(),
3932
+ ok: z.literal(true),
3933
+ requestId: requestIdSchema,
3934
+ state: screenshotStateSchema,
3935
+ type: z.literal(BRIDGE_HIGH_RES_SCREENSHOT_REQUEST_TYPE),
3936
+ version: z.literal(2)
3937
+ });
3938
+ const bridgeDuplicateActorSuccessResponseSchema = z.object({
3939
+ ...levelEditResponseFields,
3940
+ type: z.literal(BRIDGE_DUPLICATE_ACTOR_REQUEST_TYPE)
3941
+ }).refine(isLevelEditStateConsistent, levelEditStateRefinement);
3942
+ const bridgeAttachActorSuccessResponseSchema = z.object({
3943
+ ...levelEditResponseFields,
3944
+ type: z.literal(BRIDGE_ATTACH_ACTOR_REQUEST_TYPE)
3945
+ }).refine(isLevelEditStateConsistent, levelEditStateRefinement);
3946
+ const bridgeAddActorComponentSuccessResponseSchema = z.object({
3947
+ ...levelEditResponseFields,
3948
+ type: z.literal(BRIDGE_ADD_ACTOR_COMPONENT_REQUEST_TYPE)
3949
+ }).refine(isLevelEditStateConsistent, levelEditStateRefinement);
3950
+ const bridgeSetActorTagsSuccessResponseSchema = z.object({
3951
+ ...levelEditResponseFields,
3952
+ type: z.literal(BRIDGE_SET_ACTOR_TAGS_REQUEST_TYPE)
3953
+ }).refine(isLevelEditStateConsistent, levelEditStateRefinement);
3954
+ const bridgeMoveToFolderSuccessResponseSchema = z.object({
3955
+ ...levelEditResponseFields,
3956
+ type: z.literal(BRIDGE_MOVE_TO_FOLDER_REQUEST_TYPE)
3957
+ }).refine(isLevelEditStateConsistent, levelEditStateRefinement);
3958
+ const bridgePlaceAssetSuccessResponseSchema = z.object({
3959
+ ...levelEditResponseFields,
3960
+ type: z.literal(BRIDGE_PLACE_ASSET_REQUEST_TYPE)
3961
+ }).refine(isLevelEditStateConsistent, levelEditStateRefinement);
3962
+ const bridgeReplaceActorsSuccessResponseSchema = z.object({
3963
+ ...levelEditResponseFields,
3964
+ type: z.literal(BRIDGE_REPLACE_ACTORS_REQUEST_TYPE)
3965
+ }).refine(isLevelEditStateConsistent, levelEditStateRefinement);
3966
+ const bridgeStartEditorBuildSuccessResponseSchema = z.object({
3967
+ buildJobId: buildJobIdSchema.optional(),
3968
+ buildKind: editorBuildKindSchema,
3969
+ message: nonEmptyStringSchema.optional(),
3970
+ ok: z.literal(true),
3971
+ requestId: requestIdSchema,
3972
+ state: editorBuildAcceptStateSchema,
3973
+ type: z.literal(BRIDGE_START_EDITOR_BUILD_REQUEST_TYPE),
3974
+ version: z.literal(2)
3975
+ }).refine((value) => value.state === "accepted" === (value.buildJobId !== void 0), {
3976
+ message: "A start_editor_build response must carry buildJobId exactly when state is 'accepted'.",
3977
+ path: ["buildJobId"]
3978
+ });
3979
+ const bridgeGetBuildJobStatusSuccessResponseSchema = z.object({
3980
+ buildJobId: buildJobIdSchema,
3981
+ buildKind: editorBuildKindSchema.optional(),
3982
+ durationMs: z.number().int().min(0).optional(),
3983
+ errorCount: z.number().int().min(0),
3984
+ errors: z.array(z.string()).max(50),
3985
+ finishedAt: nonEmptyStringSchema.optional(),
3986
+ message: nonEmptyStringSchema.optional(),
3987
+ ok: z.literal(true),
3988
+ requestId: requestIdSchema,
3989
+ startedAt: nonEmptyStringSchema.optional(),
3990
+ state: editorBuildJobStateSchema,
3991
+ type: z.literal(BRIDGE_GET_BUILD_JOB_STATUS_REQUEST_TYPE),
3992
+ version: z.literal(2),
3993
+ warningCount: z.number().int().min(0),
3994
+ warnings: z.array(z.string()).max(50)
3995
+ }).refine((value) => value.state !== "unknown_job" || value.errors.length === 0, {
3996
+ message: "An unknown_job get_build_job_status response must carry no build errors.",
3997
+ path: ["errors"]
3998
+ }).refine((value) => value.state !== "failed" || value.errorCount > 0, {
3999
+ message: "A 'failed' get_build_job_status response must report at least one error.",
4000
+ path: ["errorCount"]
4001
+ });
4002
+ const bridgeCreateGameplayTagSuccessResponseSchema = z.object({
4003
+ configFilePath: z.string(),
4004
+ message: nonEmptyStringSchema.optional(),
4005
+ ok: z.literal(true),
4006
+ requestId: requestIdSchema,
4007
+ state: createGameplayTagStateSchema,
4008
+ tagName: z.string(),
4009
+ type: z.literal(BRIDGE_CREATE_GAMEPLAY_TAG_REQUEST_TYPE),
4010
+ version: z.literal(2)
4011
+ });
4012
+ const bridgeGameplayTagSchema = z.object({
4013
+ comment: z.string().optional(),
4014
+ source: z.string().optional(),
4015
+ tagName: z.string()
4016
+ });
4017
+ const bridgeListGameplayTagsSuccessResponseSchema = z.object({
4018
+ nextCursor: assetCursorSchema.optional(),
4019
+ ok: z.literal(true),
4020
+ requestId: requestIdSchema,
4021
+ tags: z.array(bridgeGameplayTagSchema).max(200),
4022
+ totalCount: z.number().int().min(0),
4023
+ truncated: z.boolean(),
4024
+ type: z.literal(BRIDGE_LIST_GAMEPLAY_TAGS_REQUEST_TYPE),
4025
+ version: z.literal(2)
4026
+ });
4027
+ const bridgeCreateLandscapeSuccessResponseSchema = z.object({
4028
+ actorPath: z.string(),
4029
+ componentCount: z.number().int().min(0),
4030
+ message: nonEmptyStringSchema.optional(),
4031
+ ok: z.literal(true),
4032
+ requestId: requestIdSchema,
4033
+ resolutionX: z.number().int().min(0),
4034
+ resolutionY: z.number().int().min(0),
4035
+ state: creativeEditStateSchema,
4036
+ type: z.literal(BRIDGE_CREATE_LANDSCAPE_REQUEST_TYPE),
4037
+ version: z.literal(2)
4038
+ });
4039
+ const landscapeEditResponseFields = {
4040
+ actorPath: z.string(),
4041
+ message: nonEmptyStringSchema.optional(),
4042
+ modifiedVertexCount: z.number().int().min(0),
4043
+ ok: z.literal(true),
4044
+ requestId: requestIdSchema,
4045
+ state: creativeEditStateSchema,
4046
+ version: z.literal(2)
4047
+ };
4048
+ const bridgeSculptLandscapeSuccessResponseSchema = z.object({
4049
+ ...landscapeEditResponseFields,
4050
+ mode: landscapeSculptModeSchema,
4051
+ type: z.literal(BRIDGE_SCULPT_LANDSCAPE_REQUEST_TYPE)
4052
+ });
4053
+ const bridgePaintLandscapeLayerSuccessResponseSchema = z.object({
4054
+ ...landscapeEditResponseFields,
4055
+ layerName: z.string(),
4056
+ type: z.literal(BRIDGE_PAINT_LANDSCAPE_LAYER_REQUEST_TYPE)
4057
+ });
4058
+ const bridgeRunGeometryScriptSuccessResponseSchema = z.object({
4059
+ actorPath: z.string().optional(),
4060
+ message: nonEmptyStringSchema.optional(),
4061
+ objectPath: z.string().optional(),
4062
+ ok: z.literal(true),
4063
+ operationCount: z.number().int().min(0),
4064
+ requestId: requestIdSchema,
4065
+ state: creativeEditStateSchema,
4066
+ triangleCount: z.number().int().min(0),
4067
+ type: z.literal(BRIDGE_RUN_GEOMETRY_SCRIPT_REQUEST_TYPE),
4068
+ version: z.literal(2),
4069
+ vertexCount: z.number().int().min(0)
4070
+ });
4071
+ const bridgeDataLayerSchema = z.object({
4072
+ dataLayerAsset: z.string(),
4073
+ editorVisible: z.boolean(),
4074
+ initialRuntimeState: dataLayerRuntimeStateSchema,
4075
+ isRuntime: z.boolean(),
4076
+ loadedInEditor: z.boolean(),
4077
+ name: z.string(),
4078
+ runtimeState: dataLayerRuntimeStateSchema
4079
+ });
4080
+ const bridgeListDataLayersSuccessResponseSchema = z.object({
4081
+ dataLayers: z.array(bridgeDataLayerSchema).max(100),
4082
+ isWorldPartition: z.boolean(),
4083
+ message: nonEmptyStringSchema.optional(),
4084
+ nextCursor: assetCursorSchema.optional(),
4085
+ ok: z.literal(true),
4086
+ requestId: requestIdSchema,
4087
+ totalCount: z.number().int().min(0),
4088
+ truncated: z.boolean(),
4089
+ type: z.literal(BRIDGE_LIST_DATA_LAYERS_REQUEST_TYPE),
4090
+ version: z.literal(2)
4091
+ }).refine((value) => value.isWorldPartition || value.dataLayers.length === 0, {
4092
+ message: "A non-World-Partition list_data_layers response must carry no data layers.",
4093
+ path: ["dataLayers"]
4094
+ });
4095
+ const bridgeDataLayerResultSchema = z.object({
4096
+ dataLayerAsset: z.string(),
4097
+ error: z.string().optional(),
4098
+ index: z.number().int().min(0),
4099
+ ok: z.boolean()
4100
+ });
4101
+ const bridgeSetDataLayerStateSuccessResponseSchema = z.object({
4102
+ failureCount: z.number().int().min(0),
4103
+ message: nonEmptyStringSchema.optional(),
4104
+ ok: z.literal(true),
4105
+ requestId: requestIdSchema,
4106
+ results: z.array(bridgeDataLayerResultSchema).max(32),
4107
+ state: creativeEditStateSchema,
4108
+ successCount: z.number().int().min(0),
4109
+ type: z.literal(BRIDGE_SET_DATA_LAYER_STATE_REQUEST_TYPE),
4110
+ version: z.literal(2)
4111
+ });
4112
+ const bridgeLoadWpRegionSuccessResponseSchema = z.object({
4113
+ action: wpRegionActionSchema,
4114
+ loadedActorCount: z.number().int().min(0),
4115
+ message: nonEmptyStringSchema.optional(),
4116
+ ok: z.literal(true),
4117
+ pinnedRegionCount: z.number().int().min(0),
4118
+ regionId: wpRegionIdSchema.optional(),
4119
+ requestId: requestIdSchema,
4120
+ state: creativeEditStateSchema,
4121
+ type: z.literal(BRIDGE_LOAD_WP_REGION_REQUEST_TYPE),
4122
+ version: z.literal(2)
4123
+ }).refine((value) => value.action !== "pin" || value.state !== "applied" || value.regionId !== void 0, {
4124
+ message: "An applied 'pin' load_wp_region response must carry a regionId.",
4125
+ path: ["regionId"]
4126
+ });
4127
+ const bridgeListAssetFactoriesResponseSchema = z.union([bridgeListAssetFactoriesSuccessResponseSchema, bridgeErrorResponseSchema]);
4128
+ const bridgeCreateAssetResponseSchema = z.union([bridgeCreateAssetSuccessResponseSchema, bridgeErrorResponseSchema]);
4129
+ const bridgeDuplicateAssetResponseSchema = z.union([bridgeDuplicateAssetSuccessResponseSchema, bridgeErrorResponseSchema]);
4130
+ const bridgeRenameAssetResponseSchema = z.union([bridgeRenameAssetSuccessResponseSchema, bridgeErrorResponseSchema]);
4131
+ const bridgeMoveAssetResponseSchema = z.union([bridgeMoveAssetSuccessResponseSchema, bridgeErrorResponseSchema]);
4132
+ const bridgeDeleteAssetResponseSchema = z.union([bridgeDeleteAssetSuccessResponseSchema, bridgeErrorResponseSchema]);
4133
+ const bridgeSaveAssetResponseSchema = z.union([bridgeSaveAssetSuccessResponseSchema, bridgeErrorResponseSchema]);
4134
+ const bridgeCreateFolderResponseSchema = z.union([bridgeCreateFolderSuccessResponseSchema, bridgeErrorResponseSchema]);
4135
+ const bridgeGetAssetMetadataResponseSchema = z.union([bridgeGetAssetMetadataSuccessResponseSchema, bridgeErrorResponseSchema]);
4136
+ const bridgeListGraphNodesResponseSchema = z.union([bridgeListGraphNodesSuccessResponseSchema, bridgeErrorResponseSchema]);
4137
+ const bridgeAddGraphNodeResponseSchema = z.union([bridgeAddGraphNodeSuccessResponseSchema, bridgeErrorResponseSchema]);
4138
+ const bridgeRemoveGraphNodeResponseSchema = z.union([bridgeRemoveGraphNodeSuccessResponseSchema, bridgeErrorResponseSchema]);
4139
+ const bridgeConnectPinsResponseSchema = z.union([bridgeConnectPinsSuccessResponseSchema, bridgeErrorResponseSchema]);
4140
+ const bridgeDisconnectPinsResponseSchema = z.union([bridgeDisconnectPinsSuccessResponseSchema, bridgeErrorResponseSchema]);
4141
+ const bridgeSetPinDefaultResponseSchema = z.union([bridgeSetPinDefaultSuccessResponseSchema, bridgeErrorResponseSchema]);
4142
+ const bridgeListAvailableNodesResponseSchema = z.union([bridgeListAvailableNodesSuccessResponseSchema, bridgeErrorResponseSchema]);
4143
+ const bridgeSetViewportCameraResponseSchema = z.union([bridgeSetViewportCameraSuccessResponseSchema, bridgeErrorResponseSchema]);
4144
+ const bridgeFocusActorsResponseSchema = z.union([bridgeFocusActorsSuccessResponseSchema, bridgeErrorResponseSchema]);
4145
+ const bridgeSetViewModeResponseSchema = z.union([bridgeSetViewModeSuccessResponseSchema, bridgeErrorResponseSchema]);
4146
+ const bridgeToggleShowFlagsResponseSchema = z.union([bridgeToggleShowFlagsSuccessResponseSchema, bridgeErrorResponseSchema]);
4147
+ const bridgeHighResScreenshotResponseSchema = z.union([bridgeHighResScreenshotSuccessResponseSchema, bridgeErrorResponseSchema]);
4148
+ const bridgeDuplicateActorResponseSchema = z.union([bridgeDuplicateActorSuccessResponseSchema, bridgeErrorResponseSchema]);
4149
+ const bridgeAttachActorResponseSchema = z.union([bridgeAttachActorSuccessResponseSchema, bridgeErrorResponseSchema]);
4150
+ const bridgeAddActorComponentResponseSchema = z.union([bridgeAddActorComponentSuccessResponseSchema, bridgeErrorResponseSchema]);
4151
+ const bridgeSetActorTagsResponseSchema = z.union([bridgeSetActorTagsSuccessResponseSchema, bridgeErrorResponseSchema]);
4152
+ const bridgeMoveToFolderResponseSchema = z.union([bridgeMoveToFolderSuccessResponseSchema, bridgeErrorResponseSchema]);
4153
+ const bridgePlaceAssetResponseSchema = z.union([bridgePlaceAssetSuccessResponseSchema, bridgeErrorResponseSchema]);
4154
+ const bridgeReplaceActorsResponseSchema = z.union([bridgeReplaceActorsSuccessResponseSchema, bridgeErrorResponseSchema]);
4155
+ const bridgeStartEditorBuildResponseSchema = z.union([bridgeStartEditorBuildSuccessResponseSchema, bridgeErrorResponseSchema]);
4156
+ const bridgeGetBuildJobStatusResponseSchema = z.union([bridgeGetBuildJobStatusSuccessResponseSchema, bridgeErrorResponseSchema]);
4157
+ const bridgeCreateGameplayTagResponseSchema = z.union([bridgeCreateGameplayTagSuccessResponseSchema, bridgeErrorResponseSchema]);
4158
+ const bridgeListGameplayTagsResponseSchema = z.union([bridgeListGameplayTagsSuccessResponseSchema, bridgeErrorResponseSchema]);
4159
+ const bridgeCreateLandscapeResponseSchema = z.union([bridgeCreateLandscapeSuccessResponseSchema, bridgeErrorResponseSchema]);
4160
+ const bridgeSculptLandscapeResponseSchema = z.union([bridgeSculptLandscapeSuccessResponseSchema, bridgeErrorResponseSchema]);
4161
+ const bridgePaintLandscapeLayerResponseSchema = z.union([bridgePaintLandscapeLayerSuccessResponseSchema, bridgeErrorResponseSchema]);
4162
+ const bridgeRunGeometryScriptResponseSchema = z.union([bridgeRunGeometryScriptSuccessResponseSchema, bridgeErrorResponseSchema]);
4163
+ const bridgeListDataLayersResponseSchema = z.union([bridgeListDataLayersSuccessResponseSchema, bridgeErrorResponseSchema]);
4164
+ const bridgeSetDataLayerStateResponseSchema = z.union([bridgeSetDataLayerStateSuccessResponseSchema, bridgeErrorResponseSchema]);
4165
+ const bridgeLoadWpRegionResponseSchema = z.union([bridgeLoadWpRegionSuccessResponseSchema, bridgeErrorResponseSchema]);
4166
+ function createBridgeListAssetFactoriesRequest(options = {}, requestId = randomUUID()) {
4167
+ return bridgeListAssetFactoriesRequestSchema.parse({
4168
+ cursor: options.cursor,
4169
+ maxResults: options.maxResults,
4170
+ nameFilter: options.nameFilter,
4171
+ requestId,
4172
+ type: BRIDGE_LIST_ASSET_FACTORIES_REQUEST_TYPE,
4173
+ version: 2
4174
+ });
4175
+ }
4176
+ function createBridgeCreateAssetRequest(assetClass, assetName, packagePath, options = {}, requestId = randomUUID()) {
4177
+ return bridgeCreateAssetRequestSchema.parse({
4178
+ assetClass,
4179
+ assetName,
4180
+ factoryClass: options.factoryClass,
4181
+ options: options.options,
4182
+ packagePath,
4183
+ requestId,
4184
+ type: BRIDGE_CREATE_ASSET_REQUEST_TYPE,
4185
+ version: 2
4186
+ });
4187
+ }
4188
+ function createBridgeDuplicateAssetRequest(sourceAssetPath, destinationPath, destinationName, requestId = randomUUID()) {
4189
+ return bridgeDuplicateAssetRequestSchema.parse({
4190
+ destinationName,
4191
+ destinationPath,
4192
+ requestId,
4193
+ sourceAssetPath,
4194
+ type: BRIDGE_DUPLICATE_ASSET_REQUEST_TYPE,
4195
+ version: 2
4196
+ });
4197
+ }
4198
+ function createBridgeRenameAssetRequest(assetPath, newName, requestId = randomUUID()) {
4199
+ return bridgeRenameAssetRequestSchema.parse({
4200
+ assetPath,
4201
+ newName,
4202
+ requestId,
4203
+ type: BRIDGE_RENAME_ASSET_REQUEST_TYPE,
4204
+ version: 2
4205
+ });
4206
+ }
4207
+ function createBridgeMoveAssetRequest(assetPath, destinationPath, options = {}, requestId = randomUUID()) {
4208
+ return bridgeMoveAssetRequestSchema.parse({
4209
+ assetPath,
4210
+ destinationPath,
4211
+ newName: options.newName,
4212
+ requestId,
4213
+ type: BRIDGE_MOVE_ASSET_REQUEST_TYPE,
4214
+ version: 2
4215
+ });
4216
+ }
4217
+ function createBridgeDeleteAssetRequest(assetPath, options = {}, requestId = randomUUID()) {
4218
+ return bridgeDeleteAssetRequestSchema.parse({
4219
+ assetPath,
4220
+ force: options.force,
4221
+ requestId,
4222
+ type: BRIDGE_DELETE_ASSET_REQUEST_TYPE,
4223
+ version: 2
4224
+ });
4225
+ }
4226
+ function createBridgeSaveAssetRequest(assetPaths, requestId = randomUUID()) {
4227
+ return bridgeSaveAssetRequestSchema.parse({
4228
+ assetPaths,
4229
+ requestId,
4230
+ type: BRIDGE_SAVE_ASSET_REQUEST_TYPE,
4231
+ version: 2
4232
+ });
4233
+ }
4234
+ function createBridgeCreateFolderRequest(folderPath, requestId = randomUUID()) {
4235
+ return bridgeCreateFolderRequestSchema.parse({
4236
+ folderPath,
4237
+ requestId,
4238
+ type: BRIDGE_CREATE_FOLDER_REQUEST_TYPE,
4239
+ version: 2
4240
+ });
4241
+ }
4242
+ function createBridgeGetAssetMetadataRequest(assetPath, requestId = randomUUID()) {
4243
+ return bridgeGetAssetMetadataRequestSchema.parse({
4244
+ assetPath,
4245
+ requestId,
4246
+ type: BRIDGE_GET_ASSET_METADATA_REQUEST_TYPE,
4247
+ version: 2
4248
+ });
4249
+ }
4250
+ function createBridgeListGraphNodesRequest(assetPath, graphName, options = {}, requestId = randomUUID()) {
4251
+ return bridgeListGraphNodesRequestSchema.parse({
4252
+ assetPath,
4253
+ cursor: options.cursor,
4254
+ graphName,
4255
+ loadIfNeeded: options.loadIfNeeded,
4256
+ maxResults: options.maxResults,
4257
+ requestId,
4258
+ type: BRIDGE_LIST_GRAPH_NODES_REQUEST_TYPE,
4259
+ version: 2
4260
+ });
4261
+ }
4262
+ function createBridgeAddGraphNodeRequest(assetPath, graphName, kind, options = {}, requestId = randomUUID()) {
4263
+ return bridgeAddGraphNodeRequestSchema.parse({
4264
+ assetPath,
4265
+ graphName,
4266
+ kind,
4267
+ memberName: options.memberName,
4268
+ memberParentClass: options.memberParentClass,
4269
+ nodeClass: options.nodeClass,
4270
+ pinDefaults: options.pinDefaults,
4271
+ position: options.position,
4272
+ requestId,
4273
+ type: BRIDGE_ADD_GRAPH_NODE_REQUEST_TYPE,
4274
+ version: 2
4275
+ });
4276
+ }
4277
+ function createBridgeRemoveGraphNodeRequest(assetPath, graphName, nodeGuid, requestId = randomUUID()) {
4278
+ return bridgeRemoveGraphNodeRequestSchema.parse({
4279
+ assetPath,
4280
+ graphName,
4281
+ nodeGuid,
4282
+ requestId,
4283
+ type: BRIDGE_REMOVE_GRAPH_NODE_REQUEST_TYPE,
4284
+ version: 2
4285
+ });
4286
+ }
4287
+ function createBridgeConnectPinsRequest(assetPath, graphName, source, target, requestId = randomUUID()) {
4288
+ return bridgeConnectPinsRequestSchema.parse({
4289
+ assetPath,
4290
+ graphName,
4291
+ requestId,
4292
+ sourceNodeGuid: source.nodeGuid,
4293
+ sourcePinName: source.pinName,
4294
+ targetNodeGuid: target.nodeGuid,
4295
+ targetPinName: target.pinName,
4296
+ type: BRIDGE_CONNECT_PINS_REQUEST_TYPE,
4297
+ version: 2
4298
+ });
4299
+ }
4300
+ function createBridgeDisconnectPinsRequest(assetPath, graphName, source, target, requestId = randomUUID()) {
4301
+ return bridgeDisconnectPinsRequestSchema.parse({
4302
+ assetPath,
4303
+ graphName,
4304
+ requestId,
4305
+ sourceNodeGuid: source.nodeGuid,
4306
+ sourcePinName: source.pinName,
4307
+ targetNodeGuid: target.nodeGuid,
4308
+ targetPinName: target.pinName,
4309
+ type: BRIDGE_DISCONNECT_PINS_REQUEST_TYPE,
4310
+ version: 2
4311
+ });
4312
+ }
4313
+ function createBridgeSetPinDefaultRequest(assetPath, graphName, nodeGuid, pinName, value, requestId = randomUUID()) {
4314
+ return bridgeSetPinDefaultRequestSchema.parse({
4315
+ assetPath,
4316
+ graphName,
4317
+ nodeGuid,
4318
+ pinName,
4319
+ requestId,
4320
+ type: BRIDGE_SET_PIN_DEFAULT_REQUEST_TYPE,
4321
+ value,
4322
+ version: 2
4323
+ });
4324
+ }
4325
+ function createBridgeListAvailableNodesRequest(assetPath, graphName, options = {}, requestId = randomUUID()) {
4326
+ return bridgeListAvailableNodesRequestSchema.parse({
4327
+ assetPath,
4328
+ cursor: options.cursor,
4329
+ graphName,
4330
+ maxResults: options.maxResults,
4331
+ nameFilter: options.nameFilter,
4332
+ requestId,
4333
+ type: BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE,
4334
+ version: 2
4335
+ });
4336
+ }
4337
+ function createBridgeSetViewportCameraRequest(options = {}, requestId = randomUUID()) {
4338
+ return bridgeSetViewportCameraRequestSchema.parse({
4339
+ fov: options.fov,
4340
+ location: options.location,
4341
+ orthoWidth: options.orthoWidth,
4342
+ requestId,
4343
+ rotation: options.rotation,
4344
+ type: BRIDGE_SET_VIEWPORT_CAMERA_REQUEST_TYPE,
4345
+ version: 2,
4346
+ viewType: options.viewType
4347
+ });
4348
+ }
4349
+ function createBridgeFocusActorsRequest(actorPaths, options = {}, requestId = randomUUID()) {
4350
+ return bridgeFocusActorsRequestSchema.parse({
4351
+ actorPaths,
4352
+ instant: options.instant,
4353
+ requestId,
4354
+ type: BRIDGE_FOCUS_ACTORS_REQUEST_TYPE,
4355
+ version: 2
4356
+ });
4357
+ }
4358
+ function createBridgeSetViewModeRequest(viewMode, requestId = randomUUID()) {
4359
+ return bridgeSetViewModeRequestSchema.parse({
4360
+ requestId,
4361
+ type: BRIDGE_SET_VIEW_MODE_REQUEST_TYPE,
4362
+ version: 2,
4363
+ viewMode
4364
+ });
4365
+ }
4366
+ function createBridgeToggleShowFlagsRequest(flags, requestId = randomUUID()) {
4367
+ return bridgeToggleShowFlagsRequestSchema.parse({
4368
+ flags,
4369
+ requestId,
4370
+ type: BRIDGE_TOGGLE_SHOW_FLAGS_REQUEST_TYPE,
4371
+ version: 2
4372
+ });
4373
+ }
4374
+ function createBridgeHighResScreenshotRequest(options = {}, requestId = randomUUID()) {
4375
+ return bridgeHighResScreenshotRequestSchema.parse({
4376
+ fileName: options.fileName,
4377
+ includeUi: options.includeUi,
4378
+ multiplier: options.multiplier,
4379
+ requestId,
4380
+ type: BRIDGE_HIGH_RES_SCREENSHOT_REQUEST_TYPE,
4381
+ version: 2
4382
+ });
4383
+ }
4384
+ function createBridgeDuplicateActorRequest(actors, options = {}, requestId = randomUUID()) {
4385
+ return bridgeDuplicateActorRequestSchema.parse({
4386
+ actors,
4387
+ dryRun: options.dryRun,
4388
+ requestId,
4389
+ type: BRIDGE_DUPLICATE_ACTOR_REQUEST_TYPE,
4390
+ version: 2
4391
+ });
4392
+ }
4393
+ function createBridgeAttachActorRequest(attachments, options = {}, requestId = randomUUID()) {
4394
+ return bridgeAttachActorRequestSchema.parse({
4395
+ attachments,
4396
+ dryRun: options.dryRun,
4397
+ requestId,
4398
+ type: BRIDGE_ATTACH_ACTOR_REQUEST_TYPE,
4399
+ version: 2
4400
+ });
4401
+ }
4402
+ function createBridgeAddActorComponentRequest(components, options = {}, requestId = randomUUID()) {
4403
+ return bridgeAddActorComponentRequestSchema.parse({
4404
+ components,
4405
+ dryRun: options.dryRun,
4406
+ requestId,
4407
+ type: BRIDGE_ADD_ACTOR_COMPONENT_REQUEST_TYPE,
4408
+ version: 2
4409
+ });
4410
+ }
4411
+ function createBridgeSetActorTagsRequest(entries, options = {}, requestId = randomUUID()) {
4412
+ return bridgeSetActorTagsRequestSchema.parse({
4413
+ dryRun: options.dryRun,
4414
+ entries,
4415
+ requestId,
4416
+ type: BRIDGE_SET_ACTOR_TAGS_REQUEST_TYPE,
4417
+ version: 2
4418
+ });
4419
+ }
4420
+ function createBridgeMoveToFolderRequest(entries, options = {}, requestId = randomUUID()) {
4421
+ return bridgeMoveToFolderRequestSchema.parse({
4422
+ dryRun: options.dryRun,
4423
+ entries,
4424
+ requestId,
4425
+ type: BRIDGE_MOVE_TO_FOLDER_REQUEST_TYPE,
4426
+ version: 2
4427
+ });
4428
+ }
4429
+ function createBridgePlaceAssetRequest(placements, options = {}, requestId = randomUUID()) {
4430
+ return bridgePlaceAssetRequestSchema.parse({
4431
+ dryRun: options.dryRun,
4432
+ placements,
4433
+ requestId,
4434
+ type: BRIDGE_PLACE_ASSET_REQUEST_TYPE,
4435
+ version: 2
4436
+ });
4437
+ }
4438
+ function createBridgeReplaceActorsRequest(actorPaths, replacement, options = {}, requestId = randomUUID()) {
4439
+ return bridgeReplaceActorsRequestSchema.parse({
4440
+ actorPaths,
4441
+ dryRun: options.dryRun,
4442
+ replacementAssetPath: replacement.assetPath,
4443
+ replacementClass: replacement.className,
4444
+ requestId,
4445
+ type: BRIDGE_REPLACE_ACTORS_REQUEST_TYPE,
4446
+ version: 2
4447
+ });
4448
+ }
4449
+ function createBridgeStartEditorBuildRequest(buildKind, options = {}, requestId = randomUUID()) {
4450
+ return bridgeStartEditorBuildRequestSchema.parse({
4451
+ buildKind,
4452
+ hlodAction: options.hlodAction,
4453
+ quality: options.quality,
4454
+ requestId,
4455
+ type: BRIDGE_START_EDITOR_BUILD_REQUEST_TYPE,
4456
+ version: 2
4457
+ });
4458
+ }
4459
+ function createBridgeGetBuildJobStatusRequest(buildJobId, requestId = randomUUID()) {
4460
+ return bridgeGetBuildJobStatusRequestSchema.parse({
4461
+ buildJobId,
4462
+ requestId,
4463
+ type: BRIDGE_GET_BUILD_JOB_STATUS_REQUEST_TYPE,
4464
+ version: 2
4465
+ });
4466
+ }
4467
+ function createBridgeCreateGameplayTagRequest(tagName, options = {}, requestId = randomUUID()) {
4468
+ return bridgeCreateGameplayTagRequestSchema.parse({
4469
+ comment: options.comment,
4470
+ requestId,
4471
+ source: options.source,
4472
+ tagName,
4473
+ type: BRIDGE_CREATE_GAMEPLAY_TAG_REQUEST_TYPE,
4474
+ version: 2
4475
+ });
4476
+ }
4477
+ function createBridgeListGameplayTagsRequest(options = {}, requestId = randomUUID()) {
4478
+ return bridgeListGameplayTagsRequestSchema.parse({
4479
+ cursor: options.cursor,
4480
+ maxResults: options.maxResults,
4481
+ prefix: options.prefix,
4482
+ requestId,
4483
+ type: BRIDGE_LIST_GAMEPLAY_TAGS_REQUEST_TYPE,
4484
+ version: 2
4485
+ });
4486
+ }
4487
+ function createBridgeCreateLandscapeRequest(sizing, options = {}, requestId = randomUUID()) {
4488
+ return bridgeCreateLandscapeRequestSchema.parse({
4489
+ componentCountX: sizing.componentCountX,
4490
+ componentCountY: sizing.componentCountY,
4491
+ heightmapFilePath: options.heightmapFilePath,
4492
+ label: options.label,
4493
+ location: options.location,
4494
+ quadsPerSection: sizing.quadsPerSection,
4495
+ requestId,
4496
+ rotation: options.rotation,
4497
+ scale: options.scale,
4498
+ sectionsPerComponent: sizing.sectionsPerComponent,
4499
+ type: BRIDGE_CREATE_LANDSCAPE_REQUEST_TYPE,
4500
+ version: 2
4501
+ });
4502
+ }
4503
+ function createBridgeSculptLandscapeRequest(actorPath, mode, region, options = {}, requestId = randomUUID()) {
4504
+ return bridgeSculptLandscapeRequestSchema.parse({
4505
+ actorPath,
4506
+ height: options.height,
4507
+ heightmapFilePath: options.heightmapFilePath,
4508
+ mode,
4509
+ noiseAmplitude: options.noiseAmplitude,
4510
+ noiseFrequency: options.noiseFrequency,
4511
+ noiseSeed: options.noiseSeed,
4512
+ rampAxis: options.rampAxis,
4513
+ rampEndHeight: options.rampEndHeight,
4514
+ rampStartHeight: options.rampStartHeight,
4515
+ region,
4516
+ requestId,
4517
+ type: BRIDGE_SCULPT_LANDSCAPE_REQUEST_TYPE,
4518
+ version: 2
4519
+ });
4520
+ }
4521
+ function createBridgePaintLandscapeLayerRequest(actorPath, layerName, region, weight, requestId = randomUUID()) {
4522
+ return bridgePaintLandscapeLayerRequestSchema.parse({
4523
+ actorPath,
4524
+ layerName,
4525
+ region,
4526
+ requestId,
4527
+ type: BRIDGE_PAINT_LANDSCAPE_LAYER_REQUEST_TYPE,
4528
+ version: 2,
4529
+ weight
4530
+ });
4531
+ }
4532
+ function createBridgeRunGeometryScriptRequest(operations, output, options = {}, requestId = randomUUID()) {
4533
+ return bridgeRunGeometryScriptRequestSchema.parse({
4534
+ actorTransform: options.actorTransform,
4535
+ assetName: options.assetName,
4536
+ assetPath: options.assetPath,
4537
+ label: options.label,
4538
+ operations,
4539
+ output,
4540
+ requestId,
4541
+ type: BRIDGE_RUN_GEOMETRY_SCRIPT_REQUEST_TYPE,
4542
+ version: 2
4543
+ });
4544
+ }
4545
+ function createBridgeListDataLayersRequest(options = {}, requestId = randomUUID()) {
4546
+ return bridgeListDataLayersRequestSchema.parse({
4547
+ cursor: options.cursor,
4548
+ maxResults: options.maxResults,
4549
+ requestId,
4550
+ type: BRIDGE_LIST_DATA_LAYERS_REQUEST_TYPE,
4551
+ version: 2
4552
+ });
4553
+ }
4554
+ function createBridgeSetDataLayerStateRequest(entries, requestId = randomUUID()) {
4555
+ return bridgeSetDataLayerStateRequestSchema.parse({
4556
+ entries,
4557
+ requestId,
4558
+ type: BRIDGE_SET_DATA_LAYER_STATE_REQUEST_TYPE,
4559
+ version: 2
4560
+ });
4561
+ }
4562
+ function createBridgeLoadWpRegionRequest(action, options = {}, requestId = randomUUID()) {
4563
+ return bridgeLoadWpRegionRequestSchema.parse({
4564
+ action,
4565
+ region: options.region,
4566
+ regionId: options.regionId,
4567
+ requestId,
4568
+ type: BRIDGE_LOAD_WP_REGION_REQUEST_TYPE,
4569
+ version: 2
4570
+ });
4571
+ }
2975
4572
  //#endregion
2976
4573
  //#region src/bridgeSocketClient.ts
2977
4574
  var BridgeSocketError = class extends Error {
@@ -3141,6 +4738,123 @@ async function sendBridgeCheckoutAssetsRequest(request, options) {
3141
4738
  async function sendBridgeGetSourceControlJobStatusRequest(request, options) {
3142
4739
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetSourceControlJobStatusResponseSchema, request.requestId);
3143
4740
  }
4741
+ async function sendBridgeListAssetFactoriesRequest(request, options) {
4742
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeListAssetFactoriesResponseSchema, request.requestId);
4743
+ }
4744
+ async function sendBridgeCreateAssetRequest(request, options) {
4745
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateAssetResponseSchema, request.requestId);
4746
+ }
4747
+ async function sendBridgeDuplicateAssetRequest(request, options) {
4748
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeDuplicateAssetResponseSchema, request.requestId);
4749
+ }
4750
+ async function sendBridgeRenameAssetRequest(request, options) {
4751
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeRenameAssetResponseSchema, request.requestId);
4752
+ }
4753
+ async function sendBridgeMoveAssetRequest(request, options) {
4754
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeMoveAssetResponseSchema, request.requestId);
4755
+ }
4756
+ async function sendBridgeDeleteAssetRequest(request, options) {
4757
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeDeleteAssetResponseSchema, request.requestId);
4758
+ }
4759
+ async function sendBridgeSaveAssetRequest(request, options) {
4760
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSaveAssetResponseSchema, request.requestId);
4761
+ }
4762
+ async function sendBridgeCreateFolderRequest(request, options) {
4763
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateFolderResponseSchema, request.requestId);
4764
+ }
4765
+ async function sendBridgeGetAssetMetadataRequest(request, options) {
4766
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetAssetMetadataResponseSchema, request.requestId);
4767
+ }
4768
+ async function sendBridgeListGraphNodesRequest(request, options) {
4769
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeListGraphNodesResponseSchema, request.requestId);
4770
+ }
4771
+ async function sendBridgeAddGraphNodeRequest(request, options) {
4772
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeAddGraphNodeResponseSchema, request.requestId);
4773
+ }
4774
+ async function sendBridgeRemoveGraphNodeRequest(request, options) {
4775
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeRemoveGraphNodeResponseSchema, request.requestId);
4776
+ }
4777
+ async function sendBridgeConnectPinsRequest(request, options) {
4778
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeConnectPinsResponseSchema, request.requestId);
4779
+ }
4780
+ async function sendBridgeDisconnectPinsRequest(request, options) {
4781
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeDisconnectPinsResponseSchema, request.requestId);
4782
+ }
4783
+ async function sendBridgeSetPinDefaultRequest(request, options) {
4784
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetPinDefaultResponseSchema, request.requestId);
4785
+ }
4786
+ async function sendBridgeListAvailableNodesRequest(request, options) {
4787
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeListAvailableNodesResponseSchema, request.requestId);
4788
+ }
4789
+ async function sendBridgeSetViewportCameraRequest(request, options) {
4790
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetViewportCameraResponseSchema, request.requestId);
4791
+ }
4792
+ async function sendBridgeFocusActorsRequest(request, options) {
4793
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeFocusActorsResponseSchema, request.requestId);
4794
+ }
4795
+ async function sendBridgeSetViewModeRequest(request, options) {
4796
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetViewModeResponseSchema, request.requestId);
4797
+ }
4798
+ async function sendBridgeToggleShowFlagsRequest(request, options) {
4799
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeToggleShowFlagsResponseSchema, request.requestId);
4800
+ }
4801
+ async function sendBridgeHighResScreenshotRequest(request, options) {
4802
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeHighResScreenshotResponseSchema, request.requestId);
4803
+ }
4804
+ async function sendBridgeDuplicateActorRequest(request, options) {
4805
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeDuplicateActorResponseSchema, request.requestId);
4806
+ }
4807
+ async function sendBridgeAttachActorRequest(request, options) {
4808
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeAttachActorResponseSchema, request.requestId);
4809
+ }
4810
+ async function sendBridgeAddActorComponentRequest(request, options) {
4811
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeAddActorComponentResponseSchema, request.requestId);
4812
+ }
4813
+ async function sendBridgeSetActorTagsRequest(request, options) {
4814
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetActorTagsResponseSchema, request.requestId);
4815
+ }
4816
+ async function sendBridgeMoveToFolderRequest(request, options) {
4817
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeMoveToFolderResponseSchema, request.requestId);
4818
+ }
4819
+ async function sendBridgePlaceAssetRequest(request, options) {
4820
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgePlaceAssetResponseSchema, request.requestId);
4821
+ }
4822
+ async function sendBridgeReplaceActorsRequest(request, options) {
4823
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeReplaceActorsResponseSchema, request.requestId);
4824
+ }
4825
+ async function sendBridgeStartEditorBuildRequest(request, options) {
4826
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeStartEditorBuildResponseSchema, request.requestId);
4827
+ }
4828
+ async function sendBridgeGetBuildJobStatusRequest(request, options) {
4829
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetBuildJobStatusResponseSchema, request.requestId);
4830
+ }
4831
+ async function sendBridgeCreateGameplayTagRequest(request, options) {
4832
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateGameplayTagResponseSchema, request.requestId);
4833
+ }
4834
+ async function sendBridgeListGameplayTagsRequest(request, options) {
4835
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeListGameplayTagsResponseSchema, request.requestId);
4836
+ }
4837
+ async function sendBridgeCreateLandscapeRequest(request, options) {
4838
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateLandscapeResponseSchema, request.requestId);
4839
+ }
4840
+ async function sendBridgeSculptLandscapeRequest(request, options) {
4841
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSculptLandscapeResponseSchema, request.requestId);
4842
+ }
4843
+ async function sendBridgePaintLandscapeLayerRequest(request, options) {
4844
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgePaintLandscapeLayerResponseSchema, request.requestId);
4845
+ }
4846
+ async function sendBridgeRunGeometryScriptRequest(request, options) {
4847
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeRunGeometryScriptResponseSchema, request.requestId);
4848
+ }
4849
+ async function sendBridgeListDataLayersRequest(request, options) {
4850
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeListDataLayersResponseSchema, request.requestId);
4851
+ }
4852
+ async function sendBridgeSetDataLayerStateRequest(request, options) {
4853
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetDataLayerStateResponseSchema, request.requestId);
4854
+ }
4855
+ async function sendBridgeLoadWpRegionRequest(request, options) {
4856
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeLoadWpRegionResponseSchema, request.requestId);
4857
+ }
3144
4858
  async function sendBridgeGetAssetDependenciesRequest(request, options) {
3145
4859
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetAssetDependenciesResponseSchema, request.requestId);
3146
4860
  }
@@ -5445,6 +7159,7 @@ function percentile(sortedValues, fraction) {
5445
7159
  //#region src/mcpTools.ts
5446
7160
  const EDITOR_WORK_TIMEOUT_MS = 1e4;
5447
7161
  const WAIT_FOR_JOB_KINDS = [
7162
+ "build",
5448
7163
  "compile",
5449
7164
  "create_class",
5450
7165
  "pie",
@@ -5453,6 +7168,7 @@ const WAIT_FOR_JOB_KINDS = [
5453
7168
  ];
5454
7169
  const WAIT_FOR_JOB_MAX_TIMEOUT_MS = 6e5;
5455
7170
  const WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS = {
7171
+ build: WAIT_FOR_JOB_MAX_TIMEOUT_MS,
5456
7172
  compile: 12e4,
5457
7173
  create_class: 6e4,
5458
7174
  pie: 3e4,
@@ -5460,6 +7176,10 @@ const WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS = {
5460
7176
  test_run: 3e5
5461
7177
  };
5462
7178
  const WAIT_FOR_JOB_POLL_CADENCE_MS = {
7179
+ build: {
7180
+ capMs: 15e3,
7181
+ initialMs: 1e3
7182
+ },
5463
7183
  compile: {
5464
7184
  capMs: 2e3,
5465
7185
  initialMs: 250
@@ -6472,843 +8192,1397 @@ function registerMcpTools(server, dependencies) {
6472
8192
  }, async ({ projectPath }) => {
6473
8193
  return toToolSuccess(await getProjectIdForPath(projectPath, dependencies.projectIdResolver));
6474
8194
  });
6475
- server.registerTool("add_module", {
6476
- description: "Scaffold a new Unreal C++ module (Source/<moduleName> with Build.cs, Public/<moduleName>.h, Private/<moduleName>.cpp) and register it in a .uproject or .uplugin descriptor. Pure filesystem scaffold; run generate_project_files + build_target afterward to compile it.",
6477
- inputSchema: addModuleInputSchema,
6478
- title: "Add Module"
6479
- }, async ({ descriptorPath, loadingPhase, moduleName, moduleType, privateDependencyModuleNames, publicDependencyModuleNames }) => {
6480
- return toToolSuccess(await addModule({
6481
- descriptorPath,
6482
- loadingPhase,
8195
+ server.registerTool("add_module", {
8196
+ description: "Scaffold a new Unreal C++ module (Source/<moduleName> with Build.cs, Public/<moduleName>.h, Private/<moduleName>.cpp) and register it in a .uproject or .uplugin descriptor. Pure filesystem scaffold; run generate_project_files + build_target afterward to compile it.",
8197
+ inputSchema: addModuleInputSchema,
8198
+ title: "Add Module"
8199
+ }, async ({ descriptorPath, loadingPhase, moduleName, moduleType, privateDependencyModuleNames, publicDependencyModuleNames }) => {
8200
+ return toToolSuccess(await addModule({
8201
+ descriptorPath,
8202
+ loadingPhase,
8203
+ moduleName,
8204
+ moduleType,
8205
+ privateDependencyModuleNames,
8206
+ publicDependencyModuleNames
8207
+ }, dependencies));
8208
+ });
8209
+ server.registerTool("ping_project", {
8210
+ description: "Ping the registered Unreal engine bridge for a projectId and evict stale registrations after retries.",
8211
+ inputSchema: pingProjectInputSchema,
8212
+ title: "Ping Project"
8213
+ }, async ({ projectId }) => {
8214
+ return toToolSuccess(await pingProject(projectId, dependencies));
8215
+ });
8216
+ server.registerTool("list_registered_projects", {
8217
+ description: "List every Unreal Editor currently registered with this server (projectId, projectName, projectPath, host, port, pid, registeredAt, lastSeenAt). Call this first to discover which editors are running and which projectId to pass to the other tools. Reads the registry only and performs no network I/O unless verify is true, which pings each entry once and adds reachable/reason. Never evicts a registration — use ping_project for that.",
8218
+ inputSchema: listRegisteredProjectsInputSchema,
8219
+ title: "List Registered Projects"
8220
+ }, async ({ maxResults, verify }) => {
8221
+ return toToolSuccess(await listRegisteredProjects({
8222
+ maxResults,
8223
+ verify
8224
+ }, dependencies));
8225
+ });
8226
+ server.registerTool("trigger_live_compile", {
8227
+ description: "Trigger an Unreal Live Coding recompile of patched modules for a projectId; tail stream_output_log (LogLiveCoding) for build output.",
8228
+ inputSchema: triggerLiveCompileInputSchema,
8229
+ title: "Trigger Live Compile"
8230
+ }, async ({ projectId }) => {
8231
+ return toToolSuccess(await triggerLiveCompile(projectId, dependencies));
8232
+ });
8233
+ server.registerTool("trigger_hot_reload", {
8234
+ description: "Trigger an Unreal Hot Reload recompile-and-reload of the loaded game modules for a projectId. Use on macOS and Linux, where Live Coding does not exist; on Windows prefer trigger_live_compile. Poll with get_compile_status. Tail stream_output_log (LogHotReload) for build output.",
8235
+ inputSchema: triggerHotReloadInputSchema,
8236
+ title: "Trigger Hot Reload"
8237
+ }, async ({ projectId }) => {
8238
+ return toToolSuccess(await triggerHotReload(projectId, dependencies));
8239
+ });
8240
+ server.registerTool("get_compile_status", {
8241
+ description: "Poll a compile job started by trigger_live_compile or trigger_hot_reload for a projectId; returns state (compiling, succeeded, failed, unknown_job), error/warning counts and items, and timing once finished. Hot Reload jobs also report restartRequired/restartReason when the change looks structural. Tail stream_output_log (LogLiveCoding, LogHotReload) for detailed build lines.",
8242
+ inputSchema: getCompileStatusInputSchema,
8243
+ title: "Get Compile Status"
8244
+ }, async ({ compileJobId, projectId }) => {
8245
+ return toToolSuccess(await getCompileStatus({
8246
+ compileJobId,
8247
+ projectId
8248
+ }, dependencies));
8249
+ });
8250
+ server.registerTool("get_crash_callstack", {
8251
+ description: "Report structured call stacks for ensures and fatal errors captured in the running editor for a projectId, newest first. Each record carries the failure message, the capturing thread, and per-frame module, symbol and file/line where symbols resolve.",
8252
+ inputSchema: getCrashCallstackInputSchema,
8253
+ title: "Get Crash Callstack"
8254
+ }, async ({ maxFrames, maxRecords, projectId }) => {
8255
+ return toToolSuccess(await getCrashCallstack({
8256
+ maxFrames,
8257
+ maxRecords,
8258
+ projectId
8259
+ }, dependencies));
8260
+ });
8261
+ server.registerTool("build_target", {
8262
+ description: "Run a full UnrealBuildTool build for a target/configuration/platform as a child process and return pass/fail with parsed error and warning diagnostics. Use for structural changes Live Coding cannot handle (new UPROPERTY/UCLASS, layout changes). Server-side; does not require a running editor.",
8263
+ inputSchema: buildTargetInputSchema,
8264
+ title: "Build Target"
8265
+ }, async (input) => {
8266
+ return toToolSuccess(await buildTarget(input, dependencies));
8267
+ });
8268
+ server.registerTool("generate_project_files", {
8269
+ description: "Regenerate IDE project files with UnrealBuildTool (-projectfiles) so newly added modules and classes appear in the project. Returns success and any UBT errors. Server-side; does not require a running editor.",
8270
+ inputSchema: generateProjectFilesInputSchema,
8271
+ title: "Generate Project Files"
8272
+ }, async (input) => {
8273
+ return toToolSuccess(await generateProjectFiles(input, dependencies));
8274
+ });
8275
+ server.registerTool("clean_build", {
8276
+ description: "Clean build artifacts (Intermediate/Binaries) for a target with UnrealBuildTool (-Clean) to recover from stale-build issues. Returns the result and any UBT errors. Chain with build_target to rebuild. Server-side; does not require a running editor.",
8277
+ inputSchema: cleanBuildInputSchema,
8278
+ title: "Clean Build"
8279
+ }, async (input) => {
8280
+ return toToolSuccess(await cleanBuild(input, dependencies));
8281
+ });
8282
+ server.registerTool("cook_content", {
8283
+ description: "Start a full offline cook (UnrealEditor-Cmd -run=Cook) for a target platform and return a packageJobId immediately; poll it with get_package_status. Unlike launch_on_device (cook-on-the-fly) this proves the content actually cooks, surfacing missing references, unfixed redirectors and platform shader failures. Runs for minutes to tens of minutes. Refuses while the project editor is running unless force is true. Server-side; no running editor required.",
8284
+ inputSchema: cookContentInputSchema,
8285
+ title: "Cook Content"
8286
+ }, async (input) => {
8287
+ return toToolSuccess(await cookContent(input, dependencies));
8288
+ });
8289
+ server.registerTool("package_project", {
8290
+ description: "Start a full package via RunUAT BuildCookRun (build + cook + stage + pak + archive) for a platform, configuration and archive directory, returning a packageJobId immediately; poll it with get_package_status. Runs for minutes to tens of minutes. Refuses while the project editor is running unless force is true. Server-side; no running editor required.",
8291
+ inputSchema: packageProjectInputSchema,
8292
+ title: "Package Project"
8293
+ }, async (input) => {
8294
+ return toToolSuccess(await packageProject(input, dependencies));
8295
+ });
8296
+ server.registerTool("run_editor_commandlet", {
8297
+ description: "Start an editor commandlet (UnrealEditor-Cmd -run=<name>) with an argv array and return a packageJobId; poll it with get_package_status. Unlocks the maintenance commandlets you reach for after a failed cook — ResavePackages, FixupRedirects, DataValidation. The commandlet name must be identifier characters only and arguments are passed as separate argv entries without a shell; -run= and -Project= are set by the tool and rejected as arguments. A commandlet can modify or delete project assets, so it refuses to run while the project editor is running unless force is true.",
8298
+ inputSchema: runEditorCommandletInputSchema,
8299
+ title: "Run Editor Commandlet"
8300
+ }, async (input) => {
8301
+ return toToolSuccess(await runEditorCommandlet(input, dependencies));
8302
+ });
8303
+ server.registerTool("analyze_trace", {
8304
+ description: "Analyze a completed .utrace (the path stop_insights_trace returns) headlessly with the engine's Unreal Insights analyzer and return a bounded, readable summary: frame-time p50/p90/p99, the worst N hitches with timestamps, a CPU vs GPU time split, and top-N timing scopes by inclusive and exclusive time. Memory and LLM-tag totals are deliberately not reported — they need a separate analysis pass. Resolve the engine with engineVersion or projectPath. Every list is top-N and the response is byte-capped, with truncated naming what was shortened. Returns state 'unsupported' when the installed engine ships no Insights analyzer for this host.",
8305
+ inputSchema: analyzeTraceInputSchema,
8306
+ title: "Analyze Trace"
8307
+ }, async (input) => {
8308
+ return toToolSuccess(await analyzeTrace(input, dependencies));
8309
+ });
8310
+ server.registerTool("get_package_status", {
8311
+ description: "Poll a job started by cook_content, package_project, or run_editor_commandlet. Returns state ('running', 'succeeded', 'failed', 'cancelled', or 'unknown_job' for an unknown/evicted id), structured cook/UAT error and warning diagnostics, truncation flags, exit code, and timing once finished.",
8312
+ inputSchema: getPackageStatusInputSchema,
8313
+ title: "Get Package Status"
8314
+ }, async ({ packageJobId }) => {
8315
+ return toToolSuccess(getPackageStatus({ packageJobId }, dependencies));
8316
+ });
8317
+ server.registerTool("cancel_package_job", {
8318
+ description: "Abort an in-flight cook, package, or commandlet job by its packageJobId. Returns cancelled=true (state cancelled) when a live job was killed, or cancelled=false with the job current state (or unknown_job) otherwise.",
8319
+ inputSchema: cancelPackageJobInputSchema,
8320
+ title: "Cancel Package Job"
8321
+ }, async ({ packageJobId }) => {
8322
+ return toToolSuccess(cancelPackageJob({ packageJobId }, dependencies));
8323
+ });
8324
+ server.registerTool("run_clang_tidy", {
8325
+ description: "Run clang-tidy over a project's synced compile_commands.json and return structured findings (file, line, column, check, severity, message), catching issues before a compile. Report only; does not apply fixes. Server-side; does not require a running editor.",
8326
+ inputSchema: runClangTidyInputSchema,
8327
+ title: "Run clang-tidy"
8328
+ }, async (input) => {
8329
+ return toToolSuccess(await runClangTidy(input, dependencies));
8330
+ });
8331
+ server.registerTool("create_cpp_class", {
8332
+ description: "Scaffold a new C++ class in a projectId the way the editor New C++ Class wizard does (header, source, GENERATED_BODY, module API macro, project files). Generation is scheduled on the editor game thread and returns a createClassJobId; poll it with get_create_class_status.",
8333
+ inputSchema: createCppClassInputSchema,
8334
+ title: "Create C++ Class"
8335
+ }, async ({ className, classPath, moduleName, parentClass, projectId }) => {
8336
+ return toToolSuccess(await createCppClass({
8337
+ className,
8338
+ classPath,
6483
8339
  moduleName,
6484
- moduleType,
6485
- privateDependencyModuleNames,
6486
- publicDependencyModuleNames
8340
+ parentClass,
8341
+ projectId
8342
+ }, dependencies));
8343
+ });
8344
+ server.registerTool("get_create_class_status", {
8345
+ description: "Poll a C++ class generation job started by create_cpp_class for a projectId; returns state (creating, succeeded, failed, unknown_job), the generated headerPath and sourcePath, whether the editor hot-reloaded the class, and timing once finished.",
8346
+ inputSchema: getCreateClassStatusInputSchema,
8347
+ title: "Get Create Class Status"
8348
+ }, async ({ createClassJobId, projectId }) => {
8349
+ return toToolSuccess(await getCreateClassStatus({
8350
+ createClassJobId,
8351
+ projectId
8352
+ }, dependencies));
8353
+ });
8354
+ server.registerTool("stream_output_log", {
8355
+ description: "Poll a bounded batch of Unreal Output Log events for a project and continue by calling again with the returned cursor.",
8356
+ inputSchema: streamOutputLogInputSchema,
8357
+ title: "Stream Output Log"
8358
+ }, async ({ categoryAllow, categoryDeny, cursor, maxEvents, minVerbosity, projectId, textContains, textPattern }) => {
8359
+ return toToolSuccess(await streamLogs({
8360
+ cursor,
8361
+ filters: {
8362
+ categoryAllow,
8363
+ categoryDeny,
8364
+ minVerbosity,
8365
+ textContains,
8366
+ textPattern
8367
+ },
8368
+ maxEvents,
8369
+ projectId,
8370
+ registry: dependencies.registry,
8371
+ sessionManager: dependencies.logSessionManager,
8372
+ source: "output_log"
8373
+ }));
8374
+ });
8375
+ server.registerTool("stream_message_log", {
8376
+ description: "Poll a bounded batch from a named Unreal Message Log listing and continue by calling again with the returned cursor.",
8377
+ inputSchema: streamMessageLogInputSchema,
8378
+ title: "Stream Message Log"
8379
+ }, async ({ cursor, listingName, maxEvents, minSeverity, projectId, textContains, textPattern }) => {
8380
+ return toToolSuccess(await streamLogs({
8381
+ cursor,
8382
+ filters: {
8383
+ listingName,
8384
+ minSeverity,
8385
+ textContains,
8386
+ textPattern
8387
+ },
8388
+ maxEvents,
8389
+ projectId,
8390
+ registry: dependencies.registry,
8391
+ sessionManager: dependencies.logSessionManager,
8392
+ source: "message_log"
8393
+ }));
8394
+ });
8395
+ server.registerTool("stream_device_output_log", {
8396
+ description: "Poll a bounded batch of Unreal device-output log events and continue by calling again with the returned cursor.",
8397
+ inputSchema: streamDeviceOutputLogInputSchema,
8398
+ title: "Stream Device Output Log"
8399
+ }, async ({ cursor, deviceId, deviceName, maxEvents, projectId, textContains, textPattern }) => {
8400
+ return toToolSuccess(await streamLogs({
8401
+ cursor,
8402
+ filters: {
8403
+ deviceId,
8404
+ deviceName,
8405
+ textContains,
8406
+ textPattern
8407
+ },
8408
+ maxEvents,
8409
+ projectId,
8410
+ registry: dependencies.registry,
8411
+ sessionManager: dependencies.logSessionManager,
8412
+ source: "device_output_log"
8413
+ }));
8414
+ });
8415
+ server.registerTool("start_pie", {
8416
+ description: "Start a Play-in-Editor session in the registered Unreal editor for a project; play begins on the next editor tick (async). Returns starting/running/unsupported.",
8417
+ inputSchema: startPieInputSchema,
8418
+ title: "Start Play-in-Editor"
8419
+ }, async ({ map, mode, netMode, numClients, projectId, runUnderOneProcess }) => {
8420
+ return toToolSuccess(await startPie({
8421
+ map,
8422
+ mode,
8423
+ netMode,
8424
+ numClients,
8425
+ projectId,
8426
+ runUnderOneProcess
8427
+ }, dependencies));
8428
+ });
8429
+ server.registerTool("get_pie_status", {
8430
+ description: "Report the state of the Play-in-Editor session started by start_pie for a project: starting, running, stopped, or none. Reports running only after PIE has actually begun.",
8431
+ inputSchema: getPieStatusInputSchema,
8432
+ title: "Get Play-in-Editor Status"
8433
+ }, async ({ pieSessionId, projectId }) => {
8434
+ return toToolSuccess(await getPieStatus({
8435
+ pieSessionId,
8436
+ projectId
8437
+ }, dependencies));
8438
+ });
8439
+ server.registerTool("stop_pie", {
8440
+ description: "End the active Play-in-Editor session for a project. Returns stopped=true when a session was ended, or stopped=false (state none) when nothing was playing.",
8441
+ inputSchema: stopPieInputSchema,
8442
+ title: "Stop Play-in-Editor"
8443
+ }, async ({ pieSessionId, projectId }) => {
8444
+ return toToolSuccess(await stopPie({
8445
+ pieSessionId,
8446
+ projectId
8447
+ }, dependencies));
8448
+ });
8449
+ server.registerTool("list_launch_devices", {
8450
+ description: "List the target devices the registered Unreal editor can launch onto (iOS, Android, etc.), with each device id, name, platform, and connected/authorized state. Pick a deviceId for launch_on_device.",
8451
+ inputSchema: listLaunchDevicesInputSchema,
8452
+ title: "List Launch Devices"
8453
+ }, async ({ projectId }) => {
8454
+ return toToolSuccess(await listLaunchDevices({ projectId }, dependencies));
8455
+ });
8456
+ server.registerTool("launch_on_device", {
8457
+ description: "Launch (cook-on-the-fly + deploy, not package) the current project onto a connected target device by deviceId from list_launch_devices. Returns a launchSessionId and starting/unsupported state; deploy proceeds asynchronously.",
8458
+ inputSchema: launchOnDeviceInputSchema,
8459
+ title: "Launch On Device"
8460
+ }, async ({ deviceId, map, projectId }) => {
8461
+ return toToolSuccess(await launchOnDevice({
8462
+ deviceId,
8463
+ map,
8464
+ projectId
8465
+ }, dependencies));
8466
+ });
8467
+ server.registerTool("list_automation_tests", {
8468
+ description: "List the automation tests registered in a project's running Unreal Editor, with optional name and flag filters; returns each test's full name, display name, flags, and test type.",
8469
+ inputSchema: listAutomationTestsInputSchema,
8470
+ title: "List Automation Tests"
8471
+ }, async ({ cursor, flags, maxResults, nameFilter, projectId }) => {
8472
+ return toToolSuccess(await listAutomationTests({
8473
+ cursor,
8474
+ flags,
8475
+ maxResults,
8476
+ nameFilter,
8477
+ projectId
8478
+ }, dependencies));
8479
+ });
8480
+ server.registerTool("run_automation_tests", {
8481
+ description: "Start an Unreal automation run (unit, smoke, and functional/BP scene tests) for a project and return a testRunId; requires at least one of testNames or nameFilter. Poll progress separately via stream_message_log on the AutomationTesting listing.",
8482
+ inputSchema: runAutomationTestsInputSchema,
8483
+ title: "Run Automation Tests"
8484
+ }, async ({ flags, nameFilter, projectId, testNames }) => {
8485
+ return toToolSuccess(await runAutomationTests({
8486
+ flags,
8487
+ nameFilter,
8488
+ projectId,
8489
+ testNames
6487
8490
  }, dependencies));
6488
8491
  });
6489
- server.registerTool("ping_project", {
6490
- description: "Ping the registered Unreal engine bridge for a projectId and evict stale registrations after retries.",
6491
- inputSchema: pingProjectInputSchema,
6492
- title: "Ping Project"
6493
- }, async ({ projectId }) => {
6494
- return toToolSuccess(await pingProject(projectId, dependencies));
6495
- });
6496
- server.registerTool("list_registered_projects", {
6497
- description: "List every Unreal Editor currently registered with this server (projectId, projectName, projectPath, host, port, pid, registeredAt, lastSeenAt). Call this first to discover which editors are running and which projectId to pass to the other tools. Reads the registry only and performs no network I/O unless verify is true, which pings each entry once and adds reachable/reason. Never evicts a registration — use ping_project for that.",
6498
- inputSchema: listRegisteredProjectsInputSchema,
6499
- title: "List Registered Projects"
6500
- }, async ({ maxResults, verify }) => {
6501
- return toToolSuccess(await listRegisteredProjects({
8492
+ server.registerTool("get_test_run_status", {
8493
+ description: "Poll an automation run started by run_automation_tests by its testRunId; returns the run state ('running', 'complete', or 'unknown_run' for an unknown/expired id), aggregate pass/fail/skip counts, and structured per-test results with their log entries. Results are paged: pass the previous response nextCursor to fetch the next page (totalCount reports the full result count).",
8494
+ inputSchema: getTestRunStatusInputSchema,
8495
+ title: "Get Test Run Status"
8496
+ }, async ({ cursor, maxResults, projectId, testRunId }) => {
8497
+ return toToolSuccess(await getTestRunStatus({
8498
+ cursor,
6502
8499
  maxResults,
6503
- verify
8500
+ projectId,
8501
+ testRunId
6504
8502
  }, dependencies));
6505
8503
  });
6506
- server.registerTool("trigger_live_compile", {
6507
- description: "Trigger an Unreal Live Coding recompile of patched modules for a projectId; tail stream_output_log (LogLiveCoding) for build output.",
6508
- inputSchema: triggerLiveCompileInputSchema,
6509
- title: "Trigger Live Compile"
6510
- }, async ({ projectId }) => {
6511
- return toToolSuccess(await triggerLiveCompile(projectId, dependencies));
8504
+ server.registerTool("wait_for_job", {
8505
+ description: `Block server-side until an async job reaches a terminal state, then return the payload its get_*_status tool would have returned under 'status'. Use instead of a poll loop after trigger_live_compile, trigger_hot_reload (kind 'compile'), create_cpp_class ('create_class'), run_automation_tests ('test_run'), or start_pie ('pie'). kind is required — job ids carry no type tag. outcome is 'completed', 'timed_out' (the last observed status is still returned; call again or poll), or 'unknown_job' (unknown/expired/cancelled id, returned immediately). timeoutMs defaults per kind (compile ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.compile)}ms, create_class ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.create_class)}ms, pie ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.pie)}ms, test_run ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.test_run)}ms) and is clamped to ${String(WAIT_FOR_JOB_MAX_TIMEOUT_MS)}ms, so a long automation run may need more than one call. For kind 'test_run' the returned status.results is the first page only — page the rest with get_test_run_status and nextCursor. For kind 'pie' only 'starting' keeps waiting; 'running', 'stopped' and 'none' are all terminal.`,
8506
+ inputSchema: waitForJobInputSchema,
8507
+ title: "Wait For Job"
8508
+ }, async ({ jobId, kind, projectId, timeoutMs }) => {
8509
+ return toToolSuccess(await waitForJob({
8510
+ jobId,
8511
+ kind,
8512
+ projectId,
8513
+ timeoutMs
8514
+ }, dependencies));
6512
8515
  });
6513
- server.registerTool("trigger_hot_reload", {
6514
- description: "Trigger an Unreal Hot Reload recompile-and-reload of the loaded game modules for a projectId. Use on macOS and Linux, where Live Coding does not exist; on Windows prefer trigger_live_compile. Poll with get_compile_status. Tail stream_output_log (LogHotReload) for build output.",
6515
- inputSchema: triggerHotReloadInputSchema,
6516
- title: "Trigger Hot Reload"
8516
+ server.registerTool("cancel_test_run", {
8517
+ description: "Abort an in-progress Unreal automation run for a project by its testRunId. Returns cancelled=true (state cancelled) when a live run was aborted, or cancelled=false (state not_found) when the run is unknown or already finished.",
8518
+ inputSchema: cancelTestRunInputSchema,
8519
+ title: "Cancel Test Run"
8520
+ }, async ({ projectId, testRunId }) => {
8521
+ return toToolSuccess(await cancelTestRun({
8522
+ projectId,
8523
+ testRunId
8524
+ }, dependencies));
8525
+ });
8526
+ server.registerTool("get_editor_state", {
8527
+ description: "Report the registered Unreal Editor's current state for a project: the open map name and package path, the selected actors as { actorPath, label } objects whose actorPath the level tools accept directly, the active editor modes, and whether Play-in-Editor is running. Selected actors are capped per response; selectedActorCount reports the full selection size. activeModes is empty until the level editor has finished initializing, so an empty list right after the editor starts means 'not ready yet', not 'no mode'.",
8528
+ inputSchema: getEditorStateInputSchema,
8529
+ title: "Get Editor State"
6517
8530
  }, async ({ projectId }) => {
6518
- return toToolSuccess(await triggerHotReload(projectId, dependencies));
8531
+ return toToolSuccess(await getEditorState({ projectId }, dependencies));
6519
8532
  });
6520
- server.registerTool("get_compile_status", {
6521
- description: "Poll a compile job started by trigger_live_compile or trigger_hot_reload for a projectId; returns state (compiling, succeeded, failed, unknown_job), error/warning counts and items, and timing once finished. Hot Reload jobs also report restartRequired/restartReason when the change looks structural. Tail stream_output_log (LogLiveCoding, LogHotReload) for detailed build lines.",
6522
- inputSchema: getCompileStatusInputSchema,
6523
- title: "Get Compile Status"
6524
- }, async ({ compileJobId, projectId }) => {
6525
- return toToolSuccess(await getCompileStatus({
6526
- compileJobId,
8533
+ server.registerTool("exec_console_command", {
8534
+ description: "Run an arbitrary Unreal console command in a project's running editor and return the captured console output. Targets the active Play-in-Editor world when PIE is running and the editor world otherwise. This runs with full editor authority — commands such as 'quit' will act on the live editor.",
8535
+ inputSchema: execConsoleCommandInputSchema,
8536
+ title: "Execute Console Command"
8537
+ }, async ({ command, projectId }) => {
8538
+ return toToolSuccess(await execConsoleCommand({
8539
+ command,
6527
8540
  projectId
6528
8541
  }, dependencies));
6529
8542
  });
6530
- server.registerTool("get_crash_callstack", {
6531
- description: "Report structured call stacks for ensures and fatal errors captured in the running editor for a projectId, newest first. Each record carries the failure message, the capturing thread, and per-frame module, symbol and file/line where symbols resolve.",
6532
- inputSchema: getCrashCallstackInputSchema,
6533
- title: "Get Crash Callstack"
6534
- }, async ({ maxFrames, maxRecords, projectId }) => {
6535
- return toToolSuccess(await getCrashCallstack({
6536
- maxFrames,
6537
- maxRecords,
6538
- projectId
8543
+ server.registerTool("get_config_value", {
8544
+ description: "Read one project config value through the running editor's config system, which resolves the full Base*/Default*/Saved hierarchy. Returns the resolved value, the ini it came from, and resolvedFrom ('engine_base', 'project_default', 'saved_user'), and reports present=false for an unset key so an absent value is distinguishable from a present-but-empty one. file is a closed set of known ini names, not a path.",
8545
+ inputSchema: getConfigValueInputSchema,
8546
+ title: "Get Config Value"
8547
+ }, async ({ file, key, projectId, section }) => {
8548
+ return toToolSuccess(await getConfigValue({
8549
+ file,
8550
+ key,
8551
+ projectId,
8552
+ section
6539
8553
  }, dependencies));
6540
8554
  });
6541
- server.registerTool("build_target", {
6542
- description: "Run a full UnrealBuildTool build for a target/configuration/platform as a child process and return pass/fail with parsed error and warning diagnostics. Use for structural changes Live Coding cannot handle (new UPROPERTY/UCLASS, layout changes). Server-side; does not require a running editor.",
6543
- inputSchema: buildTargetInputSchema,
6544
- title: "Build Target"
6545
- }, async (input) => {
6546
- return toToolSuccess(await buildTarget(input, dependencies));
6547
- });
6548
- server.registerTool("generate_project_files", {
6549
- description: "Regenerate IDE project files with UnrealBuildTool (-projectfiles) so newly added modules and classes appear in the project. Returns success and any UBT errors. Server-side; does not require a running editor.",
6550
- inputSchema: generateProjectFilesInputSchema,
6551
- title: "Generate Project Files"
6552
- }, async (input) => {
6553
- return toToolSuccess(await generateProjectFiles(input, dependencies));
6554
- });
6555
- server.registerTool("clean_build", {
6556
- description: "Clean build artifacts (Intermediate/Binaries) for a target with UnrealBuildTool (-Clean) to recover from stale-build issues. Returns the result and any UBT errors. Chain with build_target to rebuild. Server-side; does not require a running editor.",
6557
- inputSchema: cleanBuildInputSchema,
6558
- title: "Clean Build"
6559
- }, async (input) => {
6560
- return toToolSuccess(await cleanBuild(input, dependencies));
8555
+ server.registerTool("set_config_value", {
8556
+ description: "Write one project config value through the running editor's config system and flush it to disk, so the ini is normalised the way the engine expects and the live editor picks the change up without a restart. Writes Config/Default<File>.ini by default, or the Saved/Config user override with scope 'saved_user'. Returns the previous value as the editor resolved it across the whole hierarchy, which is not necessarily what the target layer held: if it came from an engine or default layer, writing it back leaves the key materialised in the layer this tool wrote. Requires a registered editor: a raw file write behind a running editor is clobbered when the editor saves its own config.",
8557
+ inputSchema: setConfigValueInputSchema,
8558
+ title: "Set Config Value"
8559
+ }, async ({ file, key, projectId, scope, section, value }) => {
8560
+ return toToolSuccess(await setConfigValue({
8561
+ file,
8562
+ key,
8563
+ projectId,
8564
+ scope,
8565
+ section,
8566
+ value
8567
+ }, dependencies));
6561
8568
  });
6562
- server.registerTool("cook_content", {
6563
- description: "Start a full offline cook (UnrealEditor-Cmd -run=Cook) for a target platform and return a packageJobId immediately; poll it with get_package_status. Unlike launch_on_device (cook-on-the-fly) this proves the content actually cooks, surfacing missing references, unfixed redirectors and platform shader failures. Runs for minutes to tens of minutes. Refuses while the project editor is running unless force is true. Server-side; no running editor required.",
6564
- inputSchema: cookContentInputSchema,
6565
- title: "Cook Content"
6566
- }, async (input) => {
6567
- return toToolSuccess(await cookContent(input, dependencies));
8569
+ server.registerTool("list_config_section", {
8570
+ description: "Dump one config section as key/value pairs as the running editor resolves it. Paged: pass the previous response nextCursor for the next page; totalCount reports the full key count.",
8571
+ inputSchema: listConfigSectionInputSchema,
8572
+ title: "List Config Section"
8573
+ }, async ({ cursor, file, maxResults, projectId, section }) => {
8574
+ return toToolSuccess(await listConfigSection({
8575
+ cursor,
8576
+ file,
8577
+ maxResults,
8578
+ projectId,
8579
+ section
8580
+ }, dependencies));
6568
8581
  });
6569
- server.registerTool("package_project", {
6570
- description: "Start a full package via RunUAT BuildCookRun (build + cook + stage + pak + archive) for a platform, configuration and archive directory, returning a packageJobId immediately; poll it with get_package_status. Runs for minutes to tens of minutes. Refuses while the project editor is running unless force is true. Server-side; no running editor required.",
6571
- inputSchema: packageProjectInputSchema,
6572
- title: "Package Project"
6573
- }, async (input) => {
6574
- return toToolSuccess(await packageProject(input, dependencies));
8582
+ server.registerTool("get_class_reflection", {
8583
+ description: "Reflect a UCLASS or USTRUCT in a project's running Unreal Editor: parent type, implemented interfaces, class flags, and the declared properties (name, C++ type, UPROPERTY specifiers, metadata) and functions (UFUNCTION specifiers, parameters, metadata). Use it to learn a type's API without reading headers. Properties and functions page independently — pass the previous response nextPropertyCursor/nextFunctionCursor to continue.",
8584
+ inputSchema: getClassReflectionInputSchema,
8585
+ title: "Get Class Reflection"
8586
+ }, async ({ className, functionCursor, includeInherited, maxFunctions, maxProperties, projectId, propertyCursor }) => {
8587
+ return toToolSuccess(await getClassReflection({
8588
+ className,
8589
+ functionCursor,
8590
+ includeInherited,
8591
+ maxFunctions,
8592
+ maxProperties,
8593
+ projectId,
8594
+ propertyCursor
8595
+ }, dependencies));
6575
8596
  });
6576
- server.registerTool("run_editor_commandlet", {
6577
- description: "Start an editor commandlet (UnrealEditor-Cmd -run=<name>) with an argv array and return a packageJobId; poll it with get_package_status. Unlocks the maintenance commandlets you reach for after a failed cook — ResavePackages, FixupRedirects, DataValidation. The commandlet name must be identifier characters only and arguments are passed as separate argv entries without a shell; -run= and -Project= are set by the tool and rejected as arguments. A commandlet can modify or delete project assets, so it refuses to run while the project editor is running unless force is true.",
6578
- inputSchema: runEditorCommandletInputSchema,
6579
- title: "Run Editor Commandlet"
6580
- }, async (input) => {
6581
- return toToolSuccess(await runEditorCommandlet(input, dependencies));
8597
+ server.registerTool("save_dirty_packages", {
8598
+ description: "Save the unsaved (dirty) map and content packages in the registered Unreal Editor for a project, so changes made by other tools are persisted to disk. Returns which packages were saved and which are still dirty. Packages that have never been written to disk are skipped rather than prompting the editor for a filename.",
8599
+ inputSchema: saveDirtyPackagesInputSchema,
8600
+ title: "Save Dirty Packages"
8601
+ }, async ({ projectId, saveContentPackages, saveMapPackages }) => {
8602
+ return toToolSuccess(await saveDirtyPackages({
8603
+ projectId,
8604
+ saveContentPackages,
8605
+ saveMapPackages
8606
+ }, dependencies));
6582
8607
  });
6583
- server.registerTool("analyze_trace", {
6584
- description: "Analyze a completed .utrace (the path stop_insights_trace returns) headlessly with the engine's Unreal Insights analyzer and return a bounded, readable summary: frame-time p50/p90/p99, the worst N hitches with timestamps, a CPU vs GPU time split, and top-N timing scopes by inclusive and exclusive time. Memory and LLM-tag totals are deliberately not reported — they need a separate analysis pass. Resolve the engine with engineVersion or projectPath. Every list is top-N and the response is byte-capped, with truncated naming what was shortened. Returns state 'unsupported' when the installed engine ships no Insights analyzer for this host.",
6585
- inputSchema: analyzeTraceInputSchema,
6586
- title: "Analyze Trace"
6587
- }, async (input) => {
6588
- return toToolSuccess(await analyzeTrace(input, dependencies));
8608
+ server.registerTool("get_stat_snapshot", {
8609
+ description: "Sample a project's running Unreal editor for core performance counters: frames per second, frame time, game/render thread times, and process memory usage. Single snapshot — call again to sample a later frame.",
8610
+ inputSchema: getStatSnapshotInputSchema,
8611
+ title: "Get Stat Snapshot"
8612
+ }, async ({ projectId }) => {
8613
+ return toToolSuccess(await getStatSnapshot(projectId, dependencies));
6589
8614
  });
6590
- server.registerTool("get_package_status", {
6591
- description: "Poll a job started by cook_content, package_project, or run_editor_commandlet. Returns state ('running', 'succeeded', 'failed', 'cancelled', or 'unknown_job' for an unknown/evicted id), structured cook/UAT error and warning diagnostics, truncation flags, exit code, and timing once finished.",
6592
- inputSchema: getPackageStatusInputSchema,
6593
- title: "Get Package Status"
6594
- }, async ({ packageJobId }) => {
6595
- return toToolSuccess(getPackageStatus({ packageJobId }, dependencies));
8615
+ server.registerTool("capture_viewport", {
8616
+ description: "Capture the registered Unreal Editor's active viewport to a PNG on the editor host and return the absolute file path plus the image dimensions. The image bytes are never inlined in the response.",
8617
+ inputSchema: captureViewportInputSchema,
8618
+ title: "Capture Viewport"
8619
+ }, async ({ projectId }) => {
8620
+ return toToolSuccess(await captureViewport({ projectId }, dependencies));
6596
8621
  });
6597
- server.registerTool("cancel_package_job", {
6598
- description: "Abort an in-flight cook, package, or commandlet job by its packageJobId. Returns cancelled=true (state cancelled) when a live job was killed, or cancelled=false with the job current state (or unknown_job) otherwise.",
6599
- inputSchema: cancelPackageJobInputSchema,
6600
- title: "Cancel Package Job"
6601
- }, async ({ packageJobId }) => {
6602
- return toToolSuccess(cancelPackageJob({ packageJobId }, dependencies));
8622
+ server.registerTool("start_insights_trace", {
8623
+ description: "Start an Unreal Insights trace capture in a project's running editor and return the .utrace file path being written. Returns already_tracing (with the current path) when a capture is already running.",
8624
+ inputSchema: startInsightsTraceInputSchema,
8625
+ title: "Start Insights Trace"
8626
+ }, async ({ channels, fileName, projectId }) => {
8627
+ return toToolSuccess(await startInsightsTrace({
8628
+ channels,
8629
+ fileName,
8630
+ projectId
8631
+ }, dependencies));
6603
8632
  });
6604
- server.registerTool("run_clang_tidy", {
6605
- description: "Run clang-tidy over a project's synced compile_commands.json and return structured findings (file, line, column, check, severity, message), catching issues before a compile. Report only; does not apply fixes. Server-side; does not require a running editor.",
6606
- inputSchema: runClangTidyInputSchema,
6607
- title: "Run clang-tidy"
6608
- }, async (input) => {
6609
- return toToolSuccess(await runClangTidy(input, dependencies));
8633
+ server.registerTool("stop_insights_trace", {
8634
+ description: "Stop the Unreal Insights trace running in a project's editor and return the completed .utrace file path. Returns not_tracing when no capture was running, and fails with trace_not_ready (retryable) when called before the capture has finished opening.",
8635
+ inputSchema: stopInsightsTraceInputSchema,
8636
+ title: "Stop Insights Trace"
8637
+ }, async ({ projectId }) => {
8638
+ return toToolSuccess(await stopInsightsTrace(projectId, dependencies));
6610
8639
  });
6611
- server.registerTool("create_cpp_class", {
6612
- description: "Scaffold a new C++ class in a projectId the way the editor New C++ Class wizard does (header, source, GENERATED_BODY, module API macro, project files). Generation is scheduled on the editor game thread and returns a createClassJobId; poll it with get_create_class_status.",
6613
- inputSchema: createCppClassInputSchema,
6614
- title: "Create C++ Class"
6615
- }, async ({ className, classPath, moduleName, parentClass, projectId }) => {
6616
- return toToolSuccess(await createCppClass({
8640
+ server.registerTool("get_cdo_defaults", {
8641
+ description: "Read the Class Default Object property values for a UCLASS in a project's running Unreal Editor, so configured defaults are visible without opening the asset or header. Values are exported as Unreal property text, so nested structs and arrays come back fully expanded. Results are paged: pass the previous response nextCursor to fetch the next page.",
8642
+ inputSchema: getCdoDefaultsInputSchema,
8643
+ title: "Get CDO Defaults"
8644
+ }, async ({ className, cursor, includeInherited, maxResults, nameFilter, projectId }) => {
8645
+ return toToolSuccess(await getCdoDefaults({
6617
8646
  className,
6618
- classPath,
6619
- moduleName,
6620
- parentClass,
8647
+ cursor,
8648
+ includeInherited,
8649
+ maxResults,
8650
+ nameFilter,
6621
8651
  projectId
6622
8652
  }, dependencies));
6623
8653
  });
6624
- server.registerTool("get_create_class_status", {
6625
- description: "Poll a C++ class generation job started by create_cpp_class for a projectId; returns state (creating, succeeded, failed, unknown_job), the generated headerPath and sourcePath, whether the editor hot-reloaded the class, and timing once finished.",
6626
- inputSchema: getCreateClassStatusInputSchema,
6627
- title: "Get Create Class Status"
6628
- }, async ({ createClassJobId, projectId }) => {
6629
- return toToolSuccess(await getCreateClassStatus({
6630
- createClassJobId,
6631
- projectId
8654
+ server.registerTool("list_actors", {
8655
+ description: "Enumerate actors in the editor's currently loaded level(s), optionally filtered by class, name substring, tag, or level. Returns each actor's canonical actorPath (the identifier every other level tool takes), display label, class, level, and World Outliner folder. Results are paged: pass the previous response nextCursor to fetch the next page, and totalCount reports the full match count even when a page truncates. Use this to find an actor before calling get_actor_details.",
8656
+ inputSchema: listActorsInputSchema,
8657
+ title: "List Actors"
8658
+ }, async ({ classNames, cursor, levelName, maxResults, nameFilter, projectId, tag }) => {
8659
+ return toToolSuccess(await listActors({
8660
+ classNames,
8661
+ cursor,
8662
+ levelName,
8663
+ maxResults,
8664
+ nameFilter,
8665
+ projectId,
8666
+ tag
6632
8667
  }, dependencies));
6633
8668
  });
6634
- server.registerTool("stream_output_log", {
6635
- description: "Poll a bounded batch of Unreal Output Log events for a project and continue by calling again with the returned cursor.",
6636
- inputSchema: streamOutputLogInputSchema,
6637
- title: "Stream Output Log"
6638
- }, async ({ categoryAllow, categoryDeny, cursor, maxEvents, minVerbosity, projectId, textContains, textPattern }) => {
6639
- return toToolSuccess(await streamLogs({
6640
- cursor,
6641
- filters: {
6642
- categoryAllow,
6643
- categoryDeny,
6644
- minVerbosity,
6645
- textContains,
6646
- textPattern
6647
- },
6648
- maxEvents,
8669
+ server.registerTool("get_actor_details", {
8670
+ description: "Inspect one actor in the loaded level by its actorPath: world transform, attached component hierarchy (each component's name, class, attachment parent, and relative transform), and reflected UPROPERTY values. Property values use the same ExportText format get_cdo_defaults emits, so a value read here can be written back verbatim. Components and properties page independently — pass nextComponentCursor / nextPropertyCursor to continue each list. Inherited properties are excluded unless includeInherited is true.",
8671
+ inputSchema: getActorDetailsInputSchema,
8672
+ title: "Get Actor Details"
8673
+ }, async ({ actorPath, componentCursor, includeInherited, maxResults, projectId, propertyCursor }) => {
8674
+ return toToolSuccess(await getActorDetails({
8675
+ actorPath,
8676
+ componentCursor,
8677
+ includeInherited,
8678
+ maxResults,
6649
8679
  projectId,
6650
- registry: dependencies.registry,
6651
- sessionManager: dependencies.logSessionManager,
6652
- source: "output_log"
6653
- }));
8680
+ propertyCursor
8681
+ }, dependencies));
6654
8682
  });
6655
- server.registerTool("stream_message_log", {
6656
- description: "Poll a bounded batch from a named Unreal Message Log listing and continue by calling again with the returned cursor.",
6657
- inputSchema: streamMessageLogInputSchema,
6658
- title: "Stream Message Log"
6659
- }, async ({ cursor, listingName, maxEvents, minSeverity, projectId, textContains, textPattern }) => {
6660
- return toToolSuccess(await streamLogs({
6661
- cursor,
6662
- filters: {
6663
- listingName,
6664
- minSeverity,
6665
- textContains,
6666
- textPattern
6667
- },
6668
- maxEvents,
8683
+ server.registerTool("get_current_level", {
8684
+ description: "Report the level the editor currently has open — its short name and package path — plus every streaming level registered on that world with its loaded and visible state. worldPartition=true means the map streams cells through World Partition rather than through the listed ULevelStreaming entries, so the streamingLevels list will usually be empty for such a map. Returns no level fields when the editor has no world loaded.",
8685
+ inputSchema: getCurrentLevelInputSchema,
8686
+ title: "Get Current Level"
8687
+ }, async ({ projectId }) => {
8688
+ return toToolSuccess(await getCurrentLevel({ projectId }, dependencies));
8689
+ });
8690
+ server.registerTool("spawn_actor", {
8691
+ description: "Spawn one or more actors into the editor's loaded level. Each entry takes a classPath (native or Blueprint generated class) and an optional transform, label, outliner folder, and tags. The whole batch runs inside a single editor transaction, so a human pressing Ctrl+Z removes every actor the call spawned as one step, and save_dirty_packages will report the level afterwards. Returns a per-entry result carrying the new actorPath or the reason that entry failed; a failed entry does not abort the rest of the batch. Pass dryRun: true to validate the batch and see what would be spawned without changing anything.",
8692
+ inputSchema: spawnActorInputSchema,
8693
+ title: "Spawn Actor"
8694
+ }, async ({ dryRun, projectId, spawns }) => {
8695
+ return toToolSuccess(await spawnActor({
8696
+ dryRun,
6669
8697
  projectId,
6670
- registry: dependencies.registry,
6671
- sessionManager: dependencies.logSessionManager,
6672
- source: "message_log"
6673
- }));
8698
+ spawns
8699
+ }, dependencies));
6674
8700
  });
6675
- server.registerTool("stream_device_output_log", {
6676
- description: "Poll a bounded batch of Unreal device-output log events and continue by calling again with the returned cursor.",
6677
- inputSchema: streamDeviceOutputLogInputSchema,
6678
- title: "Stream Device Output Log"
6679
- }, async ({ cursor, deviceId, deviceName, maxEvents, projectId, textContains, textPattern }) => {
6680
- return toToolSuccess(await streamLogs({
6681
- cursor,
6682
- filters: {
6683
- deviceId,
6684
- deviceName,
6685
- textContains,
6686
- textPattern
6687
- },
6688
- maxEvents,
8701
+ server.registerTool("destroy_actor", {
8702
+ description: "Destroy one or more actors in the loaded level, addressed by the actorPath list_actors returns. The whole batch runs inside a single editor transaction, so Ctrl+Z restores every actor the call destroyed as one step. Returns a per-entry result; an actorPath that no longer resolves fails only its own entry. Pass dryRun: true to check the paths and see what would be destroyed without changing anything.",
8703
+ inputSchema: destroyActorInputSchema,
8704
+ title: "Destroy Actor"
8705
+ }, async ({ actorPaths, dryRun, projectId }) => {
8706
+ return toToolSuccess(await destroyActor({
8707
+ actorPaths,
8708
+ dryRun,
8709
+ projectId
8710
+ }, dependencies));
8711
+ });
8712
+ server.registerTool("set_actor_transform", {
8713
+ description: "Move, rotate, and/or scale one or more actors in the loaded level. Each entry addresses an actor by actorPath and supplies any of location, rotation, and scale — an omitted component keeps its current value. The whole batch runs inside a single editor transaction, so Ctrl+Z restores every original transform as one step. Returns a per-entry result; pass dryRun: true to check the paths without moving anything.",
8714
+ inputSchema: setActorTransformInputSchema,
8715
+ title: "Set Actor Transform"
8716
+ }, async ({ dryRun, projectId, transforms }) => {
8717
+ return toToolSuccess(await setActorTransform({
8718
+ dryRun,
6689
8719
  projectId,
6690
- registry: dependencies.registry,
6691
- sessionManager: dependencies.logSessionManager,
6692
- source: "device_output_log"
6693
- }));
8720
+ transforms
8721
+ }, dependencies));
6694
8722
  });
6695
- server.registerTool("start_pie", {
6696
- description: "Start a Play-in-Editor session in the registered Unreal editor for a project; play begins on the next editor tick (async). Returns starting/running/unsupported.",
6697
- inputSchema: startPieInputSchema,
6698
- title: "Start Play-in-Editor"
6699
- }, async ({ map, mode, netMode, numClients, projectId, runUnderOneProcess }) => {
6700
- return toToolSuccess(await startPie({
6701
- map,
6702
- mode,
6703
- netMode,
6704
- numClients,
8723
+ server.registerTool("set_actor_property", {
8724
+ description: "Write reflected UPROPERTY values on actors or their components in the loaded level. Each entry takes an actorPath, a propertyPath ('bHidden' on the actor, 'StaticMeshComponent.RelativeScale3D' on a component), and a value in the same ExportText format get_actor_details and get_cdo_defaults emit — so you can read a value, edit it, and write it back without translating. Properties marked EditConst or not exposed for editing are rejected with an explicit error rather than silently ignored. The whole batch runs in one transaction; pass dryRun: true to resolve paths and check coercion without writing.",
8725
+ inputSchema: setActorPropertyInputSchema,
8726
+ title: "Set Actor Property"
8727
+ }, async ({ dryRun, projectId, properties }) => {
8728
+ return toToolSuccess(await setActorProperty({
8729
+ dryRun,
6705
8730
  projectId,
6706
- runUnderOneProcess
8731
+ properties
6707
8732
  }, dependencies));
6708
8733
  });
6709
- server.registerTool("get_pie_status", {
6710
- description: "Report the state of the Play-in-Editor session started by start_pie for a project: starting, running, stopped, or none. Reports running only after PIE has actually begun.",
6711
- inputSchema: getPieStatusInputSchema,
6712
- title: "Get Play-in-Editor Status"
6713
- }, async ({ pieSessionId, projectId }) => {
6714
- return toToolSuccess(await getPieStatus({
6715
- pieSessionId,
8734
+ server.registerTool("select_actors", {
8735
+ description: "Set the editor's actor selection — the write-side counterpart to get_editor_state, using the same actorPath identifiers list_actors returns. An empty actorPaths list clears the selection; addToSelection adds to it instead of replacing it. Runs inside a transaction, so Ctrl+Z restores the previous selection. Returns the resulting selectedActorCount plus a per-entry result for any path that no longer resolves.",
8736
+ inputSchema: selectActorsInputSchema,
8737
+ title: "Select Actors"
8738
+ }, async ({ actorPaths, addToSelection, dryRun, projectId }) => {
8739
+ return toToolSuccess(await selectActors({
8740
+ actorPaths,
8741
+ addToSelection,
8742
+ dryRun,
6716
8743
  projectId
6717
8744
  }, dependencies));
6718
8745
  });
6719
- server.registerTool("stop_pie", {
6720
- description: "End the active Play-in-Editor session for a project. Returns stopped=true when a session was ended, or stopped=false (state none) when nothing was playing.",
6721
- inputSchema: stopPieInputSchema,
6722
- title: "Stop Play-in-Editor"
6723
- }, async ({ pieSessionId, projectId }) => {
6724
- return toToolSuccess(await stopPie({
6725
- pieSessionId,
8746
+ server.registerTool("undo", {
8747
+ description: "Undo the editor's most recent transaction — the same action as pressing Ctrl+Z in the editor — and report the title of the transaction that was undone. Use this to roll back your own level edits without a human in the loop. Returns state 'nothing_to_undo' when the transaction buffer is empty. Note this undoes whatever is at the head of the buffer, which may be a human's edit rather than yours, so check the returned transactionTitle.",
8748
+ inputSchema: undoInputSchema,
8749
+ title: "Undo"
8750
+ }, async ({ projectId }) => {
8751
+ return toToolSuccess(await undo({ projectId }, dependencies));
8752
+ });
8753
+ server.registerTool("redo", {
8754
+ description: "Redo the editor's most recently undone transaction — the same action as pressing Ctrl+Y in the editor — and report the title of the transaction that was redone. Returns state 'nothing_to_redo' when there is nothing to reapply.",
8755
+ inputSchema: redoInputSchema,
8756
+ title: "Redo"
8757
+ }, async ({ projectId }) => {
8758
+ return toToolSuccess(await redo({ projectId }, dependencies));
8759
+ });
8760
+ server.registerTool("open_level", {
8761
+ description: "Open a level in the editor by package name. Loading a map tears down and rebuilds the world, which takes far longer than a bridge request can wait, so this only accepts the job: it returns state 'opening' with an openLevelJobId to poll with get_open_level_status. Unsaved changes in the current world are discarded unless saveDirtyPackages is true. This is NOT undoable — loading a map clears the editor's transaction buffer, so undo cannot bring the previous level back.",
8762
+ inputSchema: openLevelInputSchema,
8763
+ title: "Open Level"
8764
+ }, async ({ dryRun, levelPath, projectId, saveDirtyPackages }) => {
8765
+ return toToolSuccess(await openLevel({
8766
+ dryRun,
8767
+ levelPath,
8768
+ projectId,
8769
+ saveDirtyPackages
8770
+ }, dependencies));
8771
+ });
8772
+ server.registerTool("get_open_level_status", {
8773
+ description: "Poll a level load started by open_level for a projectId; returns state (opening, succeeded, failed, unknown_job), the loaded levelPath, and timing once finished. Poll until the state leaves 'opening' before issuing further level tools — actor paths from the previous world do not survive the load.",
8774
+ inputSchema: getOpenLevelStatusInputSchema,
8775
+ title: "Get Open Level Status"
8776
+ }, async ({ openLevelJobId, projectId }) => {
8777
+ return toToolSuccess(await getOpenLevelStatus({
8778
+ openLevelJobId,
6726
8779
  projectId
6727
8780
  }, dependencies));
6728
8781
  });
6729
- server.registerTool("list_launch_devices", {
6730
- description: "List the target devices the registered Unreal editor can launch onto (iOS, Android, etc.), with each device id, name, platform, and connected/authorized state. Pick a deviceId for launch_on_device.",
6731
- inputSchema: listLaunchDevicesInputSchema,
6732
- title: "List Launch Devices"
6733
- }, async ({ projectId }) => {
6734
- return toToolSuccess(await listLaunchDevices({ projectId }, dependencies));
8782
+ server.registerTool("get_source_control_status", {
8783
+ description: "Report the editor's source control provider and the per-file state of up to 64 assets. Answered from the provider's state cache, so it costs no network round trip and returns inline. enabled distinguishes 'no source control configured' from 'configured, and this file is simply not checked out'; per-file state is one of checked_out_by_me, checked_out_by_other (with checkedOutBy naming the holder), marked_for_add, not_checked_out, not_in_depot, unknown. A file the editor has never queried reports 'unknown' — call refresh_source_control_status to fetch its real state from the server. Call this before any asset write on a team project: under Perforce or Git-LFS file locking a .uasset stays read-only until checked out, and the write otherwise fails later at save time.",
8784
+ inputSchema: getSourceControlStatusInputSchema,
8785
+ title: "Get Source Control Status"
8786
+ }, async ({ assetPaths, projectId }) => {
8787
+ return toToolSuccess(await getSourceControlStatus({
8788
+ assetPaths,
8789
+ projectId
8790
+ }, dependencies));
6735
8791
  });
6736
- server.registerTool("launch_on_device", {
6737
- description: "Launch (cook-on-the-fly + deploy, not package) the current project onto a connected target device by deviceId from list_launch_devices. Returns a launchSessionId and starting/unsupported state; deploy proceeds asynchronously.",
6738
- inputSchema: launchOnDeviceInputSchema,
6739
- title: "Launch On Device"
6740
- }, async ({ deviceId, map, projectId }) => {
6741
- return toToolSuccess(await launchOnDevice({
6742
- deviceId,
6743
- map,
8792
+ server.registerTool("refresh_source_control_status", {
8793
+ description: "Re-read the depot state of up to 64 assets from the source control server, so a later get_source_control_status reports something better than 'unknown'. This is a network round trip to the provider and runs far past what a bridge request can wait for, so it only accepts the job: it returns state 'accepted' with a sourceControlJobId to poll with get_source_control_job_status (or wait_for_job with kind source_control).",
8794
+ inputSchema: refreshSourceControlStatusInputSchema,
8795
+ title: "Refresh Source Control Status"
8796
+ }, async ({ assetPaths, projectId }) => {
8797
+ return toToolSuccess(await refreshSourceControlStatus({
8798
+ assetPaths,
6744
8799
  projectId
6745
8800
  }, dependencies));
6746
8801
  });
6747
- server.registerTool("list_automation_tests", {
6748
- description: "List the automation tests registered in a project's running Unreal Editor, with optional name and flag filters; returns each test's full name, display name, flags, and test type.",
6749
- inputSchema: listAutomationTestsInputSchema,
6750
- title: "List Automation Tests"
6751
- }, async ({ cursor, flags, maxResults, nameFilter, projectId }) => {
6752
- return toToolSuccess(await listAutomationTests({
6753
- cursor,
6754
- flags,
6755
- maxResults,
6756
- nameFilter,
8802
+ server.registerTool("checkout_assets", {
8803
+ description: "Check up to 64 assets out of source control so they become writable. This is a network round trip to the provider and runs far past what a bridge request can wait for, so it only accepts the job: it returns state 'accepted' with a sourceControlJobId to poll with get_source_control_job_status (or wait_for_job with kind source_control). The poll reports per-item results with successCount / failureCount — one asset the provider refuses does not abort the rest. This checks out only; it never submits, and a checked-out asset stays checked out until a human submits or reverts it.",
8804
+ inputSchema: checkoutAssetsInputSchema,
8805
+ title: "Checkout Assets"
8806
+ }, async ({ assetPaths, projectId }) => {
8807
+ return toToolSuccess(await checkoutAssets({
8808
+ assetPaths,
6757
8809
  projectId
6758
8810
  }, dependencies));
6759
8811
  });
6760
- server.registerTool("run_automation_tests", {
6761
- description: "Start an Unreal automation run (unit, smoke, and functional/BP scene tests) for a project and return a testRunId; requires at least one of testNames or nameFilter. Poll progress separately via stream_message_log on the AutomationTesting listing.",
6762
- inputSchema: runAutomationTestsInputSchema,
6763
- title: "Run Automation Tests"
6764
- }, async ({ flags, nameFilter, projectId, testNames }) => {
6765
- return toToolSuccess(await runAutomationTests({
6766
- flags,
6767
- nameFilter,
8812
+ server.registerTool("get_source_control_job_status", {
8813
+ description: "Poll a source control job started by checkout_assets or refresh_source_control_status for a projectId; returns state (running, succeeded, failed, unknown_job), which operation it was, and once finished the per-file results with successCount / failureCount and timing. Poll until the state leaves 'running' before writing to any asset in the batch.",
8814
+ inputSchema: getSourceControlJobStatusInputSchema,
8815
+ title: "Get Source Control Job Status"
8816
+ }, async ({ projectId, sourceControlJobId }) => {
8817
+ return toToolSuccess(await getSourceControlJobStatus({
6768
8818
  projectId,
6769
- testNames
8819
+ sourceControlJobId
6770
8820
  }, dependencies));
6771
8821
  });
6772
- server.registerTool("get_test_run_status", {
6773
- description: "Poll an automation run started by run_automation_tests by its testRunId; returns the run state ('running', 'complete', or 'unknown_run' for an unknown/expired id), aggregate pass/fail/skip counts, and structured per-test results with their log entries. Results are paged: pass the previous response nextCursor to fetch the next page (totalCount reports the full result count).",
6774
- inputSchema: getTestRunStatusInputSchema,
6775
- title: "Get Test Run Status"
6776
- }, async ({ cursor, maxResults, projectId, testRunId }) => {
6777
- return toToolSuccess(await getTestRunStatus({
8822
+ server.registerTool("find_assets", {
8823
+ description: "Query a project's Unreal Asset Registry for assets by class and/or content path, without loading them; returns each match's name, class, package name, package path, and object path. Requires at least one of classNames or packagePaths — an unfiltered query would stall the editor enumerating every asset. Results are paged: pass the previous response nextCursor to fetch the next page (totalCount reports the full match count). scanning=true means the registry is still indexing, so an empty result does not prove the asset is absent.",
8824
+ inputSchema: findAssetsInputSchema,
8825
+ title: "Find Assets"
8826
+ }, async ({ classNames, cursor, maxResults, nameFilter, packagePaths, projectId, recursiveClasses, recursivePaths }) => {
8827
+ return toToolSuccess(await findAssets({
8828
+ classNames,
6778
8829
  cursor,
6779
8830
  maxResults,
8831
+ nameFilter,
8832
+ packagePaths,
6780
8833
  projectId,
6781
- testRunId
8834
+ recursiveClasses,
8835
+ recursivePaths
6782
8836
  }, dependencies));
6783
8837
  });
6784
- server.registerTool("wait_for_job", {
6785
- description: `Block server-side until an async job reaches a terminal state, then return the payload its get_*_status tool would have returned under 'status'. Use instead of a poll loop after trigger_live_compile, trigger_hot_reload (kind 'compile'), create_cpp_class ('create_class'), run_automation_tests ('test_run'), or start_pie ('pie'). kind is required — job ids carry no type tag. outcome is 'completed', 'timed_out' (the last observed status is still returned; call again or poll), or 'unknown_job' (unknown/expired/cancelled id, returned immediately). timeoutMs defaults per kind (compile ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.compile)}ms, create_class ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.create_class)}ms, pie ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.pie)}ms, test_run ${String(WAIT_FOR_JOB_DEFAULT_TIMEOUT_MS.test_run)}ms) and is clamped to ${String(WAIT_FOR_JOB_MAX_TIMEOUT_MS)}ms, so a long automation run may need more than one call. For kind 'test_run' the returned status.results is the first page only — page the rest with get_test_run_status and nextCursor. For kind 'pie' only 'starting' keeps waiting; 'running', 'stopped' and 'none' are all terminal.`,
6786
- inputSchema: waitForJobInputSchema,
6787
- title: "Wait For Job"
6788
- }, async ({ jobId, kind, projectId, timeoutMs }) => {
6789
- return toToolSuccess(await waitForJob({
6790
- jobId,
6791
- kind,
8838
+ server.registerTool("read_data_table", {
8839
+ description: "Read a DataTable asset's contents: the row struct it is typed on, its ordered column list (name plus the same type rendering get_class_reflection emits), and its rows as column-name-to-value maps. Values are ExportText, the format write_data_table_row accepts back, so a value read here round-trips. Rows are paged by name order: pass the previous response nextCursor to fetch the next page (totalRowCount reports the full count). A DataTable is a binary .uasset with no Asset Registry tags describing its rows, so there is no way to read one off disk instead — this tool loads it.",
8840
+ inputSchema: readDataTableInputSchema,
8841
+ title: "Read Data Table"
8842
+ }, async ({ assetPath, cursor, loadIfNeeded, maxRows, projectId, rowNameFilter }) => {
8843
+ return toToolSuccess(await readDataTable({
8844
+ assetPath,
8845
+ cursor,
8846
+ loadIfNeeded,
8847
+ maxRows,
6792
8848
  projectId,
6793
- timeoutMs
8849
+ rowNameFilter
6794
8850
  }, dependencies));
6795
8851
  });
6796
- server.registerTool("cancel_test_run", {
6797
- description: "Abort an in-progress Unreal automation run for a project by its testRunId. Returns cancelled=true (state cancelled) when a live run was aborted, or cancelled=false (state not_found) when the run is unknown or already finished.",
6798
- inputSchema: cancelTestRunInputSchema,
6799
- title: "Cancel Test Run"
6800
- }, async ({ projectId, testRunId }) => {
6801
- return toToolSuccess(await cancelTestRun({
8852
+ server.registerTool("write_data_table_row", {
8853
+ description: "Insert, update, or delete a single DataTable row. Every column name and value is validated against the row struct before anything is written — an unknown column or a value that will not parse rejects the whole write with an error naming the field, so a row is never partially applied and there is no silent coercion. The write runs inside one transaction, so a human at the editor can Ctrl+Z it, and it marks the package dirty without saving: call save_dirty_packages to persist. Deleting a row that does not exist reports rowExisted=false rather than failing. Use dryRun to validate first. For a whole-table replace use import_data_table instead.",
8854
+ inputSchema: writeDataTableRowInputSchema,
8855
+ title: "Write Data Table Row"
8856
+ }, async ({ assetPath, dryRun, operation, projectId, rowName, values }) => {
8857
+ return toToolSuccess(await writeDataTableRow({
8858
+ assetPath,
8859
+ dryRun,
8860
+ operation,
6802
8861
  projectId,
6803
- testRunId
8862
+ rowName,
8863
+ values
6804
8864
  }, dependencies));
6805
8865
  });
6806
- server.registerTool("get_editor_state", {
6807
- description: "Report the registered Unreal Editor's current state for a project: the open map name and package path, the selected actors as { actorPath, label } objects whose actorPath the level tools accept directly, the active editor modes, and whether Play-in-Editor is running. Selected actors are capped per response; selectedActorCount reports the full selection size. activeModes is empty until the level editor has finished initializing, so an empty list right after the editor starts means 'not ready yet', not 'no mode'.",
6808
- inputSchema: getEditorStateInputSchema,
6809
- title: "Get Editor State"
6810
- }, async ({ projectId }) => {
6811
- return toToolSuccess(await getEditorState({ projectId }, dependencies));
8866
+ server.registerTool("export_data_table", {
8867
+ description: "Serialize a whole DataTable through the engine's own JSON or CSV exporter. Returned in chunks by character offset because the engine produces one string rather than something row-addressable: concatenate the chunks in cursor order to reassemble, and note a single chunk is not valid JSON or CSV on its own. Use read_data_table when you want structured, per-row access; use this when you want the table in the same text form the editor's own export produces.",
8868
+ inputSchema: exportDataTableInputSchema,
8869
+ title: "Export Data Table"
8870
+ }, async ({ assetPath, cursor, format, loadIfNeeded, projectId }) => {
8871
+ return toToolSuccess(await exportDataTable({
8872
+ assetPath,
8873
+ cursor,
8874
+ format,
8875
+ loadIfNeeded,
8876
+ projectId
8877
+ }, dependencies));
6812
8878
  });
6813
- server.registerTool("exec_console_command", {
6814
- description: "Run an arbitrary Unreal console command in a project's running editor and return the captured console output. Targets the active Play-in-Editor world when PIE is running and the editor world otherwise. This runs with full editor authority — commands such as 'quit' will act on the live editor.",
6815
- inputSchema: execConsoleCommandInputSchema,
6816
- title: "Execute Console Command"
6817
- }, async ({ command, projectId }) => {
6818
- return toToolSuccess(await execConsoleCommand({
6819
- command,
8879
+ server.registerTool("import_data_table", {
8880
+ description: "REPLACE every row of a DataTable from a JSON or CSV payload, using the engine's own importer. This is destructive: any row not present in the content is deleted, so it is the wrong tool for changing one value — use write_data_table_row for that. The whole payload travels in one bridge frame, so a table beyond the content character bound cannot be imported this way. Runs inside one transaction (Ctrl+Z reverses it) and marks the package dirty without saving. Rows the importer rejects come back in problems while the rest still apply, so check problemCount even on success; dryRun reports the row count and problems without replacing anything.",
8881
+ inputSchema: importDataTableInputSchema,
8882
+ title: "Import Data Table"
8883
+ }, async ({ assetPath, content, dryRun, format, projectId }) => {
8884
+ return toToolSuccess(await importDataTable({
8885
+ assetPath,
8886
+ content,
8887
+ dryRun,
8888
+ format,
6820
8889
  projectId
6821
8890
  }, dependencies));
6822
8891
  });
6823
- server.registerTool("get_config_value", {
6824
- description: "Read one project config value through the running editor's config system, which resolves the full Base*/Default*/Saved hierarchy. Returns the resolved value, the ini it came from, and resolvedFrom ('engine_base', 'project_default', 'saved_user'), and reports present=false for an unset key so an absent value is distinguishable from a present-but-empty one. file is a closed set of known ini names, not a path.",
6825
- inputSchema: getConfigValueInputSchema,
6826
- title: "Get Config Value"
6827
- }, async ({ file, key, projectId, section }) => {
6828
- return toToolSuccess(await getConfigValue({
6829
- file,
6830
- key,
8892
+ server.registerTool("create_data_table", {
8893
+ description: "Create a new empty DataTable asset backed by a row struct. The struct is fixed at creation — UDataTable can have its RowStruct swapped later, but that reinterprets existing rows through the new layout, so the bridge does not expose it; create a new table instead. The struct must derive FTableRowBase, and creation fails if an asset already exists at the path. The new table is marked dirty but not written to disk: call save_dirty_packages to persist it, or it disappears when the editor closes. Use read_data_table to confirm the column set the struct produced.",
8894
+ inputSchema: createDataTableInputSchema,
8895
+ title: "Create Data Table"
8896
+ }, async ({ assetPath, dryRun, projectId, rowStructPath }) => {
8897
+ return toToolSuccess(await createDataTable({
8898
+ assetPath,
8899
+ dryRun,
6831
8900
  projectId,
6832
- section
8901
+ rowStructPath
6833
8902
  }, dependencies));
6834
8903
  });
6835
- server.registerTool("set_config_value", {
6836
- description: "Write one project config value through the running editor's config system and flush it to disk, so the ini is normalised the way the engine expects and the live editor picks the change up without a restart. Writes Config/Default<File>.ini by default, or the Saved/Config user override with scope 'saved_user'. Returns the previous value as the editor resolved it across the whole hierarchy, which is not necessarily what the target layer held: if it came from an engine or default layer, writing it back leaves the key materialised in the layer this tool wrote. Requires a registered editor: a raw file write behind a running editor is clobbered when the editor saves its own config.",
6837
- inputSchema: setConfigValueInputSchema,
6838
- title: "Set Config Value"
6839
- }, async ({ file, key, projectId, scope, section, value }) => {
6840
- return toToolSuccess(await setConfigValue({
6841
- file,
6842
- key,
8904
+ server.registerTool("rename_data_table", {
8905
+ description: "Rename a DataTable, move it to another package path, or both. Goes through the editor's asset tools, so references from other assets are fixed up and a redirector is left at the old path to keep hard references resolving. Renaming is not a transaction the editor can Ctrl+Z — it rewrites packages on disk. Use dryRun to check the destination is free first.",
8906
+ inputSchema: renameDataTableInputSchema,
8907
+ title: "Rename Data Table"
8908
+ }, async ({ assetPath, destinationPath, dryRun, newName, projectId }) => {
8909
+ return toToolSuccess(await renameDataTable({
8910
+ assetPath,
8911
+ destinationPath,
8912
+ dryRun,
8913
+ newName,
8914
+ projectId
8915
+ }, dependencies));
8916
+ });
8917
+ server.registerTool("delete_data_table", {
8918
+ description: "Delete a DataTable asset from the project. This is the one DataTable tool that cannot be undone — asset deletion is not a transaction, so there is no Ctrl+Z and no dirty-package step to reconsider at. A table other assets still reference is refused, and those referencers are reported; force deletes anyway and breaks them. Always dryRun first on a table you did not create: it reports the referencers without touching anything.",
8919
+ inputSchema: deleteDataTableInputSchema,
8920
+ title: "Delete Data Table"
8921
+ }, async ({ assetPath, dryRun, force, projectId }) => {
8922
+ return toToolSuccess(await deleteDataTable({
8923
+ assetPath,
8924
+ dryRun,
8925
+ force,
8926
+ projectId
8927
+ }, dependencies));
8928
+ });
8929
+ server.registerTool("rename_data_table_row", {
8930
+ description: "Rename a single row, keeping its position in the table and its values intact. Not the same as an upsert under the new name followed by a delete of the old one: that pair costs two transactions and moves the row to the end. Fails if the row does not exist or the new name is already taken. Runs inside one transaction (Ctrl+Z reverses it) and marks the package dirty without saving. Note that row names are how other assets address rows, so a rename breaks any FDataTableRowHandle pointing at the old name — nothing fixes those up.",
8931
+ inputSchema: renameDataTableRowInputSchema,
8932
+ title: "Rename Data Table Row"
8933
+ }, async ({ assetPath, dryRun, newRowName, projectId, rowName }) => {
8934
+ return toToolSuccess(await renameDataTableRow({
8935
+ assetPath,
8936
+ dryRun,
8937
+ newRowName,
6843
8938
  projectId,
6844
- scope,
6845
- section,
6846
- value
8939
+ rowName
6847
8940
  }, dependencies));
6848
8941
  });
6849
- server.registerTool("list_config_section", {
6850
- description: "Dump one config section as key/value pairs as the running editor resolves it. Paged: pass the previous response nextCursor for the next page; totalCount reports the full key count.",
6851
- inputSchema: listConfigSectionInputSchema,
6852
- title: "List Config Section"
6853
- }, async ({ cursor, file, maxResults, projectId, section }) => {
6854
- return toToolSuccess(await listConfigSection({
6855
- cursor,
6856
- file,
8942
+ server.registerTool("get_asset_dependencies", {
8943
+ description: "Report an asset's package-level dependencies (what it needs) and referencers (what needs it) from the Unreal Asset Registry — the Reference Viewer data — so you can judge the blast radius before changing it. Depth is 1: transitive links are not walked. Each list pages independently via nextDependencyCursor / nextReferencerCursor.",
8944
+ inputSchema: getAssetDependenciesInputSchema,
8945
+ title: "Get Asset Dependencies"
8946
+ }, async ({ assetPath, categories, dependencyCursor, linkage, maxResults, projectId, referencerCursor }) => {
8947
+ return toToolSuccess(await getAssetDependencies({
8948
+ assetPath,
8949
+ categories,
8950
+ dependencyCursor,
8951
+ linkage,
6857
8952
  maxResults,
6858
8953
  projectId,
6859
- section
8954
+ referencerCursor
6860
8955
  }, dependencies));
6861
8956
  });
6862
- server.registerTool("get_class_reflection", {
6863
- description: "Reflect a UCLASS or USTRUCT in a project's running Unreal Editor: parent type, implemented interfaces, class flags, and the declared properties (name, C++ type, UPROPERTY specifiers, metadata) and functions (UFUNCTION specifiers, parameters, metadata). Use it to learn a type's API without reading headers. Properties and functions page independently — pass the previous response nextPropertyCursor/nextFunctionCursor to continue.",
6864
- inputSchema: getClassReflectionInputSchema,
6865
- title: "Get Class Reflection"
6866
- }, async ({ className, functionCursor, includeInherited, maxFunctions, maxProperties, projectId, propertyCursor }) => {
6867
- return toToolSuccess(await getClassReflection({
8957
+ server.registerTool("find_blueprint_references", {
8958
+ description: "Report which Blueprint assets depend on a C++ class, so you can judge whether renaming or removing it will break content. Each hit is either 'subclass' (the Blueprint's parent chain reaches the class) or 'module_dependency' (the Blueprint's package depends on the class's /Script module, which may be through this class or another type in it). Answers from Asset Registry metadata only — no Blueprints are loaded, so per-function and per-property usage is not resolved.",
8959
+ inputSchema: findBlueprintReferencesInputSchema,
8960
+ title: "Find Blueprint References"
8961
+ }, async ({ className, cursor, maxResults, projectId, referenceKinds }) => {
8962
+ return toToolSuccess(await findBlueprintReferences({
6868
8963
  className,
6869
- functionCursor,
6870
- includeInherited,
6871
- maxFunctions,
6872
- maxProperties,
8964
+ cursor,
8965
+ maxResults,
6873
8966
  projectId,
6874
- propertyCursor
8967
+ referenceKinds
6875
8968
  }, dependencies));
6876
8969
  });
6877
- server.registerTool("save_dirty_packages", {
6878
- description: "Save the unsaved (dirty) map and content packages in the registered Unreal Editor for a project, so changes made by other tools are persisted to disk. Returns which packages were saved and which are still dirty. Packages that have never been written to disk are skipped rather than prompting the editor for a filename.",
6879
- inputSchema: saveDirtyPackagesInputSchema,
6880
- title: "Save Dirty Packages"
6881
- }, async ({ projectId, saveContentPackages, saveMapPackages }) => {
6882
- return toToolSuccess(await saveDirtyPackages({
8970
+ server.registerTool("get_blueprint_summary", {
8971
+ description: "Describe what is inside a Blueprint asset: parent class, implemented interfaces, its component hierarchy from the Simple Construction Script, its variables (type, default, category, replication), its functions/events/macros with signatures, and an inventory of its graphs. Use the returned graph names with get_blueprint_graph. By default nothing is loaded — an unloaded Blueprint answers from Asset Registry metadata (parent and generated class only) and reports loaded=false; pass loadIfNeeded to read the full contents. Each list pages independently.",
8972
+ inputSchema: getBlueprintSummaryInputSchema,
8973
+ title: "Get Blueprint Summary"
8974
+ }, async ({ blueprintPath, componentCursor, functionCursor, graphCursor, loadIfNeeded, maxResults, projectId, variableCursor }) => {
8975
+ return toToolSuccess(await getBlueprintSummary({
8976
+ blueprintPath,
8977
+ componentCursor,
8978
+ functionCursor,
8979
+ graphCursor,
8980
+ loadIfNeeded,
8981
+ maxResults,
6883
8982
  projectId,
6884
- saveContentPackages,
6885
- saveMapPackages
8983
+ variableCursor
6886
8984
  }, dependencies));
6887
8985
  });
6888
- server.registerTool("get_stat_snapshot", {
6889
- description: "Sample a project's running Unreal editor for core performance counters: frames per second, frame time, game/render thread times, and process memory usage. Single snapshot — call again to sample a later frame.",
6890
- inputSchema: getStatSnapshotInputSchema,
6891
- title: "Get Stat Snapshot"
6892
- }, async ({ projectId }) => {
6893
- return toToolSuccess(await getStatSnapshot(projectId, dependencies));
6894
- });
6895
- server.registerTool("capture_viewport", {
6896
- description: "Capture the registered Unreal Editor's active viewport to a PNG on the editor host and return the absolute file path plus the image dimensions. The image bytes are never inlined in the response.",
6897
- inputSchema: captureViewportInputSchema,
6898
- title: "Capture Viewport"
6899
- }, async ({ projectId }) => {
6900
- return toToolSuccess(await captureViewport({ projectId }, dependencies));
6901
- });
6902
- server.registerTool("start_insights_trace", {
6903
- description: "Start an Unreal Insights trace capture in a project's running editor and return the .utrace file path being written. Returns already_tracing (with the current path) when a capture is already running.",
6904
- inputSchema: startInsightsTraceInputSchema,
6905
- title: "Start Insights Trace"
6906
- }, async ({ channels, fileName, projectId }) => {
6907
- return toToolSuccess(await startInsightsTrace({
6908
- channels,
6909
- fileName,
8986
+ server.registerTool("get_blueprint_graph", {
8987
+ description: "Dump one Blueprint graph as nodes and connections: each node reports its title, node class and pins, and each pin reports its name, direction, type, default value and the node/pin ids it links to. Get valid graph names from get_blueprint_summary first. Reading a graph requires the Blueprint in memory, so pass loadIfNeeded for an unloaded asset. Nodes are ordered by their stable GUID and paged via nextNodeCursor.",
8988
+ inputSchema: getBlueprintGraphInputSchema,
8989
+ title: "Get Blueprint Graph"
8990
+ }, async ({ blueprintPath, graphName, loadIfNeeded, maxNodes, nodeCursor, projectId }) => {
8991
+ return toToolSuccess(await getBlueprintGraph({
8992
+ blueprintPath,
8993
+ graphName,
8994
+ loadIfNeeded,
8995
+ maxNodes,
8996
+ nodeCursor,
6910
8997
  projectId
6911
8998
  }, dependencies));
6912
8999
  });
6913
- server.registerTool("stop_insights_trace", {
6914
- description: "Stop the Unreal Insights trace running in a project's editor and return the completed .utrace file path. Returns not_tracing when no capture was running, and fails with trace_not_ready (retryable) when called before the capture has finished opening.",
6915
- inputSchema: stopInsightsTraceInputSchema,
6916
- title: "Stop Insights Trace"
6917
- }, async ({ projectId }) => {
6918
- return toToolSuccess(await stopInsightsTrace(projectId, dependencies));
6919
- });
6920
- server.registerTool("get_cdo_defaults", {
6921
- description: "Read the Class Default Object property values for a UCLASS in a project's running Unreal Editor, so configured defaults are visible without opening the asset or header. Values are exported as Unreal property text, so nested structs and arrays come back fully expanded. Results are paged: pass the previous response nextCursor to fetch the next page.",
6922
- inputSchema: getCdoDefaultsInputSchema,
6923
- title: "Get CDO Defaults"
6924
- }, async ({ className, cursor, includeInherited, maxResults, nameFilter, projectId }) => {
6925
- return toToolSuccess(await getCdoDefaults({
6926
- className,
9000
+ server.registerTool("get_blueprint_compile_errors", {
9001
+ description: "Report each Blueprint's compile status (up_to_date, warnings, error, dirty, unknown, not_loaded, not_found) plus the errors and warnings from the last compile this bridge ran, including the node each message was attached to. hasDiagnostics=false means this bridge has not compiled that Blueprint in this editor session, so empty lists do not mean it is clean — run compile_blueprint first to get diagnostics.",
9002
+ inputSchema: getBlueprintCompileErrorsInputSchema,
9003
+ title: "Get Blueprint Compile Errors"
9004
+ }, async ({ blueprintPaths, cursor, maxResults, projectId }) => {
9005
+ return toToolSuccess(await getBlueprintCompileErrors({
9006
+ blueprintPaths,
6927
9007
  cursor,
6928
- includeInherited,
6929
9008
  maxResults,
6930
- nameFilter,
6931
9009
  projectId
6932
9010
  }, dependencies));
6933
9011
  });
6934
- server.registerTool("list_actors", {
6935
- description: "Enumerate actors in the editor's currently loaded level(s), optionally filtered by class, name substring, tag, or level. Returns each actor's canonical actorPath (the identifier every other level tool takes), display label, class, level, and World Outliner folder. Results are paged: pass the previous response nextCursor to fetch the next page, and totalCount reports the full match count even when a page truncates. Use this to find an actor before calling get_actor_details.",
6936
- inputSchema: listActorsInputSchema,
6937
- title: "List Actors"
6938
- }, async ({ classNames, cursor, levelName, maxResults, nameFilter, projectId, tag }) => {
6939
- return toToolSuccess(await listActors({
6940
- classNames,
9012
+ server.registerTool("compile_blueprint", {
9013
+ description: "Compile one or more Blueprints in the running editor so content breakage is caught after a C++ change that altered a base class or a UFUNCTION signature. Compiling is asynchronous: this returns a compileJobId to poll with get_blueprint_compile_status, which reports the per-Blueprint diagnostics. Blueprints are loaded as needed and their assets are modified in memory — save them with save_dirty_packages if you want the result on disk.",
9014
+ inputSchema: compileBlueprintInputSchema,
9015
+ title: "Compile Blueprint"
9016
+ }, async ({ blueprintPaths, projectId }) => {
9017
+ return toToolSuccess(await compileBlueprint({
9018
+ blueprintPaths,
9019
+ projectId
9020
+ }, dependencies));
9021
+ });
9022
+ server.registerTool("get_blueprint_compile_status", {
9023
+ description: "Poll a compile_blueprint job. Reports 'compiling' while it runs, then 'succeeded' or 'failed' with per-Blueprint errors and warnings (each carrying the node the compiler blamed); 'unknown_job' means the id was never issued or has been evicted.",
9024
+ inputSchema: getBlueprintCompileStatusInputSchema,
9025
+ title: "Get Blueprint Compile Status"
9026
+ }, async ({ compileJobId, cursor, maxResults, projectId }) => {
9027
+ return toToolSuccess(await getBlueprintCompileStatus({
9028
+ compileJobId,
6941
9029
  cursor,
6942
- levelName,
6943
9030
  maxResults,
6944
- nameFilter,
6945
- projectId,
6946
- tag
9031
+ projectId
6947
9032
  }, dependencies));
6948
9033
  });
6949
- server.registerTool("get_actor_details", {
6950
- description: "Inspect one actor in the loaded level by its actorPath: world transform, attached component hierarchy (each component's name, class, attachment parent, and relative transform), and reflected UPROPERTY values. Property values use the same ExportText format get_cdo_defaults emits, so a value read here can be written back verbatim. Components and properties page independently — pass nextComponentCursor / nextPropertyCursor to continue each list. Inherited properties are excluded unless includeInherited is true.",
6951
- inputSchema: getActorDetailsInputSchema,
6952
- title: "Get Actor Details"
6953
- }, async ({ actorPath, componentCursor, includeInherited, maxResults, projectId, propertyCursor }) => {
6954
- return toToolSuccess(await getActorDetails({
6955
- actorPath,
6956
- componentCursor,
6957
- includeInherited,
9034
+ server.registerTool("list_asset_factories", {
9035
+ description: "List every asset type the editor can create, with the UFactory behind it, the class it produces, its Content Browser menu category, and the requiredOptions create_asset must be given for it to run without opening a modal dialog. Use this to discover valid assetClass names instead of guessing them. Results are paged: pass the previous response nextCursor for the next page, and nameFilter to narrow by factory, asset class or category.",
9036
+ inputSchema: listAssetFactoriesInputSchema,
9037
+ title: "List Asset Factories"
9038
+ }, async ({ cursor, maxResults, nameFilter, projectId }) => {
9039
+ return toToolSuccess(await listAssetFactories({
9040
+ cursor,
6958
9041
  maxResults,
6959
- projectId,
6960
- propertyCursor
9042
+ nameFilter,
9043
+ projectId
6961
9044
  }, dependencies));
6962
9045
  });
6963
- server.registerTool("get_current_level", {
6964
- description: "Report the level the editor currently has open — its short name and package path — plus every streaming level registered on that world with its loaded and visible state. worldPartition=true means the map streams cells through World Partition rather than through the listed ULevelStreaming entries, so the streamingLevels list will usually be empty for such a map. Returns no level fields when the editor has no world loaded.",
6965
- inputSchema: getCurrentLevelInputSchema,
6966
- title: "Get Current Level"
6967
- }, async ({ projectId }) => {
6968
- return toToolSuccess(await getCurrentLevel({ projectId }, dependencies));
9046
+ server.registerTool("create_asset", {
9047
+ description: "Create a content asset through its UFactory — anything in the Content Browser's Add menu: DataTables, Materials, Input Actions, Blueprints, Behavior Trees, widgets. Discover valid assetClass names with list_asset_factories first. A factory that would open a modal picker (a Blueprint parent class, a blend space skeleton) is configured headlessly through options instead; if a required option is missing the call fails naming exactly which ones. packagePath must be under /Game. Creates the asset empty — populating it is a separate call.",
9048
+ inputSchema: createAssetInputSchema,
9049
+ title: "Create Asset"
9050
+ }, async ({ assetClass, assetName, factoryClass, options, packagePath, projectId }) => {
9051
+ return toToolSuccess(await createAsset({
9052
+ assetClass,
9053
+ assetName,
9054
+ factoryClass,
9055
+ options,
9056
+ packagePath,
9057
+ projectId
9058
+ }, dependencies));
6969
9059
  });
6970
- server.registerTool("spawn_actor", {
6971
- description: "Spawn one or more actors into the editor's loaded level. Each entry takes a classPath (native or Blueprint generated class) and an optional transform, label, outliner folder, and tags. The whole batch runs inside a single editor transaction, so a human pressing Ctrl+Z removes every actor the call spawned as one step, and save_dirty_packages will report the level afterwards. Returns a per-entry result carrying the new actorPath or the reason that entry failed; a failed entry does not abort the rest of the batch. Pass dryRun: true to validate the batch and see what would be spawned without changing anything.",
6972
- inputSchema: spawnActorInputSchema,
6973
- title: "Spawn Actor"
6974
- }, async ({ dryRun, projectId, spawns }) => {
6975
- return toToolSuccess(await spawnActor({
6976
- dryRun,
9060
+ server.registerTool("duplicate_asset", {
9061
+ description: "Copy an asset to a new name and folder. Iterating on content usually means copying a base asset rather than authoring one from scratch, so this is the cheaper path to a variant than create_asset plus a fresh setup. Returns the new object path.",
9062
+ inputSchema: duplicateAssetInputSchema,
9063
+ title: "Duplicate Asset"
9064
+ }, async ({ destinationName, destinationPath, projectId, sourceAssetPath }) => {
9065
+ return toToolSuccess(await duplicateAsset({
9066
+ destinationName,
9067
+ destinationPath,
6977
9068
  projectId,
6978
- spawns
9069
+ sourceAssetPath
6979
9070
  }, dependencies));
6980
9071
  });
6981
- server.registerTool("destroy_actor", {
6982
- description: "Destroy one or more actors in the loaded level, addressed by the actorPath list_actors returns. The whole batch runs inside a single editor transaction, so Ctrl+Z restores every actor the call destroyed as one step. Returns a per-entry result; an actorPath that no longer resolves fails only its own entry. Pass dryRun: true to check the paths and see what would be destroyed without changing anything.",
6983
- inputSchema: destroyActorInputSchema,
6984
- title: "Destroy Actor"
6985
- }, async ({ actorPaths, dryRun, projectId }) => {
6986
- return toToolSuccess(await destroyActor({
6987
- actorPaths,
6988
- dryRun,
9072
+ server.registerTool("rename_asset", {
9073
+ description: "Rename an asset in place, fixing up every referencer and leaving a redirector behind, so a Blueprint pointing at it still resolves afterwards. Refuses anything outside /Game.",
9074
+ inputSchema: renameAssetInputSchema,
9075
+ title: "Rename Asset"
9076
+ }, async ({ assetPath, newName, projectId }) => {
9077
+ return toToolSuccess(await renameAsset({
9078
+ assetPath,
9079
+ newName,
6989
9080
  projectId
6990
9081
  }, dependencies));
6991
9082
  });
6992
- server.registerTool("set_actor_transform", {
6993
- description: "Move, rotate, and/or scale one or more actors in the loaded level. Each entry addresses an actor by actorPath and supplies any of location, rotation, and scale — an omitted component keeps its current value. The whole batch runs inside a single editor transaction, so Ctrl+Z restores every original transform as one step. Returns a per-entry result; pass dryRun: true to check the paths without moving anything.",
6994
- inputSchema: setActorTransformInputSchema,
6995
- title: "Set Actor Transform"
6996
- }, async ({ dryRun, projectId, transforms }) => {
6997
- return toToolSuccess(await setActorTransform({
6998
- dryRun,
6999
- projectId,
7000
- transforms
9083
+ server.registerTool("move_asset", {
9084
+ description: "Move an asset to another content folder, optionally renaming it, fixing up referencers and leaving a redirector behind. Refuses anything outside /Game.",
9085
+ inputSchema: moveAssetInputSchema,
9086
+ title: "Move Asset"
9087
+ }, async ({ assetPath, destinationPath, newName, projectId }) => {
9088
+ return toToolSuccess(await moveAsset({
9089
+ assetPath,
9090
+ destinationPath,
9091
+ newName,
9092
+ projectId
7001
9093
  }, dependencies));
7002
9094
  });
7003
- server.registerTool("set_actor_property", {
7004
- description: "Write reflected UPROPERTY values on actors or their components in the loaded level. Each entry takes an actorPath, a propertyPath ('bHidden' on the actor, 'StaticMeshComponent.RelativeScale3D' on a component), and a value in the same ExportText format get_actor_details and get_cdo_defaults emit — so you can read a value, edit it, and write it back without translating. Properties marked EditConst or not exposed for editing are rejected with an explicit error rather than silently ignored. The whole batch runs in one transaction; pass dryRun: true to resolve paths and check coercion without writing.",
7005
- inputSchema: setActorPropertyInputSchema,
7006
- title: "Set Actor Property"
7007
- }, async ({ dryRun, projectId, properties }) => {
7008
- return toToolSuccess(await setActorProperty({
7009
- dryRun,
7010
- projectId,
7011
- properties
9095
+ server.registerTool("delete_asset", {
9096
+ description: "Delete an asset. Without force this first asks the Asset Registry who references it and refuses with that list rather than leaving dangling references — state 'blocked' plus referencers. Pass force only when breaking those references is the intent. Refuses anything outside /Game.",
9097
+ inputSchema: deleteAssetInputSchema,
9098
+ title: "Delete Asset"
9099
+ }, async ({ assetPath, force, projectId }) => {
9100
+ return toToolSuccess(await deleteAsset({
9101
+ assetPath,
9102
+ force,
9103
+ projectId
7012
9104
  }, dependencies));
7013
9105
  });
7014
- server.registerTool("select_actors", {
7015
- description: "Set the editor's actor selection — the write-side counterpart to get_editor_state, using the same actorPath identifiers list_actors returns. An empty actorPaths list clears the selection; addToSelection adds to it instead of replacing it. Runs inside a transaction, so Ctrl+Z restores the previous selection. Returns the resulting selectedActorCount plus a per-entry result for any path that no longer resolves.",
7016
- inputSchema: selectActorsInputSchema,
7017
- title: "Select Actors"
7018
- }, async ({ actorPaths, addToSelection, dryRun, projectId }) => {
7019
- return toToolSuccess(await selectActors({
7020
- actorPaths,
7021
- addToSelection,
7022
- dryRun,
9106
+ server.registerTool("save_asset", {
9107
+ description: "Save specific asset packages to disk — the narrow counterpart to save_dirty_packages, for when only the assets you just wrote should be committed. Per-item results report which were actually dirty; an already-clean package reports ok with saved false rather than an error.",
9108
+ inputSchema: saveAssetInputSchema,
9109
+ title: "Save Asset"
9110
+ }, async ({ assetPaths, projectId }) => {
9111
+ return toToolSuccess(await saveAsset({
9112
+ assetPaths,
7023
9113
  projectId
7024
9114
  }, dependencies));
7025
9115
  });
7026
- server.registerTool("undo", {
7027
- description: "Undo the editor's most recent transaction — the same action as pressing Ctrl+Z in the editor — and report the title of the transaction that was undone. Use this to roll back your own level edits without a human in the loop. Returns state 'nothing_to_undo' when the transaction buffer is empty. Note this undoes whatever is at the head of the buffer, which may be a human's edit rather than yours, so check the returned transactionTitle.",
7028
- inputSchema: undoInputSchema,
7029
- title: "Undo"
7030
- }, async ({ projectId }) => {
7031
- return toToolSuccess(await undo({ projectId }, dependencies));
7032
- });
7033
- server.registerTool("redo", {
7034
- description: "Redo the editor's most recently undone transaction — the same action as pressing Ctrl+Y in the editor — and report the title of the transaction that was redone. Returns state 'nothing_to_redo' when there is nothing to reapply.",
7035
- inputSchema: redoInputSchema,
7036
- title: "Redo"
7037
- }, async ({ projectId }) => {
7038
- return toToolSuccess(await redo({ projectId }, dependencies));
7039
- });
7040
- server.registerTool("open_level", {
7041
- description: "Open a level in the editor by package name. Loading a map tears down and rebuilds the world, which takes far longer than a bridge request can wait, so this only accepts the job: it returns state 'opening' with an openLevelJobId to poll with get_open_level_status. Unsaved changes in the current world are discarded unless saveDirtyPackages is true. This is NOT undoable — loading a map clears the editor's transaction buffer, so undo cannot bring the previous level back.",
7042
- inputSchema: openLevelInputSchema,
7043
- title: "Open Level"
7044
- }, async ({ dryRun, levelPath, projectId, saveDirtyPackages }) => {
7045
- return toToolSuccess(await openLevel({
7046
- dryRun,
7047
- levelPath,
7048
- projectId,
7049
- saveDirtyPackages
9116
+ server.registerTool("create_folder", {
9117
+ description: "Create a Content Browser folder under /Game. Reports state 'exists' rather than failing when the folder is already there, since that is the state the caller wanted.",
9118
+ inputSchema: createFolderInputSchema,
9119
+ title: "Create Folder"
9120
+ }, async ({ folderPath, projectId }) => {
9121
+ return toToolSuccess(await createFolder({
9122
+ folderPath,
9123
+ projectId
7050
9124
  }, dependencies));
7051
9125
  });
7052
- server.registerTool("get_open_level_status", {
7053
- description: "Poll a level load started by open_level for a projectId; returns state (opening, succeeded, failed, unknown_job), the loaded levelPath, and timing once finished. Poll until the state leaves 'opening' before issuing further level tools — actor paths from the previous world do not survive the load.",
7054
- inputSchema: getOpenLevelStatusInputSchema,
7055
- title: "Get Open Level Status"
7056
- }, async ({ openLevelJobId, projectId }) => {
7057
- return toToolSuccess(await getOpenLevelStatus({
7058
- openLevelJobId,
9126
+ server.registerTool("get_asset_metadata", {
9127
+ description: "Report an asset's class, package, on-disk size and Asset Registry tag map without loading it. Use this to inspect content cheaply — the tags carry a Blueprint's parent class, a texture's dimensions, a DataTable's row struct and so on, none of which needs the package in memory. loaded reports whether it happens to be in memory already; false is normal.",
9128
+ inputSchema: getAssetMetadataInputSchema,
9129
+ title: "Get Asset Metadata"
9130
+ }, async ({ assetPath, projectId }) => {
9131
+ return toToolSuccess(await getAssetMetadata({
9132
+ assetPath,
7059
9133
  projectId
7060
9134
  }, dependencies));
7061
9135
  });
7062
- server.registerTool("get_source_control_status", {
7063
- description: "Report the editor's source control provider and the per-file state of up to 64 assets. Answered from the provider's state cache, so it costs no network round trip and returns inline. enabled distinguishes 'no source control configured' from 'configured, and this file is simply not checked out'; per-file state is one of checked_out_by_me, checked_out_by_other (with checkedOutBy naming the holder), marked_for_add, not_checked_out, not_in_depot, unknown. A file the editor has never queried reports 'unknown' — call refresh_source_control_status to fetch its real state from the server. Call this before any asset write on a team project: under Perforce or Git-LFS file locking a .uasset stays read-only until checked out, and the write otherwise fails later at save time.",
7064
- inputSchema: getSourceControlStatusInputSchema,
7065
- title: "Get Source Control Status"
7066
- }, async ({ assetPaths, projectId }) => {
7067
- return toToolSuccess(await getSourceControlStatus({
7068
- assetPaths,
9136
+ server.registerTool("list_graph_nodes", {
9137
+ description: "List the nodes in any UEdGraph — a Blueprint event graph or function, an Animation Blueprint AnimGraph, a Material graph, a Behavior Tree — with each node's GUID, class, title and pins. The GUID is what every other graph tool addresses a node by; it survives adding and removing other nodes, which an index does not. Results are paged by nextCursor.",
9138
+ inputSchema: listGraphNodesInputSchema,
9139
+ title: "List Graph Nodes"
9140
+ }, async ({ assetPath, cursor, graphName, loadIfNeeded, maxResults, projectId }) => {
9141
+ return toToolSuccess(await listGraphNodes({
9142
+ assetPath,
9143
+ cursor,
9144
+ graphName,
9145
+ loadIfNeeded,
9146
+ maxResults,
7069
9147
  projectId
7070
9148
  }, dependencies));
7071
9149
  });
7072
- server.registerTool("refresh_source_control_status", {
7073
- description: "Re-read the depot state of up to 64 assets from the source control server, so a later get_source_control_status reports something better than 'unknown'. This is a network round trip to the provider and runs far past what a bridge request can wait for, so it only accepts the job: it returns state 'accepted' with a sourceControlJobId to poll with get_source_control_job_status (or wait_for_job with kind source_control).",
7074
- inputSchema: refreshSourceControlStatusInputSchema,
7075
- title: "Refresh Source Control Status"
7076
- }, async ({ assetPaths, projectId }) => {
7077
- return toToolSuccess(await refreshSourceControlStatus({
7078
- assetPaths,
9150
+ server.registerTool("add_graph_node", {
9151
+ description: "Add a node to a UEdGraph and return it with its pins, so it can be wired without a follow-up read. kind 'class' places a node type directly (K2Node_IfThenElse for a Branch); 'function' places a call to memberName on memberParentClass; 'variable_get' / 'variable_set' place a variable accessor. Use list_available_nodes to discover what this graph's schema accepts rather than guessing class names. pinDefaults configures the node in the same call. The Blueprint is marked structurally modified, so compile_blueprint afterwards picks the change up.",
9152
+ inputSchema: addGraphNodeInputSchema,
9153
+ title: "Add Graph Node"
9154
+ }, async ({ assetPath, graphName, kind, memberName, memberParentClass, nodeClass, pinDefaults, position, projectId }) => {
9155
+ return toToolSuccess(await addGraphNode({
9156
+ assetPath,
9157
+ graphName,
9158
+ kind,
9159
+ memberName,
9160
+ memberParentClass,
9161
+ nodeClass,
9162
+ pinDefaults,
9163
+ position,
7079
9164
  projectId
7080
9165
  }, dependencies));
7081
9166
  });
7082
- server.registerTool("checkout_assets", {
7083
- description: "Check up to 64 assets out of source control so they become writable. This is a network round trip to the provider and runs far past what a bridge request can wait for, so it only accepts the job: it returns state 'accepted' with a sourceControlJobId to poll with get_source_control_job_status (or wait_for_job with kind source_control). The poll reports per-item results with successCount / failureCount — one asset the provider refuses does not abort the rest. This checks out only; it never submits, and a checked-out asset stays checked out until a human submits or reverts it.",
7084
- inputSchema: checkoutAssetsInputSchema,
7085
- title: "Checkout Assets"
7086
- }, async ({ assetPaths, projectId }) => {
7087
- return toToolSuccess(await checkoutAssets({
7088
- assetPaths,
9167
+ server.registerTool("remove_graph_node", {
9168
+ description: "Remove a node from a UEdGraph by its GUID, breaking its connections. Reports removed false when the GUID is not in the graph, which is already the desired state.",
9169
+ inputSchema: removeGraphNodeInputSchema,
9170
+ title: "Remove Graph Node"
9171
+ }, async ({ assetPath, graphName, nodeGuid, projectId }) => {
9172
+ return toToolSuccess(await removeGraphNode({
9173
+ assetPath,
9174
+ graphName,
9175
+ nodeGuid,
7089
9176
  projectId
7090
9177
  }, dependencies));
7091
9178
  });
7092
- server.registerTool("get_source_control_job_status", {
7093
- description: "Poll a source control job started by checkout_assets or refresh_source_control_status for a projectId; returns state (running, succeeded, failed, unknown_job), which operation it was, and once finished the per-file results with successCount / failureCount and timing. Poll until the state leaves 'running' before writing to any asset in the batch.",
7094
- inputSchema: getSourceControlJobStatusInputSchema,
7095
- title: "Get Source Control Job Status"
7096
- }, async ({ projectId, sourceControlJobId }) => {
7097
- return toToolSuccess(await getSourceControlJobStatus({
9179
+ server.registerTool("connect_pins", {
9180
+ description: "Wire two pins together. The connection goes through the graph schema's own CanCreateConnection rules, so an illegal pairing — wrong type, wrong direction, would create a cycle — is refused with the schema's own reason string rather than producing a corrupt graph.",
9181
+ inputSchema: connectPinsInputSchema,
9182
+ title: "Connect Pins"
9183
+ }, async ({ assetPath, graphName, projectId, sourceNodeGuid, sourcePinName, targetNodeGuid, targetPinName }) => {
9184
+ return toToolSuccess(await connectPins({
9185
+ assetPath,
9186
+ graphName,
7098
9187
  projectId,
7099
- sourceControlJobId
9188
+ sourceNodeGuid,
9189
+ sourcePinName,
9190
+ targetNodeGuid,
9191
+ targetPinName
7100
9192
  }, dependencies));
7101
9193
  });
7102
- server.registerTool("find_assets", {
7103
- description: "Query a project's Unreal Asset Registry for assets by class and/or content path, without loading them; returns each match's name, class, package name, package path, and object path. Requires at least one of classNames or packagePaths — an unfiltered query would stall the editor enumerating every asset. Results are paged: pass the previous response nextCursor to fetch the next page (totalCount reports the full match count). scanning=true means the registry is still indexing, so an empty result does not prove the asset is absent.",
7104
- inputSchema: findAssetsInputSchema,
7105
- title: "Find Assets"
7106
- }, async ({ classNames, cursor, maxResults, nameFilter, packagePaths, projectId, recursiveClasses, recursivePaths }) => {
7107
- return toToolSuccess(await findAssets({
7108
- classNames,
9194
+ server.registerTool("disconnect_pins", {
9195
+ description: "Break the wire between two pins. Reports disconnected false when they were not linked, which is already the desired state.",
9196
+ inputSchema: disconnectPinsInputSchema,
9197
+ title: "Disconnect Pins"
9198
+ }, async ({ assetPath, graphName, projectId, sourceNodeGuid, sourcePinName, targetNodeGuid, targetPinName }) => {
9199
+ return toToolSuccess(await disconnectPins({
9200
+ assetPath,
9201
+ graphName,
9202
+ projectId,
9203
+ sourceNodeGuid,
9204
+ sourcePinName,
9205
+ targetNodeGuid,
9206
+ targetPinName
9207
+ }, dependencies));
9208
+ });
9209
+ server.registerTool("set_pin_default", {
9210
+ description: "Set an unconnected pin's default value. The write goes through the schema's TrySetDefaultValue, so a value the pin type cannot hold is refused rather than stored. Returns the value the schema actually stored, which for a struct pin is normalized rather than echoed back.",
9211
+ inputSchema: setPinDefaultInputSchema,
9212
+ title: "Set Pin Default"
9213
+ }, async ({ assetPath, graphName, nodeGuid, pinName, projectId, value }) => {
9214
+ return toToolSuccess(await setPinDefault({
9215
+ assetPath,
9216
+ graphName,
9217
+ nodeGuid,
9218
+ pinName,
9219
+ projectId,
9220
+ value
9221
+ }, dependencies));
9222
+ });
9223
+ server.registerTool("list_available_nodes", {
9224
+ description: "List what is legal to place in a specific graph, from the Blueprint action database filtered by that graph's own schema — not a global list. Each action reports the kind, class and member name add_graph_node needs. Pass nameFilter: unfiltered, a Blueprint graph offers thousands of actions.",
9225
+ inputSchema: listAvailableNodesInputSchema,
9226
+ title: "List Available Nodes"
9227
+ }, async ({ assetPath, cursor, graphName, maxResults, nameFilter, projectId }) => {
9228
+ return toToolSuccess(await listAvailableNodes({
9229
+ assetPath,
7109
9230
  cursor,
9231
+ graphName,
7110
9232
  maxResults,
7111
9233
  nameFilter,
7112
- packagePaths,
9234
+ projectId
9235
+ }, dependencies));
9236
+ });
9237
+ server.registerTool("set_viewport_camera", {
9238
+ description: "Aim the active level editor viewport: position, rotation, field of view, and perspective or one of the six orthographic view types. Without this, capture_viewport photographs wherever the user last left the view. Refused with a clear message when no level editor viewport exists, such as a -nullrhi run.",
9239
+ inputSchema: setViewportCameraInputSchema,
9240
+ title: "Set Viewport Camera"
9241
+ }, async ({ fov, location, orthoWidth, projectId, rotation, viewType }) => {
9242
+ return toToolSuccess(await setViewportCamera({
9243
+ fov,
9244
+ location,
9245
+ orthoWidth,
7113
9246
  projectId,
7114
- recursiveClasses,
7115
- recursivePaths
9247
+ rotation,
9248
+ viewType
7116
9249
  }, dependencies));
7117
9250
  });
7118
- server.registerTool("read_data_table", {
7119
- description: "Read a DataTable asset's contents: the row struct it is typed on, its ordered column list (name plus the same type rendering get_class_reflection emits), and its rows as column-name-to-value maps. Values are ExportText, the format write_data_table_row accepts back, so a value read here round-trips. Rows are paged by name order: pass the previous response nextCursor to fetch the next page (totalRowCount reports the full count). A DataTable is a binary .uasset with no Asset Registry tags describing its rows, so there is no way to read one off disk instead — this tool loads it.",
7120
- inputSchema: readDataTableInputSchema,
7121
- title: "Read Data Table"
7122
- }, async ({ assetPath, cursor, loadIfNeeded, maxRows, projectId, rowNameFilter }) => {
7123
- return toToolSuccess(await readDataTable({
7124
- assetPath,
7125
- cursor,
7126
- loadIfNeeded,
7127
- maxRows,
9251
+ server.registerTool("focus_actors", {
9252
+ description: "Frame the given actors in the viewport, exactly as the editor's F key does — a bounds box over all of them with the usual padding. focusedCount reports how many resolved; a path that resolved to nothing is reported there rather than failing the framing. Follow with capture_viewport to look at the result.",
9253
+ inputSchema: focusActorsInputSchema,
9254
+ title: "Focus Actors"
9255
+ }, async ({ actorPaths, instant, projectId }) => {
9256
+ return toToolSuccess(await focusActors({
9257
+ actorPaths,
9258
+ instant,
9259
+ projectId
9260
+ }, dependencies));
9261
+ });
9262
+ server.registerTool("set_view_mode", {
9263
+ description: "Switch the active viewport view mode — lit to judge composition, wireframe to judge density, lightmap_density to judge a bake, shader_complexity or quad_overdraw to judge cost, visualize_nanite and visualize_lumen for the UE5 pipelines. Pair with capture_viewport to read the result back.",
9264
+ inputSchema: setViewModeInputSchema,
9265
+ title: "Set View Mode"
9266
+ }, async ({ projectId, viewMode }) => {
9267
+ return toToolSuccess(await setViewMode({
7128
9268
  projectId,
7129
- rowNameFilter
9269
+ viewMode
7130
9270
  }, dependencies));
7131
9271
  });
7132
- server.registerTool("write_data_table_row", {
7133
- description: "Insert, update, or delete a single DataTable row. Every column name and value is validated against the row struct before anything is written — an unknown column or a value that will not parse rejects the whole write with an error naming the field, so a row is never partially applied and there is no silent coercion. The write runs inside one transaction, so a human at the editor can Ctrl+Z it, and it marks the package dirty without saving: call save_dirty_packages to persist. Deleting a row that does not exist reports rowExisted=false rather than failing. Use dryRun to validate first. For a whole-table replace use import_data_table instead.",
7134
- inputSchema: writeDataTableRowInputSchema,
7135
- title: "Write Data Table Row"
7136
- }, async ({ assetPath, dryRun, operation, projectId, rowName, values }) => {
7137
- return toToolSuccess(await writeDataTableRow({
7138
- assetPath,
9272
+ server.registerTool("toggle_show_flags", {
9273
+ description: "Turn viewport show flags on or off by FEngineShowFlags name, so any of the engine's roughly three hundred flags is reachable without a per-flag tool. An unknown name is reported per entry with near matches, not as a failure of the whole batch.",
9274
+ inputSchema: toggleShowFlagsInputSchema,
9275
+ title: "Toggle Show Flags"
9276
+ }, async ({ flags, projectId }) => {
9277
+ return toToolSuccess(await toggleShowFlags({
9278
+ flags,
9279
+ projectId
9280
+ }, dependencies));
9281
+ });
9282
+ server.registerTool("high_res_screenshot", {
9283
+ description: "Queue a multiplier-scaled screenshot written to the project's Saved/Screenshots — the on-disk counterpart to capture_viewport, which returns image bytes in-band and is therefore capped by the bridge frame budget. The capture happens on the next rendered frame, so the response reports where the file will be rather than waiting for it.",
9284
+ inputSchema: highResScreenshotInputSchema,
9285
+ title: "High Res Screenshot"
9286
+ }, async ({ fileName, includeUi, multiplier, projectId }) => {
9287
+ return toToolSuccess(await highResScreenshot({
9288
+ fileName,
9289
+ includeUi,
9290
+ multiplier,
9291
+ projectId
9292
+ }, dependencies));
9293
+ });
9294
+ server.registerTool("duplicate_actor", {
9295
+ description: "Duplicate up to 64 actors in one undo entry, each optionally offset from its original — the cheap way to build a row, a grid or a variant set without respawning and reconfiguring every copy. dryRun resolves every entry without duplicating anything.",
9296
+ inputSchema: duplicateActorInputSchema,
9297
+ title: "Duplicate Actor"
9298
+ }, async ({ actors, dryRun, projectId }) => {
9299
+ return toToolSuccess(await duplicateActor({
9300
+ actors,
7139
9301
  dryRun,
7140
- operation,
7141
- projectId,
7142
- rowName,
7143
- values
9302
+ projectId
7144
9303
  }, dependencies));
7145
9304
  });
7146
- server.registerTool("export_data_table", {
7147
- description: "Serialize a whole DataTable through the engine's own JSON or CSV exporter. Returned in chunks by character offset because the engine produces one string rather than something row-addressable: concatenate the chunks in cursor order to reassemble, and note a single chunk is not valid JSON or CSV on its own. Use read_data_table when you want structured, per-row access; use this when you want the table in the same text form the editor's own export produces.",
7148
- inputSchema: exportDataTableInputSchema,
7149
- title: "Export Data Table"
7150
- }, async ({ assetPath, cursor, format, loadIfNeeded, projectId }) => {
7151
- return toToolSuccess(await exportDataTable({
7152
- assetPath,
7153
- cursor,
7154
- format,
7155
- loadIfNeeded,
9305
+ server.registerTool("attach_actor", {
9306
+ description: "Attach actors to parents with explicit transform rules, or detach them by passing an empty parentActorPath. Attaching an actor to itself or to one of its own descendants is refused per entry rather than corrupting the world. One undo entry for the whole batch.",
9307
+ inputSchema: attachActorInputSchema,
9308
+ title: "Attach Actor"
9309
+ }, async ({ attachments, dryRun, projectId }) => {
9310
+ return toToolSuccess(await attachActor({
9311
+ attachments,
9312
+ dryRun,
7156
9313
  projectId
7157
9314
  }, dependencies));
7158
9315
  });
7159
- server.registerTool("import_data_table", {
7160
- description: "REPLACE every row of a DataTable from a JSON or CSV payload, using the engine's own importer. This is destructive: any row not present in the content is deleted, so it is the wrong tool for changing one value — use write_data_table_row for that. The whole payload travels in one bridge frame, so a table beyond the content character bound cannot be imported this way. Runs inside one transaction (Ctrl+Z reverses it) and marks the package dirty without saving. Rows the importer rejects come back in problems while the rest still apply, so check problemCount even on success; dryRun reports the row count and problems without replacing anything.",
7161
- inputSchema: importDataTableInputSchema,
7162
- title: "Import Data Table"
7163
- }, async ({ assetPath, content, dryRun, format, projectId }) => {
7164
- return toToolSuccess(await importDataTable({
7165
- assetPath,
7166
- content,
9316
+ server.registerTool("add_actor_component", {
9317
+ description: "Add instance components to placed actors — a point light on a prop, a collision box on a blockout. These are real instance components: they show in the details panel and survive a level save and reload, unlike a transient runtime component.",
9318
+ inputSchema: addActorComponentInputSchema,
9319
+ title: "Add Actor Component"
9320
+ }, async ({ components, dryRun, projectId }) => {
9321
+ return toToolSuccess(await addActorComponent({
9322
+ components,
7167
9323
  dryRun,
7168
- format,
7169
9324
  projectId
7170
9325
  }, dependencies));
7171
9326
  });
7172
- server.registerTool("create_data_table", {
7173
- description: "Create a new empty DataTable asset backed by a row struct. The struct is fixed at creation — UDataTable can have its RowStruct swapped later, but that reinterprets existing rows through the new layout, so the bridge does not expose it; create a new table instead. The struct must derive FTableRowBase, and creation fails if an asset already exists at the path. The new table is marked dirty but not written to disk: call save_dirty_packages to persist it, or it disappears when the editor closes. Use read_data_table to confirm the column set the struct produced.",
7174
- inputSchema: createDataTableInputSchema,
7175
- title: "Create Data Table"
7176
- }, async ({ assetPath, dryRun, projectId, rowStructPath }) => {
7177
- return toToolSuccess(await createDataTable({
7178
- assetPath,
9327
+ server.registerTool("set_actor_tags", {
9328
+ description: "Write actor tags in bulk. mode 'set' replaces the actor's tag list, 'add' unions with it, 'remove' subtracts. Tags are what list_actors filters on, so this is how a batch of actors is made addressable as a group.",
9329
+ inputSchema: setActorTagsInputSchema,
9330
+ title: "Set Actor Tags"
9331
+ }, async ({ dryRun, entries, projectId }) => {
9332
+ return toToolSuccess(await setActorTags({
7179
9333
  dryRun,
7180
- projectId,
7181
- rowStructPath
9334
+ entries,
9335
+ projectId
7182
9336
  }, dependencies));
7183
9337
  });
7184
- server.registerTool("rename_data_table", {
7185
- description: "Rename a DataTable, move it to another package path, or both. Goes through the editor's asset tools, so references from other assets are fixed up and a redirector is left at the old path to keep hard references resolving. Renaming is not a transaction the editor can Ctrl+Z — it rewrites packages on disk. Use dryRun to check the destination is free first.",
7186
- inputSchema: renameDataTableInputSchema,
7187
- title: "Rename Data Table"
7188
- }, async ({ assetPath, destinationPath, dryRun, newName, projectId }) => {
7189
- return toToolSuccess(await renameDataTable({
7190
- assetPath,
7191
- destinationPath,
9338
+ server.registerTool("move_to_folder", {
9339
+ description: "Move actors into World Outliner folders, creating the folder if it does not exist. An empty folderPath moves an actor back to the outliner root.",
9340
+ inputSchema: moveToFolderInputSchema,
9341
+ title: "Move To Folder"
9342
+ }, async ({ dryRun, entries, projectId }) => {
9343
+ return toToolSuccess(await moveToFolder({
7192
9344
  dryRun,
7193
- newName,
9345
+ entries,
7194
9346
  projectId
7195
9347
  }, dependencies));
7196
9348
  });
7197
- server.registerTool("delete_data_table", {
7198
- description: "Delete a DataTable asset from the project. This is the one DataTable tool that cannot be undone — asset deletion is not a transaction, so there is no Ctrl+Z and no dirty-package step to reconsider at. A table other assets still reference is refused, and those referencers are reported; force deletes anyway and breaks them. Always dryRun first on a table you did not create: it reports the referencers without touching anything.",
7199
- inputSchema: deleteDataTableInputSchema,
7200
- title: "Delete Data Table"
7201
- }, async ({ assetPath, dryRun, force, projectId }) => {
7202
- return toToolSuccess(await deleteDataTable({
7203
- assetPath,
9349
+ server.registerTool("place_asset", {
9350
+ description: "Place assets into the level, letting the editor's actor factory pick the actor class — a static mesh becomes a StaticMeshActor, a Blueprint becomes its own class, a particle system becomes an emitter, a sound becomes an ambient sound. Use this instead of spawn_actor whenever the thing being placed is an asset rather than a bare class.",
9351
+ inputSchema: placeAssetInputSchema,
9352
+ title: "Place Asset"
9353
+ }, async ({ dryRun, placements, projectId }) => {
9354
+ return toToolSuccess(await placeAsset({
7204
9355
  dryRun,
7205
- force,
9356
+ placements,
7206
9357
  projectId
7207
9358
  }, dependencies));
7208
9359
  });
7209
- server.registerTool("rename_data_table_row", {
7210
- description: "Rename a single row, keeping its position in the table and its values intact. Not the same as an upsert under the new name followed by a delete of the old one: that pair costs two transactions and moves the row to the end. Fails if the row does not exist or the new name is already taken. Runs inside one transaction (Ctrl+Z reverses it) and marks the package dirty without saving. Note that row names are how other assets address rows, so a rename breaks any FDataTableRowHandle pointing at the old name — nothing fixes those up.",
7211
- inputSchema: renameDataTableRowInputSchema,
7212
- title: "Rename Data Table Row"
7213
- }, async ({ assetPath, dryRun, newRowName, projectId, rowName }) => {
7214
- return toToolSuccess(await renameDataTableRow({
7215
- assetPath,
9360
+ server.registerTool("replace_actors", {
9361
+ description: "Replace up to 64 actors with a different asset or class, preserving each original transform and, where the types line up, its matching properties. Give exactly one of replacementAssetPath or replacementClass. One undo entry for the whole batch.",
9362
+ inputSchema: replaceActorsInputSchema,
9363
+ title: "Replace Actors"
9364
+ }, async ({ actorPaths, dryRun, projectId, replacementAssetPath, replacementClass }) => {
9365
+ return toToolSuccess(await replaceActors({
9366
+ actorPaths,
7216
9367
  dryRun,
7217
- newRowName,
7218
9368
  projectId,
7219
- rowName
9369
+ replacementAssetPath,
9370
+ replacementClass
7220
9371
  }, dependencies));
7221
9372
  });
7222
- server.registerTool("get_asset_dependencies", {
7223
- description: "Report an asset's package-level dependencies (what it needs) and referencers (what needs it) from the Unreal Asset Registry — the Reference Viewer data — so you can judge the blast radius before changing it. Depth is 1: transitive links are not walked. Each list pages independently via nextDependencyCursor / nextReferencerCursor.",
7224
- inputSchema: getAssetDependenciesInputSchema,
7225
- title: "Get Asset Dependencies"
7226
- }, async ({ assetPath, categories, dependencyCursor, linkage, maxResults, projectId, referencerCursor }) => {
7227
- return toToolSuccess(await getAssetDependencies({
7228
- assetPath,
7229
- categories,
7230
- dependencyCursor,
7231
- linkage,
7232
- maxResults,
9373
+ server.registerTool("build_lighting", {
9374
+ description: "Run the editor's Build Lighting for the loaded level. Lightmass runs for minutes to hours, so this only accepts the job: it returns a buildJobId to poll with get_build_job_status (or wait_for_job with kind build). A Lightmass or Swarm failure surfaces its own error text and ends the job as failed, never as succeeded-with-warnings.",
9375
+ inputSchema: buildLightingInputSchema,
9376
+ title: "Build Lighting"
9377
+ }, async ({ projectId, quality }) => {
9378
+ return toToolSuccess(await startEditorBuild({
9379
+ buildKind: "lighting",
7233
9380
  projectId,
7234
- referencerCursor
9381
+ quality
7235
9382
  }, dependencies));
7236
9383
  });
7237
- server.registerTool("find_blueprint_references", {
7238
- description: "Report which Blueprint assets depend on a C++ class, so you can judge whether renaming or removing it will break content. Each hit is either 'subclass' (the Blueprint's parent chain reaches the class) or 'module_dependency' (the Blueprint's package depends on the class's /Script module, which may be through this class or another type in it). Answers from Asset Registry metadata only — no Blueprints are loaded, so per-function and per-property usage is not resolved.",
7239
- inputSchema: findBlueprintReferencesInputSchema,
7240
- title: "Find Blueprint References"
7241
- }, async ({ className, cursor, maxResults, projectId, referenceKinds }) => {
7242
- return toToolSuccess(await findBlueprintReferences({
7243
- className,
9384
+ server.registerTool("build_navigation", {
9385
+ description: "Rebuild the navmesh for the loaded level. Returns a buildJobId to poll with get_build_job_status or wait_for_job with kind build. Without this an assistant-built level has no navigation and every AI pawn stands still.",
9386
+ inputSchema: buildOnlyInputSchema,
9387
+ title: "Build Navigation"
9388
+ }, async ({ projectId }) => {
9389
+ return toToolSuccess(await startEditorBuild({
9390
+ buildKind: "navigation",
9391
+ projectId
9392
+ }, dependencies));
9393
+ });
9394
+ server.registerTool("build_hlod", {
9395
+ description: "Build Hierarchical LOD clusters and proxy meshes for the loaded level. hlodAction picks which pass to run, since clusters and proxy meshes are separate steps in the editor and a caller usually wants one of them. Returns a buildJobId to poll with get_build_job_status or wait_for_job with kind build.",
9396
+ inputSchema: buildHlodInputSchema,
9397
+ title: "Build HLOD"
9398
+ }, async ({ hlodAction, projectId }) => {
9399
+ return toToolSuccess(await startEditorBuild({
9400
+ buildKind: "hlod",
9401
+ hlodAction,
9402
+ projectId
9403
+ }, dependencies));
9404
+ });
9405
+ server.registerTool("build_reflection_captures", {
9406
+ description: "Rebuild reflection captures for the loaded level. Returns a buildJobId to poll with get_build_job_status or wait_for_job with kind build. Missing captures are the usual reason an assistant-built interior reads as flat.",
9407
+ inputSchema: buildOnlyInputSchema,
9408
+ title: "Build Reflection Captures"
9409
+ }, async ({ projectId }) => {
9410
+ return toToolSuccess(await startEditorBuild({
9411
+ buildKind: "reflection_captures",
9412
+ projectId
9413
+ }, dependencies));
9414
+ });
9415
+ server.registerTool("build_geometry", {
9416
+ description: "Rebuild BSP geometry for the loaded level. Returns a buildJobId to poll with get_build_job_status or wait_for_job with kind build.",
9417
+ inputSchema: buildOnlyInputSchema,
9418
+ title: "Build Geometry"
9419
+ }, async ({ projectId }) => {
9420
+ return toToolSuccess(await startEditorBuild({
9421
+ buildKind: "geometry",
9422
+ projectId
9423
+ }, dependencies));
9424
+ });
9425
+ server.registerTool("build_texture_streaming", {
9426
+ description: "Rebuild texture streaming data for the loaded level. Returns a buildJobId to poll with get_build_job_status or wait_for_job with kind build.",
9427
+ inputSchema: buildOnlyInputSchema,
9428
+ title: "Build Texture Streaming"
9429
+ }, async ({ projectId }) => {
9430
+ return toToolSuccess(await startEditorBuild({
9431
+ buildKind: "texture_streaming",
9432
+ projectId
9433
+ }, dependencies));
9434
+ });
9435
+ server.registerTool("build_virtual_textures", {
9436
+ description: "Rebuild runtime virtual texture data for the loaded level. Returns a buildJobId to poll with get_build_job_status or wait_for_job with kind build.",
9437
+ inputSchema: buildOnlyInputSchema,
9438
+ title: "Build Virtual Textures"
9439
+ }, async ({ projectId }) => {
9440
+ return toToolSuccess(await startEditorBuild({
9441
+ buildKind: "virtual_textures",
9442
+ projectId
9443
+ }, dependencies));
9444
+ });
9445
+ server.registerTool("precompute_visibility", {
9446
+ description: "Turn on the loaded level's precomputed visibility and run the lighting build that generates it. Returns a buildJobId to poll with get_build_job_status or wait_for_job with kind build. The level needs precomputed visibility volumes placed for this to produce anything.",
9447
+ inputSchema: buildOnlyInputSchema,
9448
+ title: "Precompute Visibility"
9449
+ }, async ({ projectId }) => {
9450
+ return toToolSuccess(await startEditorBuild({
9451
+ buildKind: "precomputed_visibility",
9452
+ projectId
9453
+ }, dependencies));
9454
+ });
9455
+ server.registerTool("get_build_job_status", {
9456
+ description: "Poll a build job started by any of the build_* tools; returns state (running, succeeded, failed, cancelled, unknown_job), which build kind it was, the real Lightmass / Swarm / builder error and warning text, and once finished the timing. A build a human aborted from the editor's own progress dialog reports 'cancelled', not 'failed'.",
9457
+ inputSchema: getBuildJobStatusInputSchema,
9458
+ title: "Get Build Job Status"
9459
+ }, async ({ buildJobId, projectId }) => {
9460
+ return toToolSuccess(await getBuildJobStatus({
9461
+ buildJobId,
9462
+ projectId
9463
+ }, dependencies));
9464
+ });
9465
+ server.registerTool("create_gameplay_tag", {
9466
+ description: "Declare a gameplay tag in a project config file, so it appears in the editor's tag picker without a restart. The response names the .ini that was written, which is the file to put under source control. A malformed hierarchical name is rejected before anything is written — a corrupted tag table is painful to unpick. Reports state 'exists' rather than failing for a tag that is already declared.",
9467
+ inputSchema: createGameplayTagInputSchema,
9468
+ title: "Create Gameplay Tag"
9469
+ }, async ({ comment, projectId, source, tagName }) => {
9470
+ return toToolSuccess(await createGameplayTag({
9471
+ comment,
9472
+ projectId,
9473
+ source,
9474
+ tagName
9475
+ }, dependencies));
9476
+ });
9477
+ server.registerTool("list_gameplay_tags", {
9478
+ description: "List the gameplay tags the project knows about, with the source that declared each one and its comment, optionally filtered to a prefix and everything under it. Check here before create_gameplay_tag: a tag that already exists under a slightly different spelling is the usual cause of a GAS setup that silently never matches.",
9479
+ inputSchema: listGameplayTagsInputSchema,
9480
+ title: "List Gameplay Tags"
9481
+ }, async ({ cursor, maxResults, prefix, projectId }) => {
9482
+ return toToolSuccess(await listGameplayTags({
7244
9483
  cursor,
7245
9484
  maxResults,
9485
+ prefix,
9486
+ projectId
9487
+ }, dependencies));
9488
+ });
9489
+ server.registerTool("create_landscape", {
9490
+ description: "Create a landscape actor in the loaded level with explicit component sizing, optionally importing a heightmap from a file on disk. quadsPerSection and sectionsPerComponent are the engine's own constrained values; the response reports the resulting vertex resolution, which is the coordinate space sculpt_landscape and paint_landscape_layer regions are expressed in. Heightmaps are always read from a path — they are orders of magnitude too large to travel in a bridge frame.",
9491
+ inputSchema: createLandscapeInputSchema,
9492
+ title: "Create Landscape"
9493
+ }, async ({ componentCountX, componentCountY, heightmapFilePath, label, location, projectId, quadsPerSection, rotation, scale, sectionsPerComponent }) => {
9494
+ return toToolSuccess(await createLandscape({
9495
+ componentCountX,
9496
+ componentCountY,
9497
+ heightmapFilePath,
9498
+ label,
9499
+ location,
7246
9500
  projectId,
7247
- referenceKinds
9501
+ quadsPerSection,
9502
+ rotation,
9503
+ scale,
9504
+ sectionsPerComponent
7248
9505
  }, dependencies));
7249
9506
  });
7250
- server.registerTool("get_blueprint_summary", {
7251
- description: "Describe what is inside a Blueprint asset: parent class, implemented interfaces, its component hierarchy from the Simple Construction Script, its variables (type, default, category, replication), its functions/events/macros with signatures, and an inventory of its graphs. Use the returned graph names with get_blueprint_graph. By default nothing is loaded — an unloaded Blueprint answers from Asset Registry metadata (parent and generated class only) and reports loaded=false; pass loadIfNeeded to read the full contents. Each list pages independently.",
7252
- inputSchema: getBlueprintSummaryInputSchema,
7253
- title: "Get Blueprint Summary"
7254
- }, async ({ blueprintPath, componentCursor, functionCursor, graphCursor, loadIfNeeded, maxResults, projectId, variableCursor }) => {
7255
- return toToolSuccess(await getBlueprintSummary({
7256
- blueprintPath,
7257
- componentCursor,
7258
- functionCursor,
7259
- graphCursor,
7260
- loadIfNeeded,
7261
- maxResults,
9507
+ server.registerTool("sculpt_landscape", {
9508
+ description: "Write landscape heights over a rectangular region: flatten to a height, ramp between two, apply noise, or import a heightmap file. This edits an explicit region rather than simulating brush strokes, so the result is reproducible. Region coordinates are landscape vertices, as create_landscape reports through resolutionX / resolutionY.",
9509
+ inputSchema: sculptLandscapeInputSchema,
9510
+ title: "Sculpt Landscape"
9511
+ }, async ({ actorPath, height, heightmapFilePath, mode, noiseAmplitude, noiseFrequency, noiseSeed, projectId, rampAxis, rampEndHeight, rampStartHeight, region }) => {
9512
+ return toToolSuccess(await sculptLandscape({
9513
+ actorPath,
9514
+ height,
9515
+ heightmapFilePath,
9516
+ mode,
9517
+ noiseAmplitude,
9518
+ noiseFrequency,
9519
+ noiseSeed,
7262
9520
  projectId,
7263
- variableCursor
9521
+ rampAxis,
9522
+ rampEndHeight,
9523
+ rampStartHeight,
9524
+ region
7264
9525
  }, dependencies));
7265
9526
  });
7266
- server.registerTool("get_blueprint_graph", {
7267
- description: "Dump one Blueprint graph as nodes and connections: each node reports its title, node class and pins, and each pin reports its name, direction, type, default value and the node/pin ids it links to. Get valid graph names from get_blueprint_summary first. Reading a graph requires the Blueprint in memory, so pass loadIfNeeded for an unloaded asset. Nodes are ordered by their stable GUID and paged via nextNodeCursor.",
7268
- inputSchema: getBlueprintGraphInputSchema,
7269
- title: "Get Blueprint Graph"
7270
- }, async ({ blueprintPath, graphName, loadIfNeeded, maxNodes, nodeCursor, projectId }) => {
7271
- return toToolSuccess(await getBlueprintGraph({
7272
- blueprintPath,
7273
- graphName,
7274
- loadIfNeeded,
7275
- maxNodes,
7276
- nodeCursor,
9527
+ server.registerTool("paint_landscape_layer", {
9528
+ description: "Write a landscape weight layer over a rectangular region, so the layer shows through the landscape material. The layer must already exist in the landscape's target layer list. Region coordinates are landscape vertices.",
9529
+ inputSchema: paintLandscapeLayerInputSchema,
9530
+ title: "Paint Landscape Layer"
9531
+ }, async ({ actorPath, layerName, projectId, region, weight }) => {
9532
+ return toToolSuccess(await paintLandscapeLayer({
9533
+ actorPath,
9534
+ layerName,
9535
+ projectId,
9536
+ region,
9537
+ weight
9538
+ }, dependencies));
9539
+ });
9540
+ server.registerTool("run_geometry_script", {
9541
+ description: "Generate geometry with Geometry Script: an ordered list of operations run against one dynamic mesh, so a whole shape — a box minus a cylinder, a swept profile, a displaced sphere — is built in a single call. Bake the result to a static mesh asset, or leave it on a placed dynamic mesh actor to keep iterating. Returns triangle and vertex counts so the shape can be sanity-checked without opening the editor. An operation that fails names its index in the list. Requires the Geometry Script plugin enabled in the project; if it is not, the call says so by name.",
9542
+ inputSchema: runGeometryScriptInputSchema,
9543
+ title: "Run Geometry Script"
9544
+ }, async ({ actorTransform, assetName, assetPath, label, operations, output, projectId }) => {
9545
+ return toToolSuccess(await runGeometryScript({
9546
+ actorTransform,
9547
+ assetName,
9548
+ assetPath,
9549
+ label,
9550
+ operations,
9551
+ output,
7277
9552
  projectId
7278
9553
  }, dependencies));
7279
9554
  });
7280
- server.registerTool("get_blueprint_compile_errors", {
7281
- description: "Report each Blueprint's compile status (up_to_date, warnings, error, dirty, unknown, not_loaded, not_found) plus the errors and warnings from the last compile this bridge ran, including the node each message was attached to. hasDiagnostics=false means this bridge has not compiled that Blueprint in this editor session, so empty lists do not mean it is clean — run compile_blueprint first to get diagnostics.",
7282
- inputSchema: getBlueprintCompileErrorsInputSchema,
7283
- title: "Get Blueprint Compile Errors"
7284
- }, async ({ blueprintPaths, cursor, maxResults, projectId }) => {
7285
- return toToolSuccess(await getBlueprintCompileErrors({
7286
- blueprintPaths,
9555
+ server.registerTool("list_data_layers", {
9556
+ description: "List the World Partition data layers of the loaded map, each with its editor loaded and visible state and its runtime state. isWorldPartition false means the map is not World Partition at all, so the empty list means there are none rather than none loaded.",
9557
+ inputSchema: listDataLayersInputSchema,
9558
+ title: "List Data Layers"
9559
+ }, async ({ cursor, maxResults, projectId }) => {
9560
+ return toToolSuccess(await listDataLayers({
7287
9561
  cursor,
7288
9562
  maxResults,
7289
9563
  projectId
7290
9564
  }, dependencies));
7291
9565
  });
7292
- server.registerTool("compile_blueprint", {
7293
- description: "Compile one or more Blueprints in the running editor so content breakage is caught after a C++ change that altered a base class or a UFUNCTION signature. Compiling is asynchronous: this returns a compileJobId to poll with get_blueprint_compile_status, which reports the per-Blueprint diagnostics. Blueprints are loaded as needed and their assets are modified in memory — save them with save_dirty_packages if you want the result on disk.",
7294
- inputSchema: compileBlueprintInputSchema,
7295
- title: "Compile Blueprint"
7296
- }, async ({ blueprintPaths, projectId }) => {
7297
- return toToolSuccess(await compileBlueprint({
7298
- blueprintPaths,
9566
+ server.registerTool("set_data_layer_state", {
9567
+ description: "Set World Partition data layer state: editor loaded, editor visible, and runtime state where the layer is a runtime layer. Every field is optional per entry, so an omitted one is left alone rather than reset.",
9568
+ inputSchema: setDataLayerStateInputSchema,
9569
+ title: "Set Data Layer State"
9570
+ }, async ({ entries, projectId }) => {
9571
+ return toToolSuccess(await setDataLayerState({
9572
+ entries,
7299
9573
  projectId
7300
9574
  }, dependencies));
7301
9575
  });
7302
- server.registerTool("get_blueprint_compile_status", {
7303
- description: "Poll a compile_blueprint job. Reports 'compiling' while it runs, then 'succeeded' or 'failed' with per-Blueprint errors and warnings (each carrying the node the compiler blamed); 'unknown_job' means the id was never issued or has been evicted.",
7304
- inputSchema: getBlueprintCompileStatusInputSchema,
7305
- title: "Get Blueprint Compile Status"
7306
- }, async ({ compileJobId, cursor, maxResults, projectId }) => {
7307
- return toToolSuccess(await getBlueprintCompileStatus({
7308
- compileJobId,
7309
- cursor,
7310
- maxResults,
7311
- projectId
9576
+ server.registerTool("load_wp_region", {
9577
+ description: "Pin a spatial region of a World Partition map into editor memory so the actors inside it become visible to list_actors and editable by the level tools. This matters for correctness, not convenience: in a World Partition map, actors in unloaded cells are simply not in memory, so list_actors under-reports and every edit tool silently no-ops on them. Unpin regions when done — a session that keeps pinning will run out of memory. pinnedRegionCount reports what is currently held.",
9578
+ inputSchema: loadWpRegionInputSchema,
9579
+ title: "Load World Partition Region"
9580
+ }, async ({ action, projectId, region, regionId }) => {
9581
+ return toToolSuccess(await loadWpRegion({
9582
+ action,
9583
+ projectId,
9584
+ region,
9585
+ regionId
7312
9586
  }, dependencies));
7313
9587
  });
7314
9588
  }
@@ -8997,6 +11271,10 @@ function clampWaitForJobTimeoutMs(kind, timeoutMs) {
8997
11271
  }
8998
11272
  async function pollJobStatus(kind, jobId, projectId, dependencies) {
8999
11273
  switch (kind) {
11274
+ case "build": return await getBuildJobStatus({
11275
+ buildJobId: jobId,
11276
+ projectId
11277
+ }, dependencies);
9000
11278
  case "compile": return await getCompileStatus({
9001
11279
  compileJobId: jobId,
9002
11280
  projectId
@@ -9021,6 +11299,7 @@ async function pollJobStatus(kind, jobId, projectId, dependencies) {
9021
11299
  }
9022
11300
  function classifyJobStatus(kind, status) {
9023
11301
  switch (kind) {
11302
+ case "build": return status.state === "running" ? "pending" : toTerminalOutcome(status.state === "unknown_job");
9024
11303
  case "compile": return status.state === "compiling" ? "pending" : toTerminalOutcome(status.state === "unknown_job");
9025
11304
  case "create_class": return status.state === "creating" ? "pending" : toTerminalOutcome(status.state === "unknown_job");
9026
11305
  case "pie": return status.state === "starting" ? "pending" : "completed";
@@ -9064,6 +11343,495 @@ async function sleep(delayMs) {
9064
11343
  setTimeout(resolve, delayMs);
9065
11344
  });
9066
11345
  }
11346
+ const CREATIVE_RESPONSE_ENVELOPE_FIELDS = /* @__PURE__ */ new Set([
11347
+ "ok",
11348
+ "requestId",
11349
+ "type",
11350
+ "version"
11351
+ ]);
11352
+ function toCreativeResult(response, projectId) {
11353
+ const result = { projectId };
11354
+ for (const [key, value] of Object.entries(response)) if (!CREATIVE_RESPONSE_ENVELOPE_FIELDS.has(key)) result[key] = value;
11355
+ return result;
11356
+ }
11357
+ async function exchangeCreativeRequest(request, send, requestType, projectId, dependencies) {
11358
+ const entry = dependencies.registry.getProject(projectId);
11359
+ if (!entry) throw new Error(`No registered Unreal engine was found for projectId '${projectId}'.`);
11360
+ const response = await send(request, {
11361
+ connectTimeoutMs: deriveBridgeConnectTimeoutMs$1(dependencies.pingTimeoutMs),
11362
+ host: BRIDGE_LOOPBACK_HOST,
11363
+ port: entry.port,
11364
+ readTimeoutMs: deriveEditorWorkTimeoutMs(dependencies.pingTimeoutMs)
11365
+ });
11366
+ if (!response.ok) {
11367
+ const { error } = response;
11368
+ throw new Error(`Bridge ${requestType} failed (${error.code}): ${error.message}`);
11369
+ }
11370
+ return toCreativeResult(response, entry.projectId);
11371
+ }
11372
+ const creativeProjectIdSchema = projectIdSchema.describe("Canonical Unreal ProjectID whose registered editor should run this request.");
11373
+ const listAssetFactoriesInputSchema = {
11374
+ cursor: bridgeListAssetFactoriesRequestSchema.shape.cursor.describe("nextCursor from a previous response, to fetch the following page."),
11375
+ maxResults: bridgeListAssetFactoriesRequestSchema.shape.maxResults.describe(`Maximum factories per page (1-${String(100)}). Defaults to ${String(50)}.`),
11376
+ nameFilter: bridgeListAssetFactoriesRequestSchema.shape.nameFilter.describe("Case-insensitive substring matched against the factory class, the produced asset class and the menu category, e.g. 'material' or 'input'."),
11377
+ projectId: creativeProjectIdSchema
11378
+ };
11379
+ const createAssetInputSchema = {
11380
+ assetClass: bridgeCreateAssetRequestSchema.shape.assetClass.describe("Class of asset to create, as list_asset_factories reports it (e.g. 'DataTable', 'Material', 'InputAction')."),
11381
+ assetName: bridgeCreateAssetRequestSchema.shape.assetName.describe("Name of the new asset, a single path segment with no '/' or '.' (e.g. 'DT_Weapons')."),
11382
+ factoryClass: bridgeCreateAssetRequestSchema.shape.factoryClass.describe("Factory class to use, when more than one produces assetClass. Omit to let the editor pick."),
11383
+ options: bridgeCreateAssetRequestSchema.shape.options.describe("Reflected properties set on the factory before it runs, as name-to-ExportText pairs (e.g. { ParentClass: \"/Script/Engine.Actor\" }). This is how a factory that would otherwise open a modal picker is configured. list_asset_factories reports each factory's requiredOptions."),
11384
+ packagePath: bridgeCreateAssetRequestSchema.shape.packagePath.describe("Content folder the asset is created in (e.g. '/Game/Data'). Must be under /Game."),
11385
+ projectId: creativeProjectIdSchema
11386
+ };
11387
+ const duplicateAssetInputSchema = {
11388
+ destinationName: bridgeDuplicateAssetRequestSchema.shape.destinationName.describe("Name of the copy, a single path segment."),
11389
+ destinationPath: bridgeDuplicateAssetRequestSchema.shape.destinationPath.describe("Content folder the copy is written to (e.g. '/Game/Weapons')."),
11390
+ projectId: creativeProjectIdSchema,
11391
+ sourceAssetPath: bridgeDuplicateAssetRequestSchema.shape.sourceAssetPath.describe("Package name or object path of the asset to copy.")
11392
+ };
11393
+ const renameAssetInputSchema = {
11394
+ assetPath: bridgeRenameAssetRequestSchema.shape.assetPath.describe("Package name or object path of the asset to rename."),
11395
+ newName: bridgeRenameAssetRequestSchema.shape.newName.describe("New name, a single path segment."),
11396
+ projectId: creativeProjectIdSchema
11397
+ };
11398
+ const moveAssetInputSchema = {
11399
+ assetPath: bridgeMoveAssetRequestSchema.shape.assetPath.describe("Package name or object path of the asset to move."),
11400
+ destinationPath: bridgeMoveAssetRequestSchema.shape.destinationPath.describe("Content folder to move it into (e.g. '/Game/Weapons/Rifles')."),
11401
+ newName: bridgeMoveAssetRequestSchema.shape.newName.describe("Optional new name; omit to keep the current one."),
11402
+ projectId: creativeProjectIdSchema
11403
+ };
11404
+ const deleteAssetInputSchema = {
11405
+ assetPath: bridgeDeleteAssetRequestSchema.shape.assetPath.describe("Package name or object path of the asset to delete."),
11406
+ force: bridgeDeleteAssetRequestSchema.shape.force.describe("Delete even when other assets reference it, leaving those references dangling. Defaults to false, which refuses and reports the referencers instead."),
11407
+ projectId: creativeProjectIdSchema
11408
+ };
11409
+ const saveAssetInputSchema = {
11410
+ assetPaths: bridgeSaveAssetRequestSchema.shape.assetPaths.describe(`Package names or object paths of the assets to save (1-${String(64)}).`),
11411
+ projectId: creativeProjectIdSchema
11412
+ };
11413
+ const createFolderInputSchema = {
11414
+ folderPath: bridgeCreateFolderRequestSchema.shape.folderPath.describe("Content folder to create (e.g. '/Game/Weapons/Rifles'). Must be under /Game."),
11415
+ projectId: creativeProjectIdSchema
11416
+ };
11417
+ const getAssetMetadataInputSchema = {
11418
+ assetPath: bridgeGetAssetMetadataRequestSchema.shape.assetPath.describe("Package name or object path of the asset to inspect."),
11419
+ projectId: creativeProjectIdSchema
11420
+ };
11421
+ const listGraphNodesInputSchema = {
11422
+ assetPath: bridgeListGraphNodesRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
11423
+ cursor: bridgeListGraphNodesRequestSchema.shape.cursor.describe("nextCursor from a previous response, to fetch the following page."),
11424
+ graphName: bridgeListGraphNodesRequestSchema.shape.graphName.describe("Graph to read, as get_blueprint_summary reports it (e.g. 'EventGraph')."),
11425
+ loadIfNeeded: bridgeListGraphNodesRequestSchema.shape.loadIfNeeded.describe("Load the asset when it is not already in memory. Defaults to true; false reports 'blueprint_not_loaded' instead, which is the cheaper answer when a large Blueprint's load could outrun the request budget."),
11426
+ maxResults: bridgeListGraphNodesRequestSchema.shape.maxResults.describe(`Maximum nodes per page (1-${String(100)}). Defaults to ${String(25)}.`),
11427
+ projectId: creativeProjectIdSchema
11428
+ };
11429
+ const addGraphNodeInputSchema = {
11430
+ assetPath: bridgeAddGraphNodeRequestFieldsSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
11431
+ graphName: bridgeAddGraphNodeRequestFieldsSchema.shape.graphName.describe("Graph to add the node to."),
11432
+ kind: bridgeAddGraphNodeRequestFieldsSchema.shape.kind.describe("How the node is named: 'class' places a node type directly, 'function' places a call, 'variable_get' / 'variable_set' place a variable accessor."),
11433
+ memberName: bridgeAddGraphNodeRequestFieldsSchema.shape.memberName.describe("Function or variable name, required for every kind except 'class'."),
11434
+ memberParentClass: bridgeAddGraphNodeRequestFieldsSchema.shape.memberParentClass.describe("Class owning memberName; omit for a call or variable on the Blueprint itself."),
11435
+ nodeClass: bridgeAddGraphNodeRequestFieldsSchema.shape.nodeClass.describe("UEdGraphNode subclass to place, required for kind 'class' (e.g. 'K2Node_IfThenElse'). list_available_nodes reports what this graph's schema accepts."),
11436
+ pinDefaults: bridgeAddGraphNodeRequestFieldsSchema.shape.pinDefaults.describe("Pin name to ExportText default value, applied after the node is created so one call produces a configured node."),
11437
+ position: bridgeAddGraphNodeRequestFieldsSchema.shape.position.describe("Graph-space position for the node; defaults to the origin."),
11438
+ projectId: creativeProjectIdSchema
11439
+ };
11440
+ const removeGraphNodeInputSchema = {
11441
+ assetPath: bridgeRemoveGraphNodeRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
11442
+ graphName: bridgeRemoveGraphNodeRequestSchema.shape.graphName.describe("Graph the node lives in."),
11443
+ nodeGuid: bridgeRemoveGraphNodeRequestSchema.shape.nodeGuid.describe("nodeId from list_graph_nodes or add_graph_node. Nodes are addressed by GUID, never by index."),
11444
+ projectId: creativeProjectIdSchema
11445
+ };
11446
+ const connectPinsInputSchema = {
11447
+ assetPath: bridgeConnectPinsRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
11448
+ graphName: bridgeConnectPinsRequestSchema.shape.graphName.describe("Graph both nodes live in."),
11449
+ projectId: creativeProjectIdSchema,
11450
+ sourceNodeGuid: bridgeConnectPinsRequestSchema.shape.sourceNodeGuid.describe("nodeId of the node the wire leaves."),
11451
+ sourcePinName: bridgeConnectPinsRequestSchema.shape.sourcePinName.describe("Pin name on the source node."),
11452
+ targetNodeGuid: bridgeConnectPinsRequestSchema.shape.targetNodeGuid.describe("nodeId of the node the wire enters."),
11453
+ targetPinName: bridgeConnectPinsRequestSchema.shape.targetPinName.describe("Pin name on the target node.")
11454
+ };
11455
+ const disconnectPinsInputSchema = {
11456
+ assetPath: bridgeDisconnectPinsRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
11457
+ graphName: bridgeDisconnectPinsRequestSchema.shape.graphName.describe("Graph both nodes live in."),
11458
+ projectId: creativeProjectIdSchema,
11459
+ sourceNodeGuid: bridgeDisconnectPinsRequestSchema.shape.sourceNodeGuid.describe("nodeId of one end of the wire."),
11460
+ sourcePinName: bridgeDisconnectPinsRequestSchema.shape.sourcePinName.describe("Pin name on the source node."),
11461
+ targetNodeGuid: bridgeDisconnectPinsRequestSchema.shape.targetNodeGuid.describe("nodeId of the other end."),
11462
+ targetPinName: bridgeDisconnectPinsRequestSchema.shape.targetPinName.describe("Pin name on the target node.")
11463
+ };
11464
+ const setPinDefaultInputSchema = {
11465
+ assetPath: bridgeSetPinDefaultRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
11466
+ graphName: bridgeSetPinDefaultRequestSchema.shape.graphName.describe("Graph the node lives in."),
11467
+ nodeGuid: bridgeSetPinDefaultRequestSchema.shape.nodeGuid.describe("nodeId of the node holding the pin."),
11468
+ pinName: bridgeSetPinDefaultRequestSchema.shape.pinName.describe("Pin to set."),
11469
+ projectId: creativeProjectIdSchema,
11470
+ value: bridgeSetPinDefaultRequestSchema.shape.value.describe("ExportText value, the same format get_actor_details emits and set_actor_property accepts.")
11471
+ };
11472
+ const listAvailableNodesInputSchema = {
11473
+ assetPath: bridgeListAvailableNodesRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
11474
+ cursor: bridgeListAvailableNodesRequestSchema.shape.cursor.describe("nextCursor from a previous response, to fetch the following page."),
11475
+ graphName: bridgeListAvailableNodesRequestSchema.shape.graphName.describe("Graph whose schema decides what is legal to place."),
11476
+ maxResults: bridgeListAvailableNodesRequestSchema.shape.maxResults.describe(`Maximum actions per page (1-${String(100)}). Defaults to ${String(25)}.`),
11477
+ nameFilter: bridgeListAvailableNodesRequestSchema.shape.nameFilter.describe("Case-insensitive substring matched against the action title, category and keywords. Strongly recommended: an unfiltered Blueprint action database runs to thousands of entries."),
11478
+ projectId: creativeProjectIdSchema
11479
+ };
11480
+ const setViewportCameraInputSchema = {
11481
+ fov: bridgeSetViewportCameraRequestSchema.shape.fov.describe(`Field of view in degrees (${String(5)}-${String(170)}); perspective views only.`),
11482
+ location: bridgeSetViewportCameraRequestSchema.shape.location.describe("World-space camera position."),
11483
+ orthoWidth: bridgeSetViewportCameraRequestSchema.shape.orthoWidth.describe("Orthographic width in world units; ignored for a perspective view type."),
11484
+ projectId: creativeProjectIdSchema,
11485
+ rotation: bridgeSetViewportCameraRequestSchema.shape.rotation.describe("Camera rotation in degrees."),
11486
+ viewType: bridgeSetViewportCameraRequestSchema.shape.viewType.describe("Projection to switch the viewport to; omit to keep the current one.")
11487
+ };
11488
+ const focusActorsInputSchema = {
11489
+ actorPaths: bridgeFocusActorsRequestSchema.shape.actorPaths.describe(`Actor object paths to frame (1-${String(64)}), as list_actors reports them.`),
11490
+ instant: bridgeFocusActorsRequestSchema.shape.instant.describe("Skip the editor easing animation so a capture taken right after this request already shows the framed result. Defaults to true."),
11491
+ projectId: creativeProjectIdSchema
11492
+ };
11493
+ const setViewModeInputSchema = {
11494
+ projectId: creativeProjectIdSchema,
11495
+ viewMode: bridgeSetViewModeRequestSchema.shape.viewMode.describe("View mode to switch the active viewport to.")
11496
+ };
11497
+ const toggleShowFlagsInputSchema = {
11498
+ flags: bridgeToggleShowFlagsRequestSchema.shape.flags.describe(`Show flags to set, by FEngineShowFlags name (1-${String(32)}), e.g. [{ name: 'Bounds', enabled: true }].`),
11499
+ projectId: creativeProjectIdSchema
11500
+ };
11501
+ const highResScreenshotInputSchema = {
11502
+ fileName: bridgeHighResScreenshotRequestSchema.shape.fileName.describe("File name only, no path — the capture always lands under the project's Saved/Screenshots."),
11503
+ includeUi: bridgeHighResScreenshotRequestSchema.shape.includeUi.describe("Include editor UI in the capture. Defaults to false."),
11504
+ multiplier: bridgeHighResScreenshotRequestSchema.shape.multiplier.describe(`Resolution multiplier over the viewport's own size (1-${String(8)}). Defaults to 1.`),
11505
+ projectId: creativeProjectIdSchema
11506
+ };
11507
+ const duplicateActorInputSchema = {
11508
+ actors: bridgeDuplicateActorRequestSchema.shape.actors.describe(`Actors to duplicate (1-${String(64)}), each optionally with a world-space offset applied to the copy.`),
11509
+ dryRun: bridgeDuplicateActorRequestSchema.shape.dryRun.describe("Resolve every entry without duplicating anything, so a batch can be validated first."),
11510
+ projectId: creativeProjectIdSchema
11511
+ };
11512
+ const attachActorInputSchema = {
11513
+ attachments: bridgeAttachActorRequestSchema.shape.attachments.describe(`Attachments to apply (1-${String(64)}). An empty parentActorPath detaches the child instead.`),
11514
+ dryRun: bridgeAttachActorRequestSchema.shape.dryRun.describe("Resolve every entry without attaching anything."),
11515
+ projectId: creativeProjectIdSchema
11516
+ };
11517
+ const addActorComponentInputSchema = {
11518
+ components: bridgeAddActorComponentRequestSchema.shape.components.describe(`Instance components to add (1-${String(64)}).`),
11519
+ dryRun: bridgeAddActorComponentRequestSchema.shape.dryRun.describe("Resolve every entry without adding anything."),
11520
+ projectId: creativeProjectIdSchema
11521
+ };
11522
+ const setActorTagsInputSchema = {
11523
+ dryRun: bridgeSetActorTagsRequestSchema.shape.dryRun.describe("Resolve every entry without writing anything."),
11524
+ entries: bridgeSetActorTagsRequestSchema.shape.entries.describe(`Tag writes (1-${String(64)}). mode 'set' replaces the actor's tags, 'add' unions, 'remove' subtracts.`),
11525
+ projectId: creativeProjectIdSchema
11526
+ };
11527
+ const moveToFolderInputSchema = {
11528
+ dryRun: bridgeMoveToFolderRequestSchema.shape.dryRun.describe("Resolve every entry without moving anything."),
11529
+ entries: bridgeMoveToFolderRequestSchema.shape.entries.describe(`Outliner folder moves (1-${String(64)}). An empty folderPath moves the actor to the outliner root.`),
11530
+ projectId: creativeProjectIdSchema
11531
+ };
11532
+ const placeAssetInputSchema = {
11533
+ dryRun: bridgePlaceAssetRequestSchema.shape.dryRun.describe("Resolve every entry without placing anything."),
11534
+ placements: bridgePlaceAssetRequestSchema.shape.placements.describe(`Assets to place in the level (1-${String(64)}). The actor factory picks the actor class, so a static mesh becomes a StaticMeshActor and a Blueprint becomes its own class.`),
11535
+ projectId: creativeProjectIdSchema
11536
+ };
11537
+ const replaceActorsInputSchema = {
11538
+ actorPaths: bridgeReplaceActorsRequestFieldsSchema.shape.actorPaths.describe(`Actors to replace (1-${String(64)}).`),
11539
+ dryRun: bridgeReplaceActorsRequestFieldsSchema.shape.dryRun.describe("Resolve every entry without replacing anything."),
11540
+ projectId: creativeProjectIdSchema,
11541
+ replacementAssetPath: bridgeReplaceActorsRequestFieldsSchema.shape.replacementAssetPath.describe("Asset the replacements are built from, routed through the same actor factory place_asset uses. Give exactly one of replacementAssetPath or replacementClass."),
11542
+ replacementClass: bridgeReplaceActorsRequestFieldsSchema.shape.replacementClass.describe("Actor class to replace with, for a replacement that has no asset behind it.")
11543
+ };
11544
+ const startEditorBuildInputSchema = {
11545
+ hlodAction: bridgeStartEditorBuildRequestSchema.shape.hlodAction.describe("What a HLOD build should do; ignored by every other build kind. Defaults to 'build_all'."),
11546
+ projectId: creativeProjectIdSchema,
11547
+ quality: bridgeStartEditorBuildRequestSchema.shape.quality.describe("Lightmass quality preset; lighting builds only. Defaults to 'preview'.")
11548
+ };
11549
+ const getBuildJobStatusInputSchema = {
11550
+ buildJobId: bridgeGetBuildJobStatusRequestSchema.shape.buildJobId.describe("buildJobId returned by one of the build_* tools."),
11551
+ projectId: creativeProjectIdSchema
11552
+ };
11553
+ const createGameplayTagInputSchema = {
11554
+ comment: bridgeCreateGameplayTagRequestSchema.shape.comment.describe("Developer comment stored alongside the tag, shown in the editor's tag picker."),
11555
+ projectId: creativeProjectIdSchema,
11556
+ source: bridgeCreateGameplayTagRequestSchema.shape.source.describe("Tag source .ini basename (e.g. 'Abilities.ini' under Config/Tags). Omit to write to DefaultGameplayTags.ini."),
11557
+ tagName: bridgeCreateGameplayTagRequestSchema.shape.tagName.describe("Hierarchical tag name, dot-separated (e.g. 'Ability.Melee.Heavy').")
11558
+ };
11559
+ const listGameplayTagsInputSchema = {
11560
+ cursor: bridgeListGameplayTagsRequestSchema.shape.cursor.describe("nextCursor from a previous response, to fetch the following page."),
11561
+ maxResults: bridgeListGameplayTagsRequestSchema.shape.maxResults.describe(`Maximum tags per page (1-${String(200)}). Defaults to ${String(50)}.`),
11562
+ prefix: bridgeListGameplayTagsRequestSchema.shape.prefix.describe("Return only this tag and everything under it (e.g. 'Ability' matches 'Ability.Melee.Heavy')."),
11563
+ projectId: creativeProjectIdSchema
11564
+ };
11565
+ const createLandscapeInputSchema = {
11566
+ componentCountX: bridgeCreateLandscapeRequestSchema.shape.componentCountX.describe(`Landscape components along X (1-${String(32)}).`),
11567
+ componentCountY: bridgeCreateLandscapeRequestSchema.shape.componentCountY.describe(`Landscape components along Y (1-${String(32)}).`),
11568
+ heightmapFilePath: bridgeCreateLandscapeRequestSchema.shape.heightmapFilePath.describe("Absolute path to a 16-bit greyscale PNG or raw .r16 to import as the starting heights. Heightmaps never travel inline — they do not fit in a bridge frame."),
11569
+ label: bridgeCreateLandscapeRequestSchema.shape.label.describe("Outliner label for the new landscape actor."),
11570
+ location: bridgeCreateLandscapeRequestSchema.shape.location.describe("World-space origin of the landscape."),
11571
+ projectId: creativeProjectIdSchema,
11572
+ quadsPerSection: bridgeCreateLandscapeRequestSchema.shape.quadsPerSection.describe("Quads per landscape section. The engine only accepts 7, 15, 31, 63, 127 or 255."),
11573
+ rotation: bridgeCreateLandscapeRequestSchema.shape.rotation.describe("Rotation of the landscape actor."),
11574
+ scale: bridgeCreateLandscapeRequestSchema.shape.scale.describe("Draw scale; Z scales the height range. Defaults to 100,100,100."),
11575
+ sectionsPerComponent: bridgeCreateLandscapeRequestSchema.shape.sectionsPerComponent.describe("Sections per component: 1 or 4.")
11576
+ };
11577
+ const sculptLandscapeInputSchema = {
11578
+ actorPath: bridgeSculptLandscapeRequestFieldsSchema.shape.actorPath.describe("Object path of the landscape actor to sculpt."),
11579
+ height: bridgeSculptLandscapeRequestFieldsSchema.shape.height.describe("Target height in landscape units; required for mode 'flatten'."),
11580
+ heightmapFilePath: bridgeSculptLandscapeRequestFieldsSchema.shape.heightmapFilePath.describe("Absolute path to a 16-bit heightmap; required for mode 'heightmap_file'."),
11581
+ mode: bridgeSculptLandscapeRequestFieldsSchema.shape.mode.describe("How the new heights are derived."),
11582
+ noiseAmplitude: bridgeSculptLandscapeRequestFieldsSchema.shape.noiseAmplitude.describe("Peak-to-centre noise height; required for mode 'noise'."),
11583
+ noiseFrequency: bridgeSculptLandscapeRequestFieldsSchema.shape.noiseFrequency.describe("Noise frequency per vertex (0-1). Defaults to 0.05."),
11584
+ noiseSeed: bridgeSculptLandscapeRequestFieldsSchema.shape.noiseSeed.describe("Seed, so the same request reproduces the same terrain."),
11585
+ projectId: creativeProjectIdSchema,
11586
+ rampAxis: bridgeSculptLandscapeRequestFieldsSchema.shape.rampAxis.describe("Axis the ramp runs along; defaults to 'x'."),
11587
+ rampEndHeight: bridgeSculptLandscapeRequestFieldsSchema.shape.rampEndHeight.describe("Height at the far edge of the region; required for mode 'ramp'."),
11588
+ rampStartHeight: bridgeSculptLandscapeRequestFieldsSchema.shape.rampStartHeight.describe("Height at the near edge of the region; required for mode 'ramp'."),
11589
+ region: bridgeSculptLandscapeRequestFieldsSchema.shape.region.describe("Inclusive rectangle in landscape vertex coordinates, as create_landscape reports through resolutionX / resolutionY.")
11590
+ };
11591
+ const paintLandscapeLayerInputSchema = {
11592
+ actorPath: bridgePaintLandscapeLayerRequestSchema.shape.actorPath.describe("Object path of the landscape actor to paint."),
11593
+ layerName: bridgePaintLandscapeLayerRequestSchema.shape.layerName.describe("Weight layer to write, as it appears in the landscape's target layer list."),
11594
+ projectId: creativeProjectIdSchema,
11595
+ region: bridgePaintLandscapeLayerRequestSchema.shape.region.describe("Inclusive rectangle in landscape vertex coordinates."),
11596
+ weight: bridgePaintLandscapeLayerRequestSchema.shape.weight.describe("Layer weight to write across the region (0-1).")
11597
+ };
11598
+ const runGeometryScriptInputSchema = {
11599
+ actorTransform: bridgeRunGeometryScriptRequestFieldsSchema.shape.actorTransform.describe("Where the actor is placed; output 'dynamic_mesh_actor' only."),
11600
+ assetName: bridgeRunGeometryScriptRequestFieldsSchema.shape.assetName.describe("Name of the baked static mesh asset; required for output 'static_mesh'."),
11601
+ assetPath: bridgeRunGeometryScriptRequestFieldsSchema.shape.assetPath.describe("Content folder the baked asset is written to; required for output 'static_mesh'."),
11602
+ label: bridgeRunGeometryScriptRequestFieldsSchema.shape.label.describe("Outliner label; output 'dynamic_mesh_actor' only."),
11603
+ operations: bridgeRunGeometryScriptRequestFieldsSchema.shape.operations.describe("Ordered operations run against one dynamic mesh. append_* adds a primitive, subtract_* / intersect_* boolean one against the working mesh, and the rest transform or clean it up. Each carries a numeric params map (box: dimensionX/dimensionY/dimensionZ; sphere: radius, stepsPhi, stepsTheta; cylinder and cone: radius, height, radialSteps; torus: majorRadius, minorRadius, majorSteps, minorSteps; translate/scale: x, y, z; rotate: pitch, roll, yaw; apply_displace_noise: magnitude, frequency, seed; simplify_to_triangle_count: triangleCount) plus an optional transform placing the primitive."),
11604
+ output: bridgeRunGeometryScriptRequestFieldsSchema.shape.output.describe("Where the finished mesh lands: baked into a static mesh asset, or left on a placed dynamic mesh actor to keep iterating on."),
11605
+ projectId: creativeProjectIdSchema
11606
+ };
11607
+ const listDataLayersInputSchema = {
11608
+ cursor: bridgeListDataLayersRequestSchema.shape.cursor.describe("nextCursor from a previous response, to fetch the following page."),
11609
+ maxResults: bridgeListDataLayersRequestSchema.shape.maxResults.describe(`Maximum data layers per page (1-${String(100)}). Defaults to ${String(50)}.`),
11610
+ projectId: creativeProjectIdSchema
11611
+ };
11612
+ const setDataLayerStateInputSchema = {
11613
+ entries: bridgeSetDataLayerStateRequestSchema.shape.entries.describe(`Data layer state writes (1-${String(32)}). Every field is optional per entry — omitted leaves that aspect alone.`),
11614
+ projectId: creativeProjectIdSchema
11615
+ };
11616
+ const loadWpRegionInputSchema = {
11617
+ action: bridgeLoadWpRegionRequestFieldsSchema.shape.action.describe("'pin' loads a spatial region's cells and holds them, 'unpin' releases one by regionId, 'unpin_all' releases every region this bridge pinned."),
11618
+ projectId: creativeProjectIdSchema,
11619
+ region: bridgeLoadWpRegionRequestFieldsSchema.shape.region.describe("World-space box to load; required for action 'pin'."),
11620
+ regionId: bridgeLoadWpRegionRequestFieldsSchema.shape.regionId.describe("Handle returned by a previous pin; required for action 'unpin'.")
11621
+ };
11622
+ async function listAssetFactories(input, dependencies) {
11623
+ return await exchangeCreativeRequest(createBridgeListAssetFactoriesRequest({
11624
+ cursor: input.cursor,
11625
+ maxResults: input.maxResults,
11626
+ nameFilter: input.nameFilter
11627
+ }), sendBridgeListAssetFactoriesRequest, BRIDGE_LIST_ASSET_FACTORIES_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11628
+ }
11629
+ async function createAsset(input, dependencies) {
11630
+ return await exchangeCreativeRequest(createBridgeCreateAssetRequest(input.assetClass, input.assetName, input.packagePath, {
11631
+ factoryClass: input.factoryClass,
11632
+ options: input.options
11633
+ }), sendBridgeCreateAssetRequest, BRIDGE_CREATE_ASSET_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11634
+ }
11635
+ async function duplicateAsset(input, dependencies) {
11636
+ return await exchangeCreativeRequest(createBridgeDuplicateAssetRequest(input.sourceAssetPath, input.destinationPath, input.destinationName), sendBridgeDuplicateAssetRequest, BRIDGE_DUPLICATE_ASSET_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11637
+ }
11638
+ async function renameAsset(input, dependencies) {
11639
+ return await exchangeCreativeRequest(createBridgeRenameAssetRequest(input.assetPath, input.newName), sendBridgeRenameAssetRequest, BRIDGE_RENAME_ASSET_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11640
+ }
11641
+ async function moveAsset(input, dependencies) {
11642
+ return await exchangeCreativeRequest(createBridgeMoveAssetRequest(input.assetPath, input.destinationPath, { newName: input.newName }), sendBridgeMoveAssetRequest, BRIDGE_MOVE_ASSET_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11643
+ }
11644
+ async function deleteAsset(input, dependencies) {
11645
+ return await exchangeCreativeRequest(createBridgeDeleteAssetRequest(input.assetPath, { force: input.force }), sendBridgeDeleteAssetRequest, BRIDGE_DELETE_ASSET_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11646
+ }
11647
+ async function saveAsset(input, dependencies) {
11648
+ return await exchangeCreativeRequest(createBridgeSaveAssetRequest(input.assetPaths), sendBridgeSaveAssetRequest, BRIDGE_SAVE_ASSET_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11649
+ }
11650
+ async function createFolder(input, dependencies) {
11651
+ return await exchangeCreativeRequest(createBridgeCreateFolderRequest(input.folderPath), sendBridgeCreateFolderRequest, BRIDGE_CREATE_FOLDER_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11652
+ }
11653
+ async function getAssetMetadata(input, dependencies) {
11654
+ return await exchangeCreativeRequest(createBridgeGetAssetMetadataRequest(input.assetPath), sendBridgeGetAssetMetadataRequest, BRIDGE_GET_ASSET_METADATA_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11655
+ }
11656
+ async function listGraphNodes(input, dependencies) {
11657
+ return await exchangeCreativeRequest(createBridgeListGraphNodesRequest(input.assetPath, input.graphName, {
11658
+ cursor: input.cursor,
11659
+ loadIfNeeded: input.loadIfNeeded,
11660
+ maxResults: input.maxResults
11661
+ }), sendBridgeListGraphNodesRequest, BRIDGE_LIST_GRAPH_NODES_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11662
+ }
11663
+ async function addGraphNode(input, dependencies) {
11664
+ return await exchangeCreativeRequest(createBridgeAddGraphNodeRequest(input.assetPath, input.graphName, input.kind, {
11665
+ memberName: input.memberName,
11666
+ memberParentClass: input.memberParentClass,
11667
+ nodeClass: input.nodeClass,
11668
+ pinDefaults: input.pinDefaults,
11669
+ position: input.position
11670
+ }), sendBridgeAddGraphNodeRequest, BRIDGE_ADD_GRAPH_NODE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11671
+ }
11672
+ async function removeGraphNode(input, dependencies) {
11673
+ return await exchangeCreativeRequest(createBridgeRemoveGraphNodeRequest(input.assetPath, input.graphName, input.nodeGuid), sendBridgeRemoveGraphNodeRequest, BRIDGE_REMOVE_GRAPH_NODE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11674
+ }
11675
+ async function connectPins(input, dependencies) {
11676
+ return await exchangeCreativeRequest(createBridgeConnectPinsRequest(input.assetPath, input.graphName, {
11677
+ nodeGuid: input.sourceNodeGuid,
11678
+ pinName: input.sourcePinName
11679
+ }, {
11680
+ nodeGuid: input.targetNodeGuid,
11681
+ pinName: input.targetPinName
11682
+ }), sendBridgeConnectPinsRequest, BRIDGE_CONNECT_PINS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11683
+ }
11684
+ async function disconnectPins(input, dependencies) {
11685
+ return await exchangeCreativeRequest(createBridgeDisconnectPinsRequest(input.assetPath, input.graphName, {
11686
+ nodeGuid: input.sourceNodeGuid,
11687
+ pinName: input.sourcePinName
11688
+ }, {
11689
+ nodeGuid: input.targetNodeGuid,
11690
+ pinName: input.targetPinName
11691
+ }), sendBridgeDisconnectPinsRequest, BRIDGE_DISCONNECT_PINS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11692
+ }
11693
+ async function setPinDefault(input, dependencies) {
11694
+ return await exchangeCreativeRequest(createBridgeSetPinDefaultRequest(input.assetPath, input.graphName, input.nodeGuid, input.pinName, input.value), sendBridgeSetPinDefaultRequest, BRIDGE_SET_PIN_DEFAULT_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11695
+ }
11696
+ async function listAvailableNodes(input, dependencies) {
11697
+ return await exchangeCreativeRequest(createBridgeListAvailableNodesRequest(input.assetPath, input.graphName, {
11698
+ cursor: input.cursor,
11699
+ maxResults: input.maxResults,
11700
+ nameFilter: input.nameFilter
11701
+ }), sendBridgeListAvailableNodesRequest, BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11702
+ }
11703
+ async function setViewportCamera(input, dependencies) {
11704
+ return await exchangeCreativeRequest(createBridgeSetViewportCameraRequest({
11705
+ fov: input.fov,
11706
+ location: input.location,
11707
+ orthoWidth: input.orthoWidth,
11708
+ rotation: input.rotation,
11709
+ viewType: input.viewType
11710
+ }), sendBridgeSetViewportCameraRequest, BRIDGE_SET_VIEWPORT_CAMERA_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11711
+ }
11712
+ async function focusActors(input, dependencies) {
11713
+ return await exchangeCreativeRequest(createBridgeFocusActorsRequest(input.actorPaths, { instant: input.instant }), sendBridgeFocusActorsRequest, BRIDGE_FOCUS_ACTORS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11714
+ }
11715
+ async function setViewMode(input, dependencies) {
11716
+ return await exchangeCreativeRequest(createBridgeSetViewModeRequest(input.viewMode), sendBridgeSetViewModeRequest, BRIDGE_SET_VIEW_MODE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11717
+ }
11718
+ async function toggleShowFlags(input, dependencies) {
11719
+ return await exchangeCreativeRequest(createBridgeToggleShowFlagsRequest(input.flags), sendBridgeToggleShowFlagsRequest, BRIDGE_TOGGLE_SHOW_FLAGS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11720
+ }
11721
+ async function highResScreenshot(input, dependencies) {
11722
+ return await exchangeCreativeRequest(createBridgeHighResScreenshotRequest({
11723
+ fileName: input.fileName,
11724
+ includeUi: input.includeUi,
11725
+ multiplier: input.multiplier
11726
+ }), sendBridgeHighResScreenshotRequest, BRIDGE_HIGH_RES_SCREENSHOT_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11727
+ }
11728
+ async function duplicateActor(input, dependencies) {
11729
+ return await exchangeCreativeRequest(createBridgeDuplicateActorRequest(input.actors, { dryRun: input.dryRun }), sendBridgeDuplicateActorRequest, BRIDGE_DUPLICATE_ACTOR_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11730
+ }
11731
+ async function attachActor(input, dependencies) {
11732
+ return await exchangeCreativeRequest(createBridgeAttachActorRequest(input.attachments, { dryRun: input.dryRun }), sendBridgeAttachActorRequest, BRIDGE_ATTACH_ACTOR_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11733
+ }
11734
+ async function addActorComponent(input, dependencies) {
11735
+ return await exchangeCreativeRequest(createBridgeAddActorComponentRequest(input.components, { dryRun: input.dryRun }), sendBridgeAddActorComponentRequest, BRIDGE_ADD_ACTOR_COMPONENT_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11736
+ }
11737
+ async function setActorTags(input, dependencies) {
11738
+ return await exchangeCreativeRequest(createBridgeSetActorTagsRequest(input.entries, { dryRun: input.dryRun }), sendBridgeSetActorTagsRequest, BRIDGE_SET_ACTOR_TAGS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11739
+ }
11740
+ async function moveToFolder(input, dependencies) {
11741
+ return await exchangeCreativeRequest(createBridgeMoveToFolderRequest(input.entries, { dryRun: input.dryRun }), sendBridgeMoveToFolderRequest, BRIDGE_MOVE_TO_FOLDER_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11742
+ }
11743
+ async function placeAsset(input, dependencies) {
11744
+ return await exchangeCreativeRequest(createBridgePlaceAssetRequest(input.placements, { dryRun: input.dryRun }), sendBridgePlaceAssetRequest, BRIDGE_PLACE_ASSET_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11745
+ }
11746
+ async function replaceActors(input, dependencies) {
11747
+ return await exchangeCreativeRequest(createBridgeReplaceActorsRequest(input.actorPaths, {
11748
+ assetPath: input.replacementAssetPath,
11749
+ className: input.replacementClass
11750
+ }, { dryRun: input.dryRun }), sendBridgeReplaceActorsRequest, BRIDGE_REPLACE_ACTORS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11751
+ }
11752
+ async function startEditorBuild(input, dependencies) {
11753
+ return await exchangeCreativeRequest(createBridgeStartEditorBuildRequest(input.buildKind, {
11754
+ hlodAction: input.hlodAction,
11755
+ quality: input.quality
11756
+ }), sendBridgeStartEditorBuildRequest, BRIDGE_START_EDITOR_BUILD_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11757
+ }
11758
+ async function getBuildJobStatus(input, dependencies) {
11759
+ return await exchangeCreativeRequest(createBridgeGetBuildJobStatusRequest(input.buildJobId), sendBridgeGetBuildJobStatusRequest, BRIDGE_GET_BUILD_JOB_STATUS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11760
+ }
11761
+ async function createGameplayTag(input, dependencies) {
11762
+ return await exchangeCreativeRequest(createBridgeCreateGameplayTagRequest(input.tagName, {
11763
+ comment: input.comment,
11764
+ source: input.source
11765
+ }), sendBridgeCreateGameplayTagRequest, BRIDGE_CREATE_GAMEPLAY_TAG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11766
+ }
11767
+ async function listGameplayTags(input, dependencies) {
11768
+ return await exchangeCreativeRequest(createBridgeListGameplayTagsRequest({
11769
+ cursor: input.cursor,
11770
+ maxResults: input.maxResults,
11771
+ prefix: input.prefix
11772
+ }), sendBridgeListGameplayTagsRequest, BRIDGE_LIST_GAMEPLAY_TAGS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11773
+ }
11774
+ async function createLandscape(input, dependencies) {
11775
+ return await exchangeCreativeRequest(createBridgeCreateLandscapeRequest({
11776
+ componentCountX: input.componentCountX,
11777
+ componentCountY: input.componentCountY,
11778
+ quadsPerSection: input.quadsPerSection,
11779
+ sectionsPerComponent: input.sectionsPerComponent
11780
+ }, {
11781
+ heightmapFilePath: input.heightmapFilePath,
11782
+ label: input.label,
11783
+ location: input.location,
11784
+ rotation: input.rotation,
11785
+ scale: input.scale
11786
+ }), sendBridgeCreateLandscapeRequest, BRIDGE_CREATE_LANDSCAPE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11787
+ }
11788
+ async function sculptLandscape(input, dependencies) {
11789
+ return await exchangeCreativeRequest(createBridgeSculptLandscapeRequest(input.actorPath, input.mode, input.region, {
11790
+ height: input.height,
11791
+ heightmapFilePath: input.heightmapFilePath,
11792
+ noiseAmplitude: input.noiseAmplitude,
11793
+ noiseFrequency: input.noiseFrequency,
11794
+ noiseSeed: input.noiseSeed,
11795
+ rampAxis: input.rampAxis,
11796
+ rampEndHeight: input.rampEndHeight,
11797
+ rampStartHeight: input.rampStartHeight
11798
+ }), sendBridgeSculptLandscapeRequest, BRIDGE_SCULPT_LANDSCAPE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11799
+ }
11800
+ async function paintLandscapeLayer(input, dependencies) {
11801
+ return await exchangeCreativeRequest(createBridgePaintLandscapeLayerRequest(input.actorPath, input.layerName, input.region, input.weight), sendBridgePaintLandscapeLayerRequest, BRIDGE_PAINT_LANDSCAPE_LAYER_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11802
+ }
11803
+ async function runGeometryScript(input, dependencies) {
11804
+ return await exchangeCreativeRequest(createBridgeRunGeometryScriptRequest(input.operations, input.output, {
11805
+ actorTransform: input.actorTransform,
11806
+ assetName: input.assetName,
11807
+ assetPath: input.assetPath,
11808
+ label: input.label
11809
+ }), sendBridgeRunGeometryScriptRequest, BRIDGE_RUN_GEOMETRY_SCRIPT_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11810
+ }
11811
+ async function listDataLayers(input, dependencies) {
11812
+ return await exchangeCreativeRequest(createBridgeListDataLayersRequest({
11813
+ cursor: input.cursor,
11814
+ maxResults: input.maxResults
11815
+ }), sendBridgeListDataLayersRequest, BRIDGE_LIST_DATA_LAYERS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11816
+ }
11817
+ async function setDataLayerState(input, dependencies) {
11818
+ return await exchangeCreativeRequest(createBridgeSetDataLayerStateRequest(input.entries), sendBridgeSetDataLayerStateRequest, BRIDGE_SET_DATA_LAYER_STATE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11819
+ }
11820
+ async function loadWpRegion(input, dependencies) {
11821
+ return await exchangeCreativeRequest(createBridgeLoadWpRegionRequest(input.action, {
11822
+ region: input.region,
11823
+ regionId: input.regionId
11824
+ }), sendBridgeLoadWpRegionRequest, BRIDGE_LOAD_WP_REGION_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
11825
+ }
11826
+ const buildLightingInputSchema = {
11827
+ projectId: creativeProjectIdSchema,
11828
+ quality: startEditorBuildInputSchema.quality
11829
+ };
11830
+ const buildHlodInputSchema = {
11831
+ hlodAction: startEditorBuildInputSchema.hlodAction,
11832
+ projectId: creativeProjectIdSchema
11833
+ };
11834
+ const buildOnlyInputSchema = { projectId: creativeProjectIdSchema };
9067
11835
  //#endregion
9068
11836
  //#region src/projectId.ts
9069
11837
  const GENERAL_PROJECT_SETTINGS_SECTION = "[/Script/EngineSettings.GeneralProjectSettings]";
@@ -9281,7 +12049,7 @@ function isMissingFileError(error) {
9281
12049
  //#endregion
9282
12050
  //#region src/server.ts
9283
12051
  const SERVER_NAME = "ue-mcp-server";
9284
- const SERVER_VERSION = "1.2.0";
12052
+ const SERVER_VERSION = "1.3.0";
9285
12053
  const logger = createModuleLogger("bootstrap");
9286
12054
  const enginePingLogger = createModuleLogger("engine-ping");
9287
12055
  const httpApiLogger = createModuleLogger("http-api");