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
@@ -1,319 +1,383 @@
1
- import { UnrealBridge } from '../unreal-bridge.js';
2
- import { promises as fs } from 'fs';
3
- import path from 'path';
4
- import { bestEffortInterpretedText, coerceNumber, coerceStringArray, interpretStandardResult } from '../utils/result-helpers.js';
5
1
 
6
- export class AssetTools {
7
- constructor(private bridge: UnrealBridge) {}
2
+ import { BaseTool } from './base-tool.js';
3
+ import { IAssetTools } from '../types/tool-interfaces.js';
4
+ import { wasmIntegration } from '../wasm/index.js';
8
5
 
9
- async importAsset(sourcePath: string, destinationPath: string) {
10
- let createdTestFile = false;
11
- try {
12
- // Sanitize destination path (remove trailing slash) and normalize UE path
13
- let cleanDest = destinationPath.replace(/\/$/, '');
14
- // Map /Content -> /Game for UE asset destinations
15
- if (/^\/?content(\/|$)/i.test(cleanDest)) {
16
- cleanDest = '/Game' + cleanDest.replace(/^\/?content/i, '');
17
- }
18
-
19
- // Create test FBX file if it's a test file
20
- if (sourcePath.includes('test_model.fbx')) {
21
- // Create the file outside of Python, before import
22
- try {
23
- await this.createTestFBX(sourcePath);
24
- createdTestFile = true;
25
- } catch (_err) {
26
- // If we can't create the file, we'll handle it in Python
27
- }
28
- }
6
+ export class AssetTools extends BaseTool implements IAssetTools {
7
+ private normalizeAssetPath(path: string): string {
8
+ if (!path) return '';
9
+ let normalized = path.replace(/\\/g, '/').trim();
29
10
 
30
- // Use Python API to import asset with file creation fallback
31
- const pythonCode = `
32
- import unreal
33
- import os
34
- import json
35
-
36
- # Create test FBX if needed
37
- source_path = r'${sourcePath}'
38
- if 'test_model.fbx' in source_path and not os.path.exists(source_path):
39
- # Create directory if needed
40
- os.makedirs(os.path.dirname(source_path), exist_ok=True)
41
-
42
- # Create a valid FBX ASCII file
43
- fbx_content = """FBXHeaderExtension: {
44
- FBXHeaderVersion: 1003
45
- FBXVersion: 7400
46
- CreationTimeStamp: {
47
- Version: 1000
48
- }
49
- Creator: "MCP FBX Test Generator"
50
- }
51
- GlobalSettings: {
52
- Version: 1000
53
- Properties70: {
54
- P: "UpAxis", "int", "Integer", "",2
55
- P: "UpAxisSign", "int", "Integer", "",1
56
- P: "FrontAxis", "int", "Integer", "",1
57
- P: "FrontAxisSign", "int", "Integer", "",1
58
- P: "CoordAxis", "int", "Integer", "",0
59
- P: "CoordAxisSign", "int", "Integer", "",1
60
- P: "UnitScaleFactor", "double", "Number", "",1
61
- }
62
- }
63
- Definitions: {
64
- Version: 100
65
- Count: 2
66
- ObjectType: "Model" {
67
- Count: 1
68
- }
69
- ObjectType: "Geometry" {
70
- Count: 1
11
+ // Handle typical prefixes if missing leading slash
12
+ if (!normalized.startsWith('/')) {
13
+ if (normalized.startsWith('Game/')) normalized = '/' + normalized;
14
+ else if (normalized.startsWith('Engine/')) normalized = '/' + normalized;
15
+ else if (normalized.startsWith('Script/')) normalized = '/' + normalized;
16
+ // Default to Game content if no known prefix
17
+ else normalized = '/Game/' + normalized;
71
18
  }
72
- }
73
- Objects: {
74
- Geometry: 1234567, "Geometry::Cube", "Mesh" {
75
- Vertices: *24 {
76
- a: -50,-50,50,50,-50,50,50,50,50,-50,50,50,-50,-50,-50,50,-50,-50,50,50,-50,-50,50,-50
77
- }
78
- PolygonVertexIndex: *36 {
79
- a: 0,1,2,-4,4,5,6,-8,0,4,7,-4,1,5,4,-1,2,6,5,-2,3,7,6,-3
80
- }
81
- GeometryVersion: 124
82
- LayerElementNormal: 0 {
83
- Version: 101
84
- Name: ""
85
- MappingInformationType: "ByPolygonVertex"
86
- ReferenceInformationType: "Direct"
87
- Normals: *108 {
88
- a: 0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0
89
- }
90
- }
91
- LayerElementUV: 0 {
92
- Version: 101
93
- Name: "UVMap"
94
- MappingInformationType: "ByPolygonVertex"
95
- ReferenceInformationType: "IndexToDirect"
96
- UV: *48 {
97
- a: 0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1
98
- }
99
- UVIndex: *36 {
100
- a: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35
101
- }
102
- }
103
- Layer: 0 {
104
- Version: 100
105
- LayerElement: {
106
- Type: "LayerElementNormal"
107
- TypedIndex: 0
108
- }
109
- LayerElement: {
110
- Type: "LayerElementUV"
111
- TypedIndex: 0
112
- }
113
- }
19
+
20
+ // Remove double slashes just in case
21
+ return normalized.replace(/\/+/g, '/');
22
+ }
23
+
24
+ async importAsset(params: { sourcePath: string; destinationPath: string; overwrite?: boolean; save?: boolean }) {
25
+ const res = await this.sendRequest('manage_asset', {
26
+ ...params,
27
+ subAction: 'import'
28
+ }, 'manage_asset', { timeoutMs: 120000 });
29
+ if (res && res.success) {
30
+ return { ...res, asset: this.normalizeAssetPath(params.destinationPath), source: params.sourcePath };
114
31
  }
115
- Model: 2345678, "Model::Cube", "Mesh" {
116
- Version: 232
117
- Properties70: {
118
- P: "InheritType", "enum", "", "",1
119
- P: "ScalingMax", "Vector3D", "Vector", "",0,0,0
120
- P: "DefaultAttributeIndex", "int", "Integer", "",0
121
- }
122
- Shading: Y
123
- Culling: "CullingOff"
32
+ return res;
33
+ }
34
+
35
+ async duplicateAsset(params: { sourcePath: string; destinationPath: string; overwrite?: boolean }) {
36
+ const sourcePath = this.normalizeAssetPath(params.sourcePath);
37
+ const destinationPath = this.normalizeAssetPath(params.destinationPath);
38
+
39
+ const res = await this.sendRequest('manage_asset', {
40
+ sourcePath,
41
+ destinationPath,
42
+ overwrite: params.overwrite ?? false,
43
+ subAction: 'duplicate'
44
+ }, 'manage_asset', { timeoutMs: 60000 });
45
+ if (res && res.success) {
46
+ return { ...res, asset: destinationPath, source: sourcePath };
124
47
  }
125
- }
126
- Connections: {
127
- C: "OO",1234567,2345678
128
- }
129
- """
130
-
131
- with open(source_path, 'w') as f:
132
- f.write(fbx_content)
133
- print(f"Created test FBX file: {source_path}")
134
-
135
- # Set up the import task
136
- task = unreal.AssetImportTask()
137
- task.filename = r'${sourcePath}'
138
- task.destination_path = '${cleanDest}'
139
- task.automated = True
140
- task.save = True
141
- task.replace_existing = True
142
-
143
- # Configure FBX import options
144
- options = unreal.FbxImportUI()
145
- options.import_mesh = True
146
- options.import_as_skeletal = False
147
- options.mesh_type_to_import = unreal.FBXImportType.FBXIT_STATIC_MESH
148
- options.static_mesh_import_data.combine_meshes = True
149
- options.static_mesh_import_data.generate_lightmap_u_vs = False
150
- options.static_mesh_import_data.auto_generate_collision = False
151
- task.options = options
152
-
153
- # Use AssetTools to import
154
- asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
155
- result = {'success': False, 'error': 'No assets imported', 'source': task.filename}
156
-
157
- try:
158
- asset_tools.import_asset_tasks([task])
159
- if task.imported_object_paths:
160
- result = {
161
- 'success': True,
162
- 'imported': len(task.imported_object_paths),
163
- 'paths': list(task.imported_object_paths)
164
- }
165
- except Exception as e:
166
- result = {'success': False, 'error': str(e), 'source': task.filename}
167
-
168
- print('RESULT:' + json.dumps(result))
169
- `.trim();
170
-
171
- const pyResp = await this.bridge.executePython(pythonCode);
172
-
173
- const interpreted = interpretStandardResult(pyResp, {
174
- successMessage: `Imported assets to ${cleanDest}`,
175
- failureMessage: 'Import failed'
176
- });
177
-
178
- if (interpreted.success) {
179
- const count = coerceNumber(interpreted.payload.imported) ?? 0;
180
- const paths = coerceStringArray(interpreted.payload.paths) ?? [];
181
- return {
182
- success: true,
183
- message: `Imported ${count} assets to ${cleanDest}`,
184
- imported: count,
185
- paths
186
- };
187
- }
48
+ return res;
49
+ }
188
50
 
189
- const errorMessage = `Import failed: ${interpreted.error ?? 'Unknown error'} (source: ${interpreted.payload.source ?? sourcePath})`;
190
- return {
191
- success: false,
192
- message: errorMessage,
193
- error: errorMessage,
194
- details: bestEffortInterpretedText(interpreted)
195
- };
196
- } catch (err) {
197
- return { success: false, error: `Failed to import asset: ${err}` };
198
- } finally {
199
- if (createdTestFile) {
200
- try {
201
- await fs.rm(sourcePath, { force: true });
202
- } catch (cleanupError) {
203
- // Swallow cleanup error but log for debug visibility
204
- console.warn(`Failed to clean up temporary FBX ${sourcePath}:`, cleanupError);
205
- }
206
- }
51
+ async renameAsset(params: { sourcePath: string; destinationPath: string }) {
52
+ const sourcePath = this.normalizeAssetPath(params.sourcePath);
53
+ const destinationPath = this.normalizeAssetPath(params.destinationPath);
54
+
55
+ const res = await this.sendRequest('manage_asset', {
56
+ sourcePath,
57
+ destinationPath,
58
+ subAction: 'rename'
59
+ }, 'manage_asset', { timeoutMs: 60000 });
60
+ if (res && res.success) {
61
+ return { ...res, asset: destinationPath, oldName: sourcePath };
207
62
  }
63
+ return res;
208
64
  }
209
65
 
210
- async duplicateAsset(sourcePath: string, destinationPath: string) {
211
- try {
212
- const res = await this.bridge.call({
213
- objectPath: '/Script/EditorScriptingUtilities.Default__EditorAssetLibrary',
214
- functionName: 'DuplicateAsset',
215
- parameters: {
216
- SourceAssetPath: sourcePath,
217
- DestinationAssetPath: destinationPath
218
- }
219
- });
220
- return res?.Result ?? res;
221
- } catch (err) {
222
- return { error: `Failed to duplicate asset: ${err}` };
66
+ async moveAsset(params: { sourcePath: string; destinationPath: string }) {
67
+ const sourcePath = this.normalizeAssetPath(params.sourcePath);
68
+ const destinationPath = this.normalizeAssetPath(params.destinationPath);
69
+
70
+ const res = await this.sendRequest('manage_asset', {
71
+ sourcePath,
72
+ destinationPath,
73
+ subAction: 'move'
74
+ }, 'manage_asset', { timeoutMs: 60000 });
75
+ if (res && res.success) {
76
+ return { ...res, asset: destinationPath, from: sourcePath };
223
77
  }
78
+ return res;
224
79
  }
225
80
 
226
- async deleteAsset(assetPath: string) {
227
- try {
228
- const res = await this.bridge.call({
229
- objectPath: '/Script/EditorScriptingUtilities.Default__EditorAssetLibrary',
230
- functionName: 'DeleteAsset',
231
- parameters: {
232
- AssetPathToDelete: assetPath
233
- }
234
- });
235
- return res?.Result ?? res;
236
- } catch (err) {
237
- return { error: `Failed to delete asset: ${err}` };
81
+ async findByTag(params: { tag: string; value?: string }) {
82
+ // tag searches don't usually involve paths, but if they did we'd normalize.
83
+ // preserving existing logic for findByTag as it takes 'tag' and 'value'.
84
+ return this.sendRequest('asset_query', {
85
+ ...params,
86
+ subAction: 'find_by_tag'
87
+ }, 'asset_query', { timeoutMs: 60000 });
88
+ }
89
+
90
+ async deleteAssets(params: { paths: string[]; fixupRedirectors?: boolean; timeoutMs?: number }) {
91
+ const assetPaths = (Array.isArray(params.paths) ? params.paths : [])
92
+ .map(p => this.normalizeAssetPath(p));
93
+
94
+ // Bulk delete maps to 'manage_asset' subAction 'bulk_delete' or 'delete'
95
+ // C++ 'HandleDeleteAssets' handles single delete, 'HandleBulkDeleteAssets' handles bulk.
96
+ // Let's use 'bulk_delete' if we have multiple, or 'delete' for consistency?
97
+ // C++ HandleAssetAction dispatches 'bulk_delete' to HandleBulkDeleteAssets.
98
+ return this.sendRequest('manage_asset', {
99
+ assetPaths,
100
+ fixupRedirectors: params.fixupRedirectors,
101
+ subAction: 'delete'
102
+ }, 'manage_asset', { timeoutMs: params.timeoutMs || 120000 });
103
+ }
104
+
105
+ async searchAssets(params: { classNames?: string[]; packagePaths?: string[]; recursivePaths?: boolean; recursiveClasses?: boolean; limit?: number }) {
106
+ // Normalize package paths if provided
107
+ const packagePaths = params.packagePaths
108
+ ? params.packagePaths.map(p => this.normalizeAssetPath(p))
109
+ : ['/Game'];
110
+
111
+ // Route via asset_query action with subAction 'search_assets'
112
+ const response = await this.sendRequest('asset_query', {
113
+ ...params,
114
+ packagePaths,
115
+ subAction: 'search_assets'
116
+ }, 'asset_query', { timeoutMs: 60000 });
117
+
118
+ if (!response.success) {
119
+ const errorMsg = response.error || `Failed to search assets. Raw response: ${JSON.stringify(response)}`;
120
+ return { success: false, error: errorMsg };
238
121
  }
122
+
123
+ const assetsRaw = response.assets || response.data || response.result;
124
+ const assets = Array.isArray(assetsRaw) ? assetsRaw : [];
125
+
126
+ return {
127
+ success: true,
128
+ message: `Found ${assets.length} assets`,
129
+ assets,
130
+ count: assets.length
131
+ };
239
132
  }
240
133
 
241
134
  async saveAsset(assetPath: string) {
135
+ const normalizedPath = this.normalizeAssetPath(assetPath);
242
136
  try {
243
- const res = await this.bridge.call({
244
- objectPath: '/Script/EditorScriptingUtilities.Default__EditorAssetLibrary',
245
- functionName: 'SaveAsset',
246
- parameters: {
247
- AssetToSave: assetPath
137
+ // Try Automation Bridge first
138
+ const bridge = this.getAutomationBridge();
139
+ if (bridge && typeof bridge.sendAutomationRequest === 'function') {
140
+ try {
141
+ const response: any = await bridge.sendAutomationRequest(
142
+ 'manage_asset',
143
+ { assetPath: normalizedPath, subAction: 'save_asset' }, // 'save_asset' isn't explicitly in HandleAssetAction but usually falls back or Editor handles it?
144
+ // Wait, HandleAssetAction does NOT have 'save'.
145
+ // But 'execute_editor_function' usually handles SAVE_ASSET.
146
+ // Let's check fallback. The original code tried 'save_asset' command which likely failed.
147
+ // Actually, keep safe fallback to 'executeEditorFunction'.
148
+ // But if we want to add save support, we should assume 'save_asset' command failed implies we need fallback.
149
+ // Let's stick to the existing fallback logic but maybe fix the command if known?
150
+ // Since 'save_asset' is not in Subsystem.cpp, it fails.
151
+ // Let's rely on executeEditorFunction below.
152
+ { timeoutMs: 60000 }
153
+ );
154
+
155
+ if (response && response.success !== false) {
156
+ return {
157
+ success: true,
158
+ saved: response.saved ?? true,
159
+ message: response.message || 'Asset saved',
160
+ ...response
161
+ };
162
+ }
163
+ } catch (_err) {
164
+ // Fall through to executeEditorFunction
248
165
  }
249
- });
250
- return res?.Result ?? res;
166
+ }
167
+
168
+ // Fallback to executeEditorFunction
169
+ const res = await this.bridge.executeEditorFunction('SAVE_ASSET', { path: normalizedPath });
170
+ if (res && typeof res === 'object' && (res.success === true || (res.result && res.result.success === true))) {
171
+ const saved = Boolean(res.saved ?? (res.result && res.result.saved));
172
+ return { success: true, saved, ...res, ...(res.result || {}) };
173
+ }
174
+
175
+ return { success: false, error: (res as any)?.error ?? 'Failed to save asset' };
251
176
  } catch (err) {
252
- return { error: `Failed to save asset: ${err}` };
177
+ return { success: false, error: `Failed to save asset: ${err}` };
253
178
  }
254
179
  }
255
180
 
256
- private async createTestFBX(filePath: string): Promise<void> {
257
- // Create a minimal valid FBX ASCII file for testing
258
- const fbxContent = `; FBX 7.5.0 project file
259
- FBXHeaderExtension: {
260
- FBXHeaderVersion: 1003
261
- FBXVersion: 7500
262
- CreationTimeStamp: {
263
- Version: 1000
264
- Year: 2024
265
- Month: 1
266
- Day: 1
267
- Hour: 0
268
- Minute: 0
269
- Second: 0
270
- Millisecond: 0
271
- }
272
- Creator: "MCP Test FBX Generator"
273
- }
274
- GlobalSettings: {
275
- Version: 1000
276
- }
277
- Definitions: {
278
- Version: 100
279
- Count: 2
280
- ObjectType: "Model" {
281
- Count: 1
282
- }
283
- ObjectType: "Geometry" {
284
- Count: 1
285
- }
286
- }
287
- Objects: {
288
- Geometry: 1234567, "Geometry::Cube", "Mesh" {
289
- Vertices: *24 {
290
- a: -50,-50,-50,50,-50,-50,50,50,-50,-50,50,-50,-50,-50,50,50,-50,50,50,50,50,-50,50,50
181
+ async createFolder(folderPath: string) {
182
+ // Folders are paths too
183
+ const path = this.normalizeAssetPath(folderPath);
184
+ return this.sendRequest('manage_asset', {
185
+ path,
186
+ subAction: 'create_folder'
187
+ }, 'manage_asset', { timeoutMs: 60000 });
188
+ }
189
+
190
+ async getDependencies(params: { assetPath: string; recursive?: boolean }) {
191
+ // get_dependencies is typically an asset query or managed asset action?
192
+ // HandleAssetAction has 'get_dependencies' dispatch.
193
+ return this.sendRequest('manage_asset', {
194
+ ...params,
195
+ assetPath: this.normalizeAssetPath(params.assetPath),
196
+ subAction: 'get_dependencies'
197
+ }, 'manage_asset');
198
+ }
199
+
200
+ async getSourceControlState(params: { assetPath: string }) {
201
+ // Source control state usually via 'asset_query' or 'manage_asset'?
202
+ // It's not in HandleAssetAction explicitly, maybe 'asset_query' subAction?
203
+ // Let's check AssetQueryHandlers.cpp or AssetWorkflowHandlers.cpp dispatch.
204
+ // Assuming 'asset_query' supports it (original code used asset_query).
205
+ return this.sendRequest('asset_query', {
206
+ ...params,
207
+ assetPath: this.normalizeAssetPath(params.assetPath),
208
+ subAction: 'get_source_control_state'
209
+ }, 'asset_query');
210
+ }
211
+
212
+ async getMetadata(params: { assetPath: string }) {
213
+ const response = await this.sendRequest('manage_asset', {
214
+ ...params,
215
+ assetPath: this.normalizeAssetPath(params.assetPath),
216
+ subAction: 'get_metadata'
217
+ }, 'manage_asset');
218
+
219
+ // BaseTool unwraps the result, so 'response' is likely the payload itself.
220
+ // However, if the result was null, 'response' might be the wrapper.
221
+ // We handle both cases to be robust.
222
+ const resultObj = (response.result || response) as Record<string, any>;
223
+ return {
224
+ success: true,
225
+ message: 'Metadata retrieved',
226
+ ...resultObj
227
+ };
228
+ }
229
+
230
+ async analyzeGraph(params: { assetPath: string; maxDepth?: number }) {
231
+ const maxDepth = params.maxDepth ?? 3;
232
+ const assetPath = this.normalizeAssetPath(params.assetPath);
233
+
234
+ try {
235
+ // Offload the heavy graph traversal to C++
236
+ const response: any = await this.sendRequest('manage_asset', {
237
+ assetPath,
238
+ maxDepth,
239
+ subAction: 'get_asset_graph'
240
+ }, 'manage_asset', { timeoutMs: 60000 });
241
+
242
+ if (!response.success || !response.graph) {
243
+ return { success: false, error: response.error || 'Failed to retrieve asset graph from engine' };
244
+ }
245
+
246
+ const graph: Record<string, string[]> = {};
247
+ // Convert the JSON object (Record<string, any[]>) to string[]
248
+ for (const [key, value] of Object.entries(response.graph)) {
249
+ if (Array.isArray(value)) {
250
+ graph[key] = value.map(v => String(v));
291
251
  }
292
- PolygonVertexIndex: *36 {
293
- a: 0,1,2,-4,4,7,6,-6,0,4,5,-2,1,5,6,-3,2,6,7,-4,4,0,3,-8
252
+ }
253
+
254
+ // Use WASM for analysis on the constructed graph
255
+ const base = await wasmIntegration.resolveDependencies(
256
+ assetPath,
257
+ graph,
258
+ { maxDepth }
259
+ );
260
+
261
+ const depth = await wasmIntegration.calculateDependencyDepth(
262
+ assetPath,
263
+ graph,
264
+ { maxDepth }
265
+ );
266
+
267
+ const circularDependencies = await wasmIntegration.findCircularDependencies(
268
+ graph,
269
+ { maxDepth }
270
+ );
271
+
272
+ const topologicalOrder = await wasmIntegration.topologicalSort(graph);
273
+
274
+ const dependenciesList = Array.isArray((base as any).dependencies)
275
+ ? (base as any).dependencies as any[]
276
+ : [];
277
+
278
+ const totalDependencyCount =
279
+ (base as any).totalDependencyCount ??
280
+ (base as any).total_dependency_count ??
281
+ dependenciesList.length;
282
+
283
+ const analysis = {
284
+ asset: (base as any).asset ?? assetPath,
285
+ dependencies: dependenciesList,
286
+ totalDependencyCount,
287
+ requestedMaxDepth: maxDepth,
288
+ maxDepthUsed: depth,
289
+ circularDependencies,
290
+ topologicalOrder,
291
+ stats: {
292
+ nodeCount: dependenciesList.length,
293
+ leafCount: dependenciesList.filter((d: any) => !d.dependencies || d.dependencies.length === 0).length
294
294
  }
295
- GeometryVersion: 124
295
+ };
296
+
297
+ return {
298
+ success: true,
299
+ message: 'graph analyzed',
300
+ analysis
301
+ };
302
+ } catch (e: any) {
303
+ return { success: false, error: `Analysis failed: ${e.message}` };
296
304
  }
297
- Model: 2345678, "Model::TestCube", "Mesh" {
298
- Version: 232
299
- Properties70: {
300
- P: "ScalingMax", "Vector3D", "Vector", "",0,0,0
301
- P: "DefaultAttributeIndex", "int", "Integer", "",0
302
- }
305
+ }
306
+
307
+ async createThumbnail(params: { assetPath: string; width?: number; height?: number }) {
308
+ return this.sendRequest('manage_asset', {
309
+ ...params,
310
+ assetPath: this.normalizeAssetPath(params.assetPath),
311
+ subAction: 'generate_thumbnail'
312
+ }, 'manage_asset', { timeoutMs: 60000 });
313
+ }
314
+
315
+ async setTags(params: { assetPath: string; tags: string[] }) {
316
+ return this.sendRequest('manage_asset', {
317
+ ...params,
318
+ assetPath: this.normalizeAssetPath(params.assetPath),
319
+ subAction: 'set_tags'
320
+ }, 'manage_asset', { timeoutMs: 60000 });
321
+ }
322
+
323
+ async generateReport(params: { directory: string; reportType?: string; outputPath?: string }) {
324
+ return this.sendRequest('manage_asset', {
325
+ ...params,
326
+ directory: this.normalizeAssetPath(params.directory),
327
+ subAction: 'generate_report'
328
+ }, 'manage_asset', { timeoutMs: 300000 });
329
+ }
330
+
331
+ async validate(params: { assetPath: string }) {
332
+ return this.sendRequest('manage_asset', {
333
+ ...params,
334
+ assetPath: this.normalizeAssetPath(params.assetPath),
335
+ subAction: 'validate'
336
+ }, 'manage_asset', { timeoutMs: 300000 });
337
+ }
338
+
339
+ async generateLODs(params: { assetPath: string; lodCount: number }) {
340
+ const assetPath = this.normalizeAssetPath(String(params.assetPath ?? '').trim());
341
+ const lodCountRaw = Number(params.lodCount);
342
+
343
+ if (!assetPath) {
344
+ return { success: false, error: 'assetPath is required' };
303
345
  }
304
- }
305
- Connections: {
306
- C: "OO",1234567,2345678
307
- }
308
- `;
309
-
310
- // Ensure directory exists
311
- const dir = path.dirname(filePath);
346
+ if (!Number.isFinite(lodCountRaw) || lodCountRaw <= 0) {
347
+ return { success: false, error: 'lodCount must be a positive number' };
348
+ }
349
+ const lodCount = Math.floor(lodCountRaw);
350
+
312
351
  try {
313
- await fs.mkdir(dir, { recursive: true });
314
- } catch {}
315
-
316
- // Write the FBX file
317
- await fs.writeFile(filePath, fbxContent, 'utf8');
352
+ const automation = this.getAutomationBridge();
353
+ const response: any = await automation.sendAutomationRequest('manage_asset', {
354
+ assetPaths: [assetPath],
355
+ numLODs: lodCount,
356
+ subAction: 'generate_lods'
357
+ }, { timeoutMs: 120000 });
358
+
359
+ if (!response || response.success === false) {
360
+ return {
361
+ success: false,
362
+ error: response?.error || response?.message || 'Failed to generate LODs',
363
+ details: response?.result
364
+ };
365
+ }
366
+
367
+ const result = (response.result && typeof response.result === 'object') ? response.result as Record<string, unknown> : {};
368
+
369
+ return {
370
+ success: true,
371
+ message: response.message || 'LODs generated successfully',
372
+ assetPath: (result.assetPath as string) ?? assetPath,
373
+ lodCount: (result.lodCount as number) ?? lodCount,
374
+ ...result
375
+ };
376
+ } catch (error) {
377
+ return {
378
+ success: false,
379
+ error: `Failed to generate LODs: ${error instanceof Error ? error.message : String(error)}`
380
+ };
381
+ }
318
382
  }
319
383
  }