unreal-engine-mcp-server 0.4.7 → 0.5.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 (438) hide show
  1. package/.env.example +26 -0
  2. package/.env.production +38 -7
  3. package/.eslintrc.json +0 -54
  4. package/.eslintrc.override.json +8 -0
  5. package/.github/ISSUE_TEMPLATE/bug_report.yml +94 -0
  6. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  7. package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
  8. package/.github/copilot-instructions.md +478 -45
  9. package/.github/dependabot.yml +19 -0
  10. package/.github/labeler.yml +24 -0
  11. package/.github/labels.yml +70 -0
  12. package/.github/pull_request_template.md +42 -0
  13. package/.github/release-drafter.yml +148 -0
  14. package/.github/workflows/auto-merge.yml +38 -0
  15. package/.github/workflows/ci.yml +38 -0
  16. package/.github/workflows/dependency-review.yml +17 -0
  17. package/.github/workflows/gemini-issue-triage.yml +172 -0
  18. package/.github/workflows/greetings.yml +23 -0
  19. package/.github/workflows/labeler.yml +16 -0
  20. package/.github/workflows/links.yml +80 -0
  21. package/.github/workflows/pr-size-labeler.yml +137 -0
  22. package/.github/workflows/publish-mcp.yml +12 -7
  23. package/.github/workflows/release-drafter.yml +23 -0
  24. package/.github/workflows/release.yml +112 -0
  25. package/.github/workflows/semantic-pull-request.yml +35 -0
  26. package/.github/workflows/smoke-test.yml +36 -0
  27. package/.github/workflows/stale.yml +28 -0
  28. package/CHANGELOG.md +267 -31
  29. package/CONTRIBUTING.md +140 -0
  30. package/README.md +166 -71
  31. package/claude_desktop_config_example.json +7 -6
  32. package/dist/automation/bridge.d.ts +50 -0
  33. package/dist/automation/bridge.js +452 -0
  34. package/dist/automation/connection-manager.d.ts +23 -0
  35. package/dist/automation/connection-manager.js +107 -0
  36. package/dist/automation/handshake.d.ts +11 -0
  37. package/dist/automation/handshake.js +89 -0
  38. package/dist/automation/index.d.ts +3 -0
  39. package/dist/automation/index.js +3 -0
  40. package/dist/automation/message-handler.d.ts +12 -0
  41. package/dist/automation/message-handler.js +149 -0
  42. package/dist/automation/request-tracker.d.ts +25 -0
  43. package/dist/automation/request-tracker.js +98 -0
  44. package/dist/automation/types.d.ts +130 -0
  45. package/dist/automation/types.js +2 -0
  46. package/dist/cli.js +32 -5
  47. package/dist/config.d.ts +27 -0
  48. package/dist/config.js +60 -0
  49. package/dist/constants.d.ts +12 -0
  50. package/dist/constants.js +12 -0
  51. package/dist/graphql/resolvers.d.ts +268 -0
  52. package/dist/graphql/resolvers.js +743 -0
  53. package/dist/graphql/schema.d.ts +5 -0
  54. package/dist/graphql/schema.js +437 -0
  55. package/dist/graphql/server.d.ts +26 -0
  56. package/dist/graphql/server.js +115 -0
  57. package/dist/graphql/types.d.ts +7 -0
  58. package/dist/graphql/types.js +2 -0
  59. package/dist/handlers/resource-handlers.d.ts +20 -0
  60. package/dist/handlers/resource-handlers.js +180 -0
  61. package/dist/index.d.ts +31 -18
  62. package/dist/index.js +119 -619
  63. package/dist/prompts/index.js +4 -4
  64. package/dist/resources/actors.d.ts +17 -12
  65. package/dist/resources/actors.js +56 -76
  66. package/dist/resources/assets.d.ts +6 -14
  67. package/dist/resources/assets.js +115 -147
  68. package/dist/resources/levels.d.ts +13 -13
  69. package/dist/resources/levels.js +25 -34
  70. package/dist/server/resource-registry.d.ts +20 -0
  71. package/dist/server/resource-registry.js +37 -0
  72. package/dist/server/tool-registry.d.ts +23 -0
  73. package/dist/server/tool-registry.js +322 -0
  74. package/dist/server-setup.d.ts +21 -0
  75. package/dist/server-setup.js +111 -0
  76. package/dist/services/health-monitor.d.ts +34 -0
  77. package/dist/services/health-monitor.js +105 -0
  78. package/dist/services/metrics-server.d.ts +11 -0
  79. package/dist/services/metrics-server.js +105 -0
  80. package/dist/tools/actors.d.ts +147 -9
  81. package/dist/tools/actors.js +350 -311
  82. package/dist/tools/animation.d.ts +135 -4
  83. package/dist/tools/animation.js +510 -411
  84. package/dist/tools/assets.d.ts +117 -19
  85. package/dist/tools/assets.js +259 -284
  86. package/dist/tools/audio.d.ts +102 -42
  87. package/dist/tools/audio.js +272 -685
  88. package/dist/tools/base-tool.d.ts +17 -0
  89. package/dist/tools/base-tool.js +46 -0
  90. package/dist/tools/behavior-tree.d.ts +94 -0
  91. package/dist/tools/behavior-tree.js +39 -0
  92. package/dist/tools/blueprint/helpers.d.ts +29 -0
  93. package/dist/tools/blueprint/helpers.js +182 -0
  94. package/dist/tools/blueprint.d.ts +228 -118
  95. package/dist/tools/blueprint.js +685 -832
  96. package/dist/tools/consolidated-tool-definitions.d.ts +5462 -1781
  97. package/dist/tools/consolidated-tool-definitions.js +829 -496
  98. package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
  99. package/dist/tools/consolidated-tool-handlers.js +211 -1026
  100. package/dist/tools/debug.d.ts +143 -85
  101. package/dist/tools/debug.js +234 -180
  102. package/dist/tools/dynamic-handler-registry.d.ts +11 -0
  103. package/dist/tools/dynamic-handler-registry.js +101 -0
  104. package/dist/tools/editor.d.ts +139 -18
  105. package/dist/tools/editor.js +239 -244
  106. package/dist/tools/engine.d.ts +10 -4
  107. package/dist/tools/engine.js +13 -5
  108. package/dist/tools/environment.d.ts +36 -0
  109. package/dist/tools/environment.js +267 -0
  110. package/dist/tools/foliage.d.ts +105 -14
  111. package/dist/tools/foliage.js +219 -331
  112. package/dist/tools/handlers/actor-handlers.d.ts +3 -0
  113. package/dist/tools/handlers/actor-handlers.js +232 -0
  114. package/dist/tools/handlers/animation-handlers.d.ts +3 -0
  115. package/dist/tools/handlers/animation-handlers.js +185 -0
  116. package/dist/tools/handlers/argument-helper.d.ts +16 -0
  117. package/dist/tools/handlers/argument-helper.js +80 -0
  118. package/dist/tools/handlers/asset-handlers.d.ts +3 -0
  119. package/dist/tools/handlers/asset-handlers.js +496 -0
  120. package/dist/tools/handlers/audio-handlers.d.ts +3 -0
  121. package/dist/tools/handlers/audio-handlers.js +166 -0
  122. package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
  123. package/dist/tools/handlers/blueprint-handlers.js +358 -0
  124. package/dist/tools/handlers/common-handlers.d.ts +14 -0
  125. package/dist/tools/handlers/common-handlers.js +56 -0
  126. package/dist/tools/handlers/editor-handlers.d.ts +3 -0
  127. package/dist/tools/handlers/editor-handlers.js +119 -0
  128. package/dist/tools/handlers/effect-handlers.d.ts +3 -0
  129. package/dist/tools/handlers/effect-handlers.js +171 -0
  130. package/dist/tools/handlers/environment-handlers.d.ts +3 -0
  131. package/dist/tools/handlers/environment-handlers.js +170 -0
  132. package/dist/tools/handlers/graph-handlers.d.ts +3 -0
  133. package/dist/tools/handlers/graph-handlers.js +90 -0
  134. package/dist/tools/handlers/input-handlers.d.ts +3 -0
  135. package/dist/tools/handlers/input-handlers.js +21 -0
  136. package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
  137. package/dist/tools/handlers/inspect-handlers.js +383 -0
  138. package/dist/tools/handlers/level-handlers.d.ts +3 -0
  139. package/dist/tools/handlers/level-handlers.js +237 -0
  140. package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
  141. package/dist/tools/handlers/lighting-handlers.js +144 -0
  142. package/dist/tools/handlers/performance-handlers.d.ts +3 -0
  143. package/dist/tools/handlers/performance-handlers.js +130 -0
  144. package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
  145. package/dist/tools/handlers/pipeline-handlers.js +110 -0
  146. package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
  147. package/dist/tools/handlers/sequence-handlers.js +376 -0
  148. package/dist/tools/handlers/system-handlers.d.ts +4 -0
  149. package/dist/tools/handlers/system-handlers.js +506 -0
  150. package/dist/tools/input.d.ts +19 -0
  151. package/dist/tools/input.js +89 -0
  152. package/dist/tools/introspection.d.ts +103 -40
  153. package/dist/tools/introspection.js +425 -568
  154. package/dist/tools/landscape.d.ts +97 -36
  155. package/dist/tools/landscape.js +280 -409
  156. package/dist/tools/level.d.ts +130 -10
  157. package/dist/tools/level.js +639 -675
  158. package/dist/tools/lighting.d.ts +77 -38
  159. package/dist/tools/lighting.js +441 -943
  160. package/dist/tools/logs.d.ts +3 -3
  161. package/dist/tools/logs.js +5 -57
  162. package/dist/tools/materials.d.ts +91 -24
  163. package/dist/tools/materials.js +190 -118
  164. package/dist/tools/niagara.d.ts +149 -39
  165. package/dist/tools/niagara.js +232 -182
  166. package/dist/tools/performance.d.ts +27 -12
  167. package/dist/tools/performance.js +204 -122
  168. package/dist/tools/physics.d.ts +32 -77
  169. package/dist/tools/physics.js +171 -582
  170. package/dist/tools/property-dictionary.d.ts +13 -0
  171. package/dist/tools/property-dictionary.js +82 -0
  172. package/dist/tools/sequence.d.ts +73 -48
  173. package/dist/tools/sequence.js +196 -748
  174. package/dist/tools/tool-definition-utils.d.ts +59 -0
  175. package/dist/tools/tool-definition-utils.js +35 -0
  176. package/dist/tools/ui.d.ts +66 -34
  177. package/dist/tools/ui.js +134 -214
  178. package/dist/types/env.d.ts +0 -3
  179. package/dist/types/env.js +0 -7
  180. package/dist/types/tool-interfaces.d.ts +898 -0
  181. package/dist/types/tool-interfaces.js +2 -0
  182. package/dist/types/tool-types.d.ts +183 -19
  183. package/dist/types/tool-types.js +0 -4
  184. package/dist/unreal-bridge.d.ts +24 -131
  185. package/dist/unreal-bridge.js +364 -1506
  186. package/dist/utils/command-validator.d.ts +9 -0
  187. package/dist/utils/command-validator.js +67 -0
  188. package/dist/utils/elicitation.d.ts +1 -1
  189. package/dist/utils/elicitation.js +12 -15
  190. package/dist/utils/error-handler.d.ts +2 -51
  191. package/dist/utils/error-handler.js +11 -87
  192. package/dist/utils/ini-reader.d.ts +3 -0
  193. package/dist/utils/ini-reader.js +69 -0
  194. package/dist/utils/logger.js +9 -6
  195. package/dist/utils/normalize.d.ts +3 -0
  196. package/dist/utils/normalize.js +56 -0
  197. package/dist/utils/response-factory.d.ts +7 -0
  198. package/dist/utils/response-factory.js +33 -0
  199. package/dist/utils/response-validator.d.ts +3 -24
  200. package/dist/utils/response-validator.js +130 -81
  201. package/dist/utils/result-helpers.d.ts +4 -5
  202. package/dist/utils/result-helpers.js +15 -16
  203. package/dist/utils/safe-json.js +5 -11
  204. package/dist/utils/unreal-command-queue.d.ts +24 -0
  205. package/dist/utils/unreal-command-queue.js +120 -0
  206. package/dist/utils/validation.d.ts +0 -40
  207. package/dist/utils/validation.js +1 -78
  208. package/dist/wasm/index.d.ts +70 -0
  209. package/dist/wasm/index.js +535 -0
  210. package/docs/GraphQL-API.md +888 -0
  211. package/docs/Migration-Guide-v0.5.0.md +692 -0
  212. package/docs/Roadmap.md +53 -0
  213. package/docs/WebAssembly-Integration.md +628 -0
  214. package/docs/editor-plugin-extension.md +370 -0
  215. package/docs/handler-mapping.md +242 -0
  216. package/docs/native-automation-progress.md +128 -0
  217. package/docs/testing-guide.md +423 -0
  218. package/mcp-config-example.json +6 -6
  219. package/package.json +60 -27
  220. package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
  221. package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
  222. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
  223. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
  224. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
  225. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
  226. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
  227. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
  228. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
  229. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
  230. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
  231. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
  232. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
  233. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
  234. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
  235. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
  236. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
  237. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
  238. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
  239. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
  240. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
  241. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
  242. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
  243. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
  244. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
  245. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
  246. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
  247. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
  248. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
  249. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
  250. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
  251. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
  252. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
  253. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
  254. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
  255. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
  256. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
  257. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
  258. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
  259. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
  260. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
  261. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
  262. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
  263. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
  264. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
  265. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
  266. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
  267. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
  268. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
  269. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
  270. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
  271. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
  272. package/scripts/check-unreal-connection.mjs +19 -0
  273. package/scripts/clean-tmp.js +23 -0
  274. package/scripts/patch-wasm.js +26 -0
  275. package/scripts/run-all-tests.mjs +131 -0
  276. package/scripts/smoke-test.ts +94 -0
  277. package/scripts/sync-mcp-plugin.js +143 -0
  278. package/scripts/test-no-plugin-alternates.mjs +113 -0
  279. package/scripts/validate-server.js +46 -0
  280. package/scripts/verify-automation-bridge.js +200 -0
  281. package/server.json +57 -21
  282. package/src/automation/bridge.ts +558 -0
  283. package/src/automation/connection-manager.ts +130 -0
  284. package/src/automation/handshake.ts +99 -0
  285. package/src/automation/index.ts +2 -0
  286. package/src/automation/message-handler.ts +167 -0
  287. package/src/automation/request-tracker.ts +123 -0
  288. package/src/automation/types.ts +107 -0
  289. package/src/cli.ts +33 -6
  290. package/src/config.ts +73 -0
  291. package/src/constants.ts +12 -0
  292. package/src/graphql/resolvers.ts +1010 -0
  293. package/src/graphql/schema.ts +452 -0
  294. package/src/graphql/server.ts +154 -0
  295. package/src/graphql/types.ts +7 -0
  296. package/src/handlers/resource-handlers.ts +186 -0
  297. package/src/index.ts +152 -663
  298. package/src/prompts/index.ts +4 -4
  299. package/src/resources/actors.ts +58 -76
  300. package/src/resources/assets.ts +147 -134
  301. package/src/resources/levels.ts +28 -33
  302. package/src/server/resource-registry.ts +47 -0
  303. package/src/server/tool-registry.ts +354 -0
  304. package/src/server-setup.ts +148 -0
  305. package/src/services/health-monitor.ts +132 -0
  306. package/src/services/metrics-server.ts +142 -0
  307. package/src/tools/actors.ts +417 -322
  308. package/src/tools/animation.ts +671 -461
  309. package/src/tools/assets.ts +353 -289
  310. package/src/tools/audio.ts +323 -766
  311. package/src/tools/base-tool.ts +52 -0
  312. package/src/tools/behavior-tree.ts +45 -0
  313. package/src/tools/blueprint/helpers.ts +189 -0
  314. package/src/tools/blueprint.ts +787 -965
  315. package/src/tools/consolidated-tool-definitions.ts +993 -515
  316. package/src/tools/consolidated-tool-handlers.ts +272 -1139
  317. package/src/tools/debug.ts +292 -187
  318. package/src/tools/dynamic-handler-registry.ts +151 -0
  319. package/src/tools/editor.ts +309 -246
  320. package/src/tools/engine.ts +14 -3
  321. package/src/tools/environment.ts +287 -0
  322. package/src/tools/foliage.ts +314 -379
  323. package/src/tools/handlers/actor-handlers.ts +271 -0
  324. package/src/tools/handlers/animation-handlers.ts +237 -0
  325. package/src/tools/handlers/argument-helper.ts +142 -0
  326. package/src/tools/handlers/asset-handlers.ts +532 -0
  327. package/src/tools/handlers/audio-handlers.ts +194 -0
  328. package/src/tools/handlers/blueprint-handlers.ts +380 -0
  329. package/src/tools/handlers/common-handlers.ts +87 -0
  330. package/src/tools/handlers/editor-handlers.ts +123 -0
  331. package/src/tools/handlers/effect-handlers.ts +220 -0
  332. package/src/tools/handlers/environment-handlers.ts +183 -0
  333. package/src/tools/handlers/graph-handlers.ts +116 -0
  334. package/src/tools/handlers/input-handlers.ts +28 -0
  335. package/src/tools/handlers/inspect-handlers.ts +450 -0
  336. package/src/tools/handlers/level-handlers.ts +252 -0
  337. package/src/tools/handlers/lighting-handlers.ts +147 -0
  338. package/src/tools/handlers/performance-handlers.ts +132 -0
  339. package/src/tools/handlers/pipeline-handlers.ts +127 -0
  340. package/src/tools/handlers/sequence-handlers.ts +415 -0
  341. package/src/tools/handlers/system-handlers.ts +564 -0
  342. package/src/tools/input.ts +101 -0
  343. package/src/tools/introspection.ts +493 -584
  344. package/src/tools/landscape.ts +394 -489
  345. package/src/tools/level.ts +752 -694
  346. package/src/tools/lighting.ts +583 -984
  347. package/src/tools/logs.ts +9 -57
  348. package/src/tools/materials.ts +231 -121
  349. package/src/tools/niagara.ts +293 -168
  350. package/src/tools/performance.ts +320 -168
  351. package/src/tools/physics.ts +268 -613
  352. package/src/tools/property-dictionary.ts +98 -0
  353. package/src/tools/sequence.ts +255 -815
  354. package/src/tools/tool-definition-utils.ts +35 -0
  355. package/src/tools/ui.ts +207 -283
  356. package/src/types/env.ts +0 -10
  357. package/src/types/tool-interfaces.ts +250 -0
  358. package/src/types/tool-types.ts +243 -21
  359. package/src/unreal-bridge.ts +460 -1550
  360. package/src/utils/command-validator.ts +75 -0
  361. package/src/utils/elicitation.ts +10 -7
  362. package/src/utils/error-handler.ts +14 -90
  363. package/src/utils/ini-reader.ts +86 -0
  364. package/src/utils/logger.ts +8 -3
  365. package/src/utils/normalize.ts +60 -0
  366. package/src/utils/response-factory.ts +39 -0
  367. package/src/utils/response-validator.ts +176 -56
  368. package/src/utils/result-helpers.ts +21 -19
  369. package/src/utils/safe-json.ts +14 -11
  370. package/src/utils/unreal-command-queue.ts +152 -0
  371. package/src/utils/validation.ts +4 -1
  372. package/src/wasm/index.ts +838 -0
  373. package/test-server.mjs +100 -0
  374. package/tests/run-unreal-tool-tests.mjs +242 -14
  375. package/tests/test-animation.mjs +44 -0
  376. package/tests/test-asset-advanced.mjs +82 -0
  377. package/tests/test-asset-errors.mjs +35 -0
  378. package/tests/test-audio.mjs +219 -0
  379. package/tests/test-automation-timeouts.mjs +98 -0
  380. package/tests/test-behavior-tree.mjs +261 -0
  381. package/tests/test-blueprint-events.mjs +35 -0
  382. package/tests/test-blueprint-graph.mjs +79 -0
  383. package/tests/test-blueprint.mjs +577 -0
  384. package/tests/test-client-mode.mjs +86 -0
  385. package/tests/test-console-command.mjs +56 -0
  386. package/tests/test-control-actor.mjs +425 -0
  387. package/tests/test-control-editor.mjs +80 -0
  388. package/tests/test-extra-tools.mjs +38 -0
  389. package/tests/test-graphql.mjs +322 -0
  390. package/tests/test-inspect.mjs +72 -0
  391. package/tests/test-landscape.mjs +60 -0
  392. package/tests/test-manage-asset.mjs +438 -0
  393. package/tests/test-manage-level.mjs +70 -0
  394. package/tests/test-materials.mjs +356 -0
  395. package/tests/test-niagara.mjs +185 -0
  396. package/tests/test-no-inline-python.mjs +122 -0
  397. package/tests/test-plugin-handshake.mjs +82 -0
  398. package/tests/test-render.mjs +33 -0
  399. package/tests/test-runner.mjs +933 -0
  400. package/tests/test-search-assets.mjs +66 -0
  401. package/tests/test-sequence.mjs +68 -0
  402. package/tests/test-system.mjs +57 -0
  403. package/tests/test-wasm.mjs +193 -0
  404. package/tests/test-world-partition.mjs +215 -0
  405. package/tsconfig.json +3 -3
  406. package/wasm/Cargo.lock +363 -0
  407. package/wasm/Cargo.toml +42 -0
  408. package/wasm/LICENSE +21 -0
  409. package/wasm/README.md +253 -0
  410. package/wasm/src/dependency_resolver.rs +377 -0
  411. package/wasm/src/lib.rs +153 -0
  412. package/wasm/src/property_parser.rs +271 -0
  413. package/wasm/src/transform_math.rs +396 -0
  414. package/wasm/tests/integration.rs +109 -0
  415. package/.github/workflows/smithery-build.yml +0 -29
  416. package/dist/tools/build_environment_advanced.d.ts +0 -65
  417. package/dist/tools/build_environment_advanced.js +0 -633
  418. package/dist/tools/rc.d.ts +0 -110
  419. package/dist/tools/rc.js +0 -437
  420. package/dist/tools/visual.d.ts +0 -40
  421. package/dist/tools/visual.js +0 -282
  422. package/dist/utils/http.d.ts +0 -6
  423. package/dist/utils/http.js +0 -151
  424. package/dist/utils/python-output.d.ts +0 -18
  425. package/dist/utils/python-output.js +0 -290
  426. package/dist/utils/python.d.ts +0 -2
  427. package/dist/utils/python.js +0 -4
  428. package/dist/utils/stdio-redirect.d.ts +0 -2
  429. package/dist/utils/stdio-redirect.js +0 -20
  430. package/docs/unreal-tool-test-cases.md +0 -574
  431. package/smithery.yaml +0 -29
  432. package/src/tools/build_environment_advanced.ts +0 -732
  433. package/src/tools/rc.ts +0 -515
  434. package/src/tools/visual.ts +0 -281
  435. package/src/utils/http.ts +0 -187
  436. package/src/utils/python-output.ts +0 -351
  437. package/src/utils/python.ts +0 -3
  438. package/src/utils/stdio-redirect.ts +0 -18
@@ -0,0 +1,532 @@
1
+ import { cleanObject } from '../../utils/safe-json.js';
2
+ import { ITools } from '../../types/tool-interfaces.js';
3
+ import { executeAutomationRequest } from './common-handlers.js';
4
+ import { normalizeArgs } from './argument-helper.js';
5
+
6
+ export async function handleAssetTools(action: string, args: any, tools: ITools) {
7
+ switch (action) {
8
+ case 'list': {
9
+ // Route through C++ HandleListAssets for proper asset enumeration
10
+ const params = normalizeArgs(args, [
11
+ { key: 'path', aliases: ['directory', 'assetPath'], default: '/Game' },
12
+ { key: 'limit', default: 50 },
13
+ { key: 'recursive', default: false },
14
+ { key: 'depth', default: undefined }
15
+ ]);
16
+
17
+ const recursive = params.recursive === true || (params.depth !== undefined && params.depth > 0);
18
+
19
+ const res = await executeAutomationRequest(tools, 'list', {
20
+ path: params.path,
21
+ recursive,
22
+ depth: params.depth
23
+ });
24
+
25
+ // const result = cleanObject(res); // Unused
26
+ const response = res as any;
27
+ const assets = (Array.isArray(response.assets) ? response.assets :
28
+ (Array.isArray(response.result) ? response.result : (response.result?.assets || [])));
29
+
30
+ // New: Handle folders
31
+ const folders = Array.isArray(response.folders) ? response.folders : (response.result?.folders || []);
32
+
33
+ const totalCount = assets.length;
34
+ const limitedAssets = assets.slice(0, params.limit);
35
+ const remaining = Math.max(0, totalCount - params.limit);
36
+
37
+ let message = `Found ${totalCount} assets`;
38
+ if (folders.length > 0) {
39
+ message += ` and ${folders.length} folders`;
40
+ }
41
+ message += `: ${limitedAssets.map((a: any) => a.path || a.package || a.name).join(', ')}`;
42
+
43
+ if (folders.length > 0 && limitedAssets.length < params.limit) {
44
+ const remainingLimit = params.limit - limitedAssets.length;
45
+ if (remainingLimit > 0) {
46
+ const limitedFolders = folders.slice(0, remainingLimit);
47
+ if (limitedAssets.length > 0) message += ', ';
48
+ message += `Folders: [${limitedFolders.join(', ')}]`;
49
+ if (folders.length > remainingLimit) message += '...';
50
+ }
51
+ }
52
+
53
+ if (remaining > 0) {
54
+ message += `... and ${remaining} others`;
55
+ }
56
+
57
+ return {
58
+ message: message,
59
+ assets: limitedAssets,
60
+ folders: folders,
61
+ totalCount: totalCount,
62
+ count: limitedAssets.length
63
+ };
64
+ }
65
+ case 'create_folder': {
66
+ const params = normalizeArgs(args, [
67
+ { key: 'path', aliases: ['directoryPath'], required: true }
68
+ ]);
69
+ const res = await tools.assetTools.createFolder(params.path);
70
+ return cleanObject(res);
71
+ }
72
+ case 'import': {
73
+ const params = normalizeArgs(args, [
74
+ { key: 'sourcePath', required: true },
75
+ { key: 'destinationPath', required: true },
76
+ { key: 'overwrite', default: false },
77
+ { key: 'save', default: true }
78
+ ]);
79
+
80
+ const res = await tools.assetTools.importAsset({
81
+ sourcePath: params.sourcePath,
82
+ destinationPath: params.destinationPath,
83
+ overwrite: params.overwrite,
84
+ save: params.save
85
+ });
86
+ return cleanObject(res);
87
+ }
88
+ case 'duplicate': {
89
+ const params = normalizeArgs(args, [
90
+ { key: 'sourcePath', aliases: ['assetPath'], required: true },
91
+ { key: 'destinationPath' },
92
+ { key: 'newName' }
93
+ ]);
94
+
95
+ let destinationPath = params.destinationPath;
96
+ if (params.newName) {
97
+ if (!destinationPath) {
98
+ const lastSlash = params.sourcePath.lastIndexOf('/');
99
+ const parentDir = lastSlash > 0 ? params.sourcePath.substring(0, lastSlash) : '/Game';
100
+ destinationPath = `${parentDir}/${params.newName}`;
101
+ } else if (!destinationPath.endsWith(params.newName)) {
102
+ if (destinationPath.endsWith('/')) {
103
+ destinationPath = `${destinationPath}${params.newName}`;
104
+ }
105
+ }
106
+ }
107
+
108
+ if (!destinationPath) {
109
+ throw new Error('destinationPath or newName is required for duplicate action');
110
+ }
111
+
112
+ const res = await tools.assetTools.duplicateAsset({
113
+ sourcePath: params.sourcePath,
114
+ destinationPath
115
+ });
116
+ return cleanObject(res);
117
+ }
118
+ case 'rename': {
119
+ const params = normalizeArgs(args, [
120
+ { key: 'sourcePath', aliases: ['assetPath'], required: true },
121
+ { key: 'destinationPath' },
122
+ { key: 'newName' }
123
+ ]);
124
+
125
+ let destinationPath = params.destinationPath;
126
+ if (!destinationPath && params.newName) {
127
+ const lastSlash = params.sourcePath.lastIndexOf('/');
128
+ const parentDir = lastSlash > 0 ? params.sourcePath.substring(0, lastSlash) : '/Game';
129
+ destinationPath = `${parentDir}/${params.newName}`;
130
+ }
131
+
132
+ if (!destinationPath) throw new Error('Missing destinationPath or newName');
133
+
134
+ const res: any = await tools.assetTools.renameAsset({
135
+ sourcePath: params.sourcePath,
136
+ destinationPath
137
+ });
138
+
139
+ if (res && res.success === false) {
140
+ const msg = (res.message || '').toLowerCase();
141
+ if (msg.includes('already exists') || msg.includes('exists')) {
142
+ return cleanObject({
143
+ success: false,
144
+ error: 'ASSET_ALREADY_EXISTS',
145
+ message: res.message || 'Asset already exists at destination',
146
+ sourcePath: params.sourcePath,
147
+ destinationPath
148
+ });
149
+ }
150
+ }
151
+ return cleanObject(res);
152
+ }
153
+ case 'move': {
154
+ const params = normalizeArgs(args, [
155
+ { key: 'sourcePath', aliases: ['assetPath'], required: true },
156
+ { key: 'destinationPath' }
157
+ ]);
158
+
159
+ let destinationPath = params.destinationPath;
160
+ const assetName = params.sourcePath.split('/').pop();
161
+ if (assetName && destinationPath && !destinationPath.endsWith(assetName)) {
162
+ destinationPath = `${destinationPath.replace(/\/$/, '')}/${assetName}`;
163
+ }
164
+
165
+ const res = await tools.assetTools.moveAsset({
166
+ sourcePath: params.sourcePath,
167
+ destinationPath
168
+ });
169
+ return cleanObject(res);
170
+ }
171
+ case 'delete_assets':
172
+ case 'delete_asset':
173
+ case 'delete': {
174
+ let paths: string[] = [];
175
+ if (Array.isArray(args.paths)) {
176
+ paths = args.paths;
177
+ } else if (Array.isArray(args.assetPaths)) {
178
+ paths = args.assetPaths;
179
+ } else {
180
+ const single = args.assetPath || args.path;
181
+ if (typeof single === 'string' && single.trim()) {
182
+ paths = [single.trim()];
183
+ }
184
+ }
185
+
186
+ if (paths.length === 0) {
187
+ throw new Error('No paths provided for delete action');
188
+ }
189
+
190
+ const res = await tools.assetTools.deleteAssets({ paths });
191
+ return cleanObject(res);
192
+ }
193
+ case 'generate_lods': {
194
+ const params = normalizeArgs(args, [
195
+ { key: 'assetPath', required: true },
196
+ { key: 'lodCount', required: true }
197
+ ]);
198
+ return cleanObject(await tools.assetTools.generateLODs({
199
+ assetPath: params.assetPath,
200
+ lodCount: params.lodCount
201
+ }));
202
+ }
203
+ case 'create_thumbnail': {
204
+ const params = normalizeArgs(args, [
205
+ { key: 'assetPath', required: true },
206
+ { key: 'width' },
207
+ { key: 'height' }
208
+ ]);
209
+ const res = await tools.assetTools.createThumbnail({
210
+ assetPath: params.assetPath,
211
+ width: params.width,
212
+ height: params.height
213
+ });
214
+ return cleanObject(res);
215
+ }
216
+ case 'set_tags': {
217
+ try {
218
+ const params = normalizeArgs(args, [
219
+ { key: 'assetPath', required: true },
220
+ { key: 'tags', required: true }
221
+ ]);
222
+ const res = await tools.assetTools.setTags({ assetPath: params.assetPath, tags: params.tags });
223
+ return cleanObject(res);
224
+ } catch (err: any) {
225
+ const message = String(err?.message || err || '').toLowerCase();
226
+ if (
227
+ message.includes('not_implemented') ||
228
+ message.includes('not implemented') ||
229
+ message.includes('unknown action') ||
230
+ message.includes('unknown subaction')
231
+ ) {
232
+ return cleanObject({
233
+ success: false,
234
+ error: 'NOT_IMPLEMENTED',
235
+ message: 'Asset tag writes are not implemented by the automation plugin.',
236
+ action: 'set_tags',
237
+ assetPath: args.assetPath,
238
+ tags: args.tags
239
+ });
240
+ }
241
+ throw err;
242
+ }
243
+ }
244
+ case 'get_metadata': {
245
+ const params = normalizeArgs(args, [
246
+ { key: 'assetPath', required: true }
247
+ ]);
248
+ const res: any = await tools.assetTools.getMetadata({ assetPath: params.assetPath });
249
+ const tags = res.tags || {};
250
+ const metadata = res.metadata || {};
251
+ const merged = { ...tags, ...metadata };
252
+ const tagCount = Object.keys(merged).length;
253
+
254
+ const cleanRes = cleanObject(res);
255
+ cleanRes.message = `Metadata retrieved (${tagCount} items)`;
256
+ cleanRes.tags = tags;
257
+ if (Object.keys(metadata).length > 0) {
258
+ cleanRes.metadata = metadata;
259
+ }
260
+
261
+ return cleanRes;
262
+ }
263
+ case 'set_metadata': {
264
+ const res = await executeAutomationRequest(tools, 'set_metadata', args);
265
+ return cleanObject(res);
266
+ }
267
+ case 'validate':
268
+ case 'validate_asset': {
269
+ const params = normalizeArgs(args, [
270
+ { key: 'assetPath', required: true }
271
+ ]);
272
+ const res = await tools.assetTools.validate({ assetPath: params.assetPath });
273
+ return cleanObject(res);
274
+ }
275
+ case 'generate_report': {
276
+ const params = normalizeArgs(args, [
277
+ { key: 'directory' },
278
+ { key: 'reportType' },
279
+ { key: 'outputPath' }
280
+ ]);
281
+ const res = await tools.assetTools.generateReport({
282
+ directory: params.directory,
283
+ reportType: params.reportType,
284
+ outputPath: params.outputPath
285
+ });
286
+ return cleanObject(res);
287
+ }
288
+ case 'create_material_instance': {
289
+ const res: any = await executeAutomationRequest(
290
+ tools,
291
+ 'create_material_instance',
292
+ args,
293
+ 'Automation bridge not available for create_material_instance'
294
+ );
295
+
296
+ const result = res?.result ?? res ?? {};
297
+ const errorCode = typeof result.error === 'string' ? result.error.toUpperCase() : '';
298
+ const message = typeof result.message === 'string' ? result.message : '';
299
+
300
+ if (errorCode === 'PARENT_NOT_FOUND' || message.toLowerCase().includes('parent material not found')) {
301
+ return cleanObject({
302
+ success: false,
303
+ error: 'PARENT_NOT_FOUND',
304
+ message: message || 'Parent material not found',
305
+ path: result.path,
306
+ parentMaterial: args.parentMaterial
307
+ });
308
+ }
309
+
310
+ return cleanObject(res);
311
+ }
312
+ case 'search_assets': {
313
+ const params = normalizeArgs(args, [
314
+ { key: 'classNames' },
315
+ { key: 'packagePaths' },
316
+ { key: 'recursivePaths' },
317
+ { key: 'recursiveClasses' },
318
+ { key: 'limit' }
319
+ ]);
320
+ const res = await tools.assetTools.searchAssets({
321
+ classNames: params.classNames,
322
+ packagePaths: params.packagePaths,
323
+ recursivePaths: params.recursivePaths,
324
+ recursiveClasses: params.recursiveClasses,
325
+ limit: params.limit
326
+ });
327
+ return cleanObject(res);
328
+ }
329
+ case 'find_by_tag': {
330
+ const params = normalizeArgs(args, [
331
+ { key: 'tag', required: true },
332
+ { key: 'value' }
333
+ ]);
334
+ return tools.assetTools.findByTag({ tag: params.tag, value: params.value });
335
+ }
336
+ case 'get_dependencies': {
337
+ const params = normalizeArgs(args, [
338
+ { key: 'assetPath', required: true },
339
+ { key: 'recursive' }
340
+ ]);
341
+ const res = await tools.assetTools.getDependencies({ assetPath: params.assetPath, recursive: params.recursive });
342
+ return cleanObject(res);
343
+ }
344
+ case 'get_source_control_state': {
345
+ const params = normalizeArgs(args, [
346
+ { key: 'assetPath', required: true }
347
+ ]);
348
+ const res = await tools.assetTools.getSourceControlState({ assetPath: params.assetPath });
349
+ return cleanObject(res);
350
+ }
351
+ case 'analyze_graph': {
352
+ const params = normalizeArgs(args, [
353
+ { key: 'assetPath', required: true },
354
+ { key: 'maxDepth' }
355
+ ]);
356
+ const res = await executeAutomationRequest(tools, 'get_asset_graph', {
357
+ assetPath: params.assetPath,
358
+ maxDepth: params.maxDepth
359
+ });
360
+ return cleanObject(res);
361
+ }
362
+ case 'create_render_target': {
363
+ const params = normalizeArgs(args, [
364
+ { key: 'name', required: true },
365
+ { key: 'packagePath', aliases: ['path'], default: '/Game' },
366
+ { key: 'width' },
367
+ { key: 'height' },
368
+ { key: 'format' }
369
+ ]);
370
+ const res = await executeAutomationRequest(tools, 'manage_render', {
371
+ subAction: 'create_render_target',
372
+ name: params.name,
373
+ packagePath: params.packagePath,
374
+ width: params.width,
375
+ height: params.height,
376
+ format: params.format,
377
+ save: true
378
+ });
379
+ return cleanObject(res);
380
+ }
381
+ case 'nanite_rebuild_mesh': {
382
+ const params = normalizeArgs(args, [
383
+ { key: 'assetPath', aliases: ['meshPath'], required: true }
384
+ ]);
385
+ const res = await executeAutomationRequest(tools, 'manage_render', {
386
+ subAction: 'nanite_rebuild_mesh',
387
+ assetPath: params.assetPath
388
+ });
389
+ return cleanObject(res);
390
+ }
391
+ case 'fixup_redirectors': {
392
+ const directoryRaw = typeof args.directory === 'string' && args.directory.trim().length > 0
393
+ ? args.directory.trim()
394
+ : (typeof args.directoryPath === 'string' && args.directoryPath.trim().length > 0
395
+ ? args.directoryPath.trim()
396
+ : '');
397
+
398
+ const payload: any = {};
399
+ if (directoryRaw) {
400
+ payload.directoryPath = directoryRaw;
401
+ }
402
+ if (typeof args.checkoutFiles === 'boolean') {
403
+ payload.checkoutFiles = args.checkoutFiles;
404
+ }
405
+
406
+ const res = await executeAutomationRequest(tools, 'fixup_redirectors', payload);
407
+ return cleanObject(res);
408
+ }
409
+ case 'add_material_parameter': {
410
+ const params = normalizeArgs(args, [
411
+ { key: 'assetPath', required: true },
412
+ { key: 'parameterName', aliases: ['name'], required: true },
413
+ { key: 'parameterType', aliases: ['type'] },
414
+ { key: 'value', aliases: ['defaultValue'] }
415
+ ]);
416
+ const res = await executeAutomationRequest(tools, 'add_material_parameter', {
417
+ assetPath: params.assetPath,
418
+ name: params.parameterName,
419
+ type: params.parameterType,
420
+ value: params.value
421
+ });
422
+ return cleanObject(res);
423
+ }
424
+ case 'list_instances': {
425
+ const params = normalizeArgs(args, [
426
+ { key: 'assetPath', required: true }
427
+ ]);
428
+ const res = await executeAutomationRequest(tools, 'list_instances', {
429
+ assetPath: params.assetPath
430
+ });
431
+ return cleanObject(res);
432
+ }
433
+ case 'reset_instance_parameters': {
434
+ const params = normalizeArgs(args, [
435
+ { key: 'assetPath', required: true }
436
+ ]);
437
+ const res = await executeAutomationRequest(tools, 'reset_instance_parameters', {
438
+ assetPath: params.assetPath
439
+ });
440
+ return cleanObject(res);
441
+ }
442
+ case 'exists': {
443
+ const params = normalizeArgs(args, [
444
+ { key: 'assetPath', required: true }
445
+ ]);
446
+ const res = await executeAutomationRequest(tools, 'exists', {
447
+ assetPath: params.assetPath
448
+ });
449
+ return cleanObject(res);
450
+ }
451
+ case 'get_material_stats': {
452
+ const params = normalizeArgs(args, [
453
+ { key: 'assetPath', required: true }
454
+ ]);
455
+ const res = await executeAutomationRequest(tools, 'get_material_stats', {
456
+ assetPath: params.assetPath
457
+ });
458
+ return cleanObject(res);
459
+ }
460
+ case 'rebuild_material': {
461
+ const params = normalizeArgs(args, [
462
+ { key: 'assetPath', required: true }
463
+ ]);
464
+ const res = await executeAutomationRequest(tools, 'rebuild_material', {
465
+ assetPath: params.assetPath
466
+ });
467
+ return cleanObject(res);
468
+ }
469
+ case 'add_material_node': {
470
+ const materialNodeAliases: Record<string, string> = {
471
+ 'Multiply': 'MaterialExpressionMultiply',
472
+ 'Add': 'MaterialExpressionAdd',
473
+ 'Subtract': 'MaterialExpressionSubtract',
474
+ 'Divide': 'MaterialExpressionDivide',
475
+ 'Power': 'MaterialExpressionPower',
476
+ 'Clamp': 'MaterialExpressionClamp',
477
+ 'Constant': 'MaterialExpressionConstant',
478
+ 'Constant2Vector': 'MaterialExpressionConstant2Vector',
479
+ 'Constant3Vector': 'MaterialExpressionConstant3Vector',
480
+ 'Constant4Vector': 'MaterialExpressionConstant4Vector',
481
+ 'TextureSample': 'MaterialExpressionTextureSample',
482
+ 'TextureCoordinate': 'MaterialExpressionTextureCoordinate',
483
+ 'Panner': 'MaterialExpressionPanner',
484
+ 'Rotator': 'MaterialExpressionRotator',
485
+ 'Lerp': 'MaterialExpressionLinearInterpolate',
486
+ 'LinearInterpolate': 'MaterialExpressionLinearInterpolate',
487
+ 'Sine': 'MaterialExpressionSine',
488
+ 'Cosine': 'MaterialExpressionCosine',
489
+ 'Append': 'MaterialExpressionAppendVector',
490
+ 'AppendVector': 'MaterialExpressionAppendVector',
491
+ 'ComponentMask': 'MaterialExpressionComponentMask',
492
+ 'Fresnel': 'MaterialExpressionFresnel',
493
+ 'Time': 'MaterialExpressionTime',
494
+ 'ScalarParameter': 'MaterialExpressionScalarParameter',
495
+ 'VectorParameter': 'MaterialExpressionVectorParameter',
496
+ 'StaticSwitchParameter': 'MaterialExpressionStaticSwitchParameter'
497
+ };
498
+
499
+ const params = normalizeArgs(args, [
500
+ { key: 'assetPath', required: true },
501
+ { key: 'nodeType', aliases: ['type'], required: true, map: materialNodeAliases },
502
+ { key: 'posX' },
503
+ { key: 'posY' }
504
+ ]);
505
+
506
+ const res = await executeAutomationRequest(tools, 'add_material_node', {
507
+ assetPath: params.assetPath,
508
+ nodeType: params.nodeType,
509
+ posX: params.posX,
510
+ posY: params.posY
511
+ });
512
+ return cleanObject(res);
513
+ }
514
+ default:
515
+ const res: any = await executeAutomationRequest(tools, action || 'manage_asset', args);
516
+ const result = res?.result ?? res ?? {};
517
+ const errorCode = typeof result.error === 'string' ? result.error.toUpperCase() : '';
518
+ const message = typeof result.message === 'string' ? result.message : '';
519
+
520
+ if (errorCode === 'INVALID_SUBACTION' || message.toLowerCase().includes('unknown subaction')) {
521
+ return cleanObject({
522
+ success: false,
523
+ error: 'INVALID_SUBACTION',
524
+ message: 'Asset action not recognized by the automation plugin.',
525
+ action: action || 'manage_asset',
526
+ assetPath: args.assetPath ?? args.path
527
+ });
528
+ }
529
+
530
+ return cleanObject(res);
531
+ }
532
+ }