unreal-engine-mcp-server 0.4.7 → 0.5.1

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 (454) 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-config.yml +51 -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 +27 -0
  19. package/.github/workflows/labeler.yml +17 -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 +13 -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 +338 -31
  29. package/CONTRIBUTING.md +140 -0
  30. package/GEMINI.md +115 -0
  31. package/Public/Plugin_setup_guide.mp4 +0 -0
  32. package/README.md +189 -128
  33. package/claude_desktop_config_example.json +7 -6
  34. package/dist/automation/bridge.d.ts +50 -0
  35. package/dist/automation/bridge.js +452 -0
  36. package/dist/automation/connection-manager.d.ts +23 -0
  37. package/dist/automation/connection-manager.js +107 -0
  38. package/dist/automation/handshake.d.ts +11 -0
  39. package/dist/automation/handshake.js +89 -0
  40. package/dist/automation/index.d.ts +3 -0
  41. package/dist/automation/index.js +3 -0
  42. package/dist/automation/message-handler.d.ts +12 -0
  43. package/dist/automation/message-handler.js +149 -0
  44. package/dist/automation/request-tracker.d.ts +25 -0
  45. package/dist/automation/request-tracker.js +98 -0
  46. package/dist/automation/types.d.ts +130 -0
  47. package/dist/automation/types.js +2 -0
  48. package/dist/cli.js +32 -5
  49. package/dist/config.d.ts +26 -0
  50. package/dist/config.js +59 -0
  51. package/dist/constants.d.ts +16 -0
  52. package/dist/constants.js +16 -0
  53. package/dist/graphql/loaders.d.ts +64 -0
  54. package/dist/graphql/loaders.js +117 -0
  55. package/dist/graphql/resolvers.d.ts +268 -0
  56. package/dist/graphql/resolvers.js +746 -0
  57. package/dist/graphql/schema.d.ts +5 -0
  58. package/dist/graphql/schema.js +437 -0
  59. package/dist/graphql/server.d.ts +26 -0
  60. package/dist/graphql/server.js +117 -0
  61. package/dist/graphql/types.d.ts +9 -0
  62. package/dist/graphql/types.js +2 -0
  63. package/dist/handlers/resource-handlers.d.ts +20 -0
  64. package/dist/handlers/resource-handlers.js +180 -0
  65. package/dist/index.d.ts +33 -18
  66. package/dist/index.js +130 -619
  67. package/dist/resources/actors.d.ts +17 -12
  68. package/dist/resources/actors.js +56 -76
  69. package/dist/resources/assets.d.ts +6 -14
  70. package/dist/resources/assets.js +115 -147
  71. package/dist/resources/levels.d.ts +13 -13
  72. package/dist/resources/levels.js +25 -34
  73. package/dist/server/resource-registry.d.ts +20 -0
  74. package/dist/server/resource-registry.js +37 -0
  75. package/dist/server/tool-registry.d.ts +23 -0
  76. package/dist/server/tool-registry.js +322 -0
  77. package/dist/server-setup.d.ts +20 -0
  78. package/dist/server-setup.js +71 -0
  79. package/dist/services/health-monitor.d.ts +34 -0
  80. package/dist/services/health-monitor.js +105 -0
  81. package/dist/services/metrics-server.d.ts +11 -0
  82. package/dist/services/metrics-server.js +105 -0
  83. package/dist/tools/actors.d.ts +163 -9
  84. package/dist/tools/actors.js +356 -311
  85. package/dist/tools/animation.d.ts +135 -4
  86. package/dist/tools/animation.js +510 -411
  87. package/dist/tools/assets.d.ts +75 -29
  88. package/dist/tools/assets.js +265 -284
  89. package/dist/tools/audio.d.ts +102 -42
  90. package/dist/tools/audio.js +272 -685
  91. package/dist/tools/base-tool.d.ts +17 -0
  92. package/dist/tools/base-tool.js +46 -0
  93. package/dist/tools/behavior-tree.d.ts +94 -0
  94. package/dist/tools/behavior-tree.js +39 -0
  95. package/dist/tools/blueprint.d.ts +208 -126
  96. package/dist/tools/blueprint.js +685 -832
  97. package/dist/tools/consolidated-tool-definitions.d.ts +5462 -1781
  98. package/dist/tools/consolidated-tool-definitions.js +829 -496
  99. package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
  100. package/dist/tools/consolidated-tool-handlers.js +198 -1027
  101. package/dist/tools/debug.d.ts +143 -85
  102. package/dist/tools/debug.js +234 -180
  103. package/dist/tools/dynamic-handler-registry.d.ts +13 -0
  104. package/dist/tools/dynamic-handler-registry.js +23 -0
  105. package/dist/tools/editor.d.ts +30 -83
  106. package/dist/tools/editor.js +247 -244
  107. package/dist/tools/engine.d.ts +10 -4
  108. package/dist/tools/engine.js +13 -5
  109. package/dist/tools/environment.d.ts +30 -0
  110. package/dist/tools/environment.js +267 -0
  111. package/dist/tools/foliage.d.ts +65 -99
  112. package/dist/tools/foliage.js +221 -331
  113. package/dist/tools/handlers/actor-handlers.d.ts +3 -0
  114. package/dist/tools/handlers/actor-handlers.js +227 -0
  115. package/dist/tools/handlers/animation-handlers.d.ts +3 -0
  116. package/dist/tools/handlers/animation-handlers.js +185 -0
  117. package/dist/tools/handlers/argument-helper.d.ts +16 -0
  118. package/dist/tools/handlers/argument-helper.js +80 -0
  119. package/dist/tools/handlers/asset-handlers.d.ts +3 -0
  120. package/dist/tools/handlers/asset-handlers.js +496 -0
  121. package/dist/tools/handlers/audio-handlers.d.ts +3 -0
  122. package/dist/tools/handlers/audio-handlers.js +166 -0
  123. package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
  124. package/dist/tools/handlers/blueprint-handlers.js +358 -0
  125. package/dist/tools/handlers/common-handlers.d.ts +14 -0
  126. package/dist/tools/handlers/common-handlers.js +56 -0
  127. package/dist/tools/handlers/editor-handlers.d.ts +3 -0
  128. package/dist/tools/handlers/editor-handlers.js +119 -0
  129. package/dist/tools/handlers/effect-handlers.d.ts +3 -0
  130. package/dist/tools/handlers/effect-handlers.js +171 -0
  131. package/dist/tools/handlers/environment-handlers.d.ts +3 -0
  132. package/dist/tools/handlers/environment-handlers.js +170 -0
  133. package/dist/tools/handlers/graph-handlers.d.ts +3 -0
  134. package/dist/tools/handlers/graph-handlers.js +90 -0
  135. package/dist/tools/handlers/input-handlers.d.ts +3 -0
  136. package/dist/tools/handlers/input-handlers.js +21 -0
  137. package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
  138. package/dist/tools/handlers/inspect-handlers.js +383 -0
  139. package/dist/tools/handlers/level-handlers.d.ts +3 -0
  140. package/dist/tools/handlers/level-handlers.js +237 -0
  141. package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
  142. package/dist/tools/handlers/lighting-handlers.js +144 -0
  143. package/dist/tools/handlers/performance-handlers.d.ts +3 -0
  144. package/dist/tools/handlers/performance-handlers.js +130 -0
  145. package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
  146. package/dist/tools/handlers/pipeline-handlers.js +110 -0
  147. package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
  148. package/dist/tools/handlers/sequence-handlers.js +376 -0
  149. package/dist/tools/handlers/system-handlers.d.ts +4 -0
  150. package/dist/tools/handlers/system-handlers.js +506 -0
  151. package/dist/tools/input.d.ts +19 -0
  152. package/dist/tools/input.js +89 -0
  153. package/dist/tools/introspection.d.ts +103 -40
  154. package/dist/tools/introspection.js +425 -568
  155. package/dist/tools/landscape.d.ts +54 -93
  156. package/dist/tools/landscape.js +284 -409
  157. package/dist/tools/level.d.ts +66 -27
  158. package/dist/tools/level.js +647 -675
  159. package/dist/tools/lighting.d.ts +77 -38
  160. package/dist/tools/lighting.js +445 -943
  161. package/dist/tools/logs.d.ts +3 -3
  162. package/dist/tools/logs.js +5 -57
  163. package/dist/tools/materials.d.ts +91 -24
  164. package/dist/tools/materials.js +194 -118
  165. package/dist/tools/niagara.d.ts +149 -39
  166. package/dist/tools/niagara.js +267 -182
  167. package/dist/tools/performance.d.ts +27 -13
  168. package/dist/tools/performance.js +203 -122
  169. package/dist/tools/physics.d.ts +32 -77
  170. package/dist/tools/physics.js +175 -582
  171. package/dist/tools/property-dictionary.d.ts +13 -0
  172. package/dist/tools/property-dictionary.js +82 -0
  173. package/dist/tools/sequence.d.ts +85 -60
  174. package/dist/tools/sequence.js +208 -747
  175. package/dist/tools/tool-definition-utils.d.ts +59 -0
  176. package/dist/tools/tool-definition-utils.js +35 -0
  177. package/dist/tools/ui.d.ts +64 -34
  178. package/dist/tools/ui.js +134 -214
  179. package/dist/types/automation-responses.d.ts +115 -0
  180. package/dist/types/automation-responses.js +2 -0
  181. package/dist/types/env.d.ts +0 -3
  182. package/dist/types/env.js +0 -7
  183. package/dist/types/responses.d.ts +249 -0
  184. package/dist/types/responses.js +2 -0
  185. package/dist/types/tool-interfaces.d.ts +898 -0
  186. package/dist/types/tool-interfaces.js +2 -0
  187. package/dist/types/tool-types.d.ts +183 -19
  188. package/dist/types/tool-types.js +0 -4
  189. package/dist/unreal-bridge.d.ts +24 -131
  190. package/dist/unreal-bridge.js +364 -1506
  191. package/dist/utils/command-validator.d.ts +9 -0
  192. package/dist/utils/command-validator.js +68 -0
  193. package/dist/utils/elicitation.d.ts +1 -1
  194. package/dist/utils/elicitation.js +12 -15
  195. package/dist/utils/error-handler.d.ts +2 -51
  196. package/dist/utils/error-handler.js +11 -87
  197. package/dist/utils/ini-reader.d.ts +3 -0
  198. package/dist/utils/ini-reader.js +69 -0
  199. package/dist/utils/logger.js +9 -6
  200. package/dist/utils/normalize.d.ts +3 -0
  201. package/dist/utils/normalize.js +56 -0
  202. package/dist/utils/path-security.d.ts +2 -0
  203. package/dist/utils/path-security.js +24 -0
  204. package/dist/utils/response-factory.d.ts +7 -0
  205. package/dist/utils/response-factory.js +27 -0
  206. package/dist/utils/response-validator.d.ts +3 -24
  207. package/dist/utils/response-validator.js +130 -81
  208. package/dist/utils/result-helpers.d.ts +4 -5
  209. package/dist/utils/result-helpers.js +15 -16
  210. package/dist/utils/safe-json.js +5 -11
  211. package/dist/utils/unreal-command-queue.d.ts +24 -0
  212. package/dist/utils/unreal-command-queue.js +120 -0
  213. package/dist/utils/validation.d.ts +0 -40
  214. package/dist/utils/validation.js +1 -78
  215. package/dist/wasm/index.d.ts +70 -0
  216. package/dist/wasm/index.js +535 -0
  217. package/docs/GraphQL-API.md +888 -0
  218. package/docs/Migration-Guide-v0.5.0.md +684 -0
  219. package/docs/Roadmap.md +53 -0
  220. package/docs/WebAssembly-Integration.md +628 -0
  221. package/docs/editor-plugin-extension.md +370 -0
  222. package/docs/handler-mapping.md +242 -0
  223. package/docs/native-automation-progress.md +128 -0
  224. package/docs/testing-guide.md +423 -0
  225. package/mcp-config-example.json +6 -6
  226. package/package.json +67 -28
  227. package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
  228. package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
  229. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
  230. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
  231. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
  232. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
  233. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
  234. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
  235. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
  236. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
  237. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
  238. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
  239. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
  240. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
  241. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
  242. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
  243. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
  244. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
  245. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
  246. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
  247. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
  248. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
  249. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
  250. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
  251. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
  252. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
  253. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
  254. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
  255. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
  256. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
  257. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
  258. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
  259. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
  260. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
  261. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
  262. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
  263. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
  264. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
  265. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
  266. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
  267. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
  268. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
  269. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
  270. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
  271. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
  272. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
  273. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
  274. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
  275. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
  276. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
  277. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
  278. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
  279. package/scripts/check-unreal-connection.mjs +19 -0
  280. package/scripts/clean-tmp.js +23 -0
  281. package/scripts/patch-wasm.js +26 -0
  282. package/scripts/run-all-tests.mjs +136 -0
  283. package/scripts/smoke-test.ts +94 -0
  284. package/scripts/sync-mcp-plugin.js +143 -0
  285. package/scripts/test-no-plugin-alternates.mjs +113 -0
  286. package/scripts/validate-server.js +46 -0
  287. package/scripts/verify-automation-bridge.js +200 -0
  288. package/server.json +58 -21
  289. package/src/automation/bridge.ts +558 -0
  290. package/src/automation/connection-manager.ts +130 -0
  291. package/src/automation/handshake.ts +99 -0
  292. package/src/automation/index.ts +2 -0
  293. package/src/automation/message-handler.ts +167 -0
  294. package/src/automation/request-tracker.ts +123 -0
  295. package/src/automation/types.ts +107 -0
  296. package/src/cli.ts +33 -6
  297. package/src/config.ts +73 -0
  298. package/src/constants.ts +19 -0
  299. package/src/graphql/loaders.ts +244 -0
  300. package/src/graphql/resolvers.ts +1008 -0
  301. package/src/graphql/schema.ts +452 -0
  302. package/src/graphql/server.ts +156 -0
  303. package/src/graphql/types.ts +10 -0
  304. package/src/handlers/resource-handlers.ts +186 -0
  305. package/src/index.ts +166 -664
  306. package/src/resources/actors.ts +58 -76
  307. package/src/resources/assets.ts +148 -134
  308. package/src/resources/levels.ts +28 -33
  309. package/src/server/resource-registry.ts +47 -0
  310. package/src/server/tool-registry.ts +354 -0
  311. package/src/server-setup.ts +114 -0
  312. package/src/services/health-monitor.ts +132 -0
  313. package/src/services/metrics-server.ts +142 -0
  314. package/src/tools/actors.ts +426 -323
  315. package/src/tools/animation.ts +672 -461
  316. package/src/tools/assets.ts +364 -289
  317. package/src/tools/audio.ts +323 -766
  318. package/src/tools/base-tool.ts +52 -0
  319. package/src/tools/behavior-tree.ts +45 -0
  320. package/src/tools/blueprint.ts +792 -970
  321. package/src/tools/consolidated-tool-definitions.ts +993 -515
  322. package/src/tools/consolidated-tool-handlers.ts +258 -1146
  323. package/src/tools/debug.ts +292 -187
  324. package/src/tools/dynamic-handler-registry.ts +33 -0
  325. package/src/tools/editor.ts +329 -253
  326. package/src/tools/engine.ts +14 -3
  327. package/src/tools/environment.ts +281 -0
  328. package/src/tools/foliage.ts +330 -392
  329. package/src/tools/handlers/actor-handlers.ts +265 -0
  330. package/src/tools/handlers/animation-handlers.ts +237 -0
  331. package/src/tools/handlers/argument-helper.ts +142 -0
  332. package/src/tools/handlers/asset-handlers.ts +532 -0
  333. package/src/tools/handlers/audio-handlers.ts +194 -0
  334. package/src/tools/handlers/blueprint-handlers.ts +380 -0
  335. package/src/tools/handlers/common-handlers.ts +87 -0
  336. package/src/tools/handlers/editor-handlers.ts +123 -0
  337. package/src/tools/handlers/effect-handlers.ts +220 -0
  338. package/src/tools/handlers/environment-handlers.ts +183 -0
  339. package/src/tools/handlers/graph-handlers.ts +116 -0
  340. package/src/tools/handlers/input-handlers.ts +28 -0
  341. package/src/tools/handlers/inspect-handlers.ts +450 -0
  342. package/src/tools/handlers/level-handlers.ts +252 -0
  343. package/src/tools/handlers/lighting-handlers.ts +147 -0
  344. package/src/tools/handlers/performance-handlers.ts +132 -0
  345. package/src/tools/handlers/pipeline-handlers.ts +127 -0
  346. package/src/tools/handlers/sequence-handlers.ts +415 -0
  347. package/src/tools/handlers/system-handlers.ts +564 -0
  348. package/src/tools/input.ts +101 -0
  349. package/src/tools/introspection.ts +493 -584
  350. package/src/tools/landscape.ts +418 -507
  351. package/src/tools/level.ts +786 -708
  352. package/src/tools/lighting.ts +588 -984
  353. package/src/tools/logs.ts +9 -57
  354. package/src/tools/materials.ts +237 -121
  355. package/src/tools/niagara.ts +335 -168
  356. package/src/tools/performance.ts +320 -169
  357. package/src/tools/physics.ts +274 -613
  358. package/src/tools/property-dictionary.ts +98 -0
  359. package/src/tools/sequence.ts +276 -820
  360. package/src/tools/tool-definition-utils.ts +35 -0
  361. package/src/tools/ui.ts +205 -283
  362. package/src/types/automation-responses.ts +119 -0
  363. package/src/types/env.ts +0 -10
  364. package/src/types/responses.ts +355 -0
  365. package/src/types/tool-interfaces.ts +250 -0
  366. package/src/types/tool-types.ts +243 -21
  367. package/src/unreal-bridge.ts +460 -1550
  368. package/src/utils/command-validator.ts +76 -0
  369. package/src/utils/elicitation.ts +10 -7
  370. package/src/utils/error-handler.ts +14 -90
  371. package/src/utils/ini-reader.ts +86 -0
  372. package/src/utils/logger.ts +8 -3
  373. package/src/utils/normalize.test.ts +162 -0
  374. package/src/utils/normalize.ts +60 -0
  375. package/src/utils/path-security.ts +43 -0
  376. package/src/utils/response-factory.ts +44 -0
  377. package/src/utils/response-validator.ts +176 -56
  378. package/src/utils/result-helpers.ts +21 -19
  379. package/src/utils/safe-json.test.ts +90 -0
  380. package/src/utils/safe-json.ts +14 -11
  381. package/src/utils/unreal-command-queue.ts +152 -0
  382. package/src/utils/validation.test.ts +184 -0
  383. package/src/utils/validation.ts +4 -1
  384. package/src/wasm/index.ts +838 -0
  385. package/test-server.mjs +100 -0
  386. package/tests/run-unreal-tool-tests.mjs +242 -14
  387. package/tests/test-animation.mjs +369 -0
  388. package/tests/test-asset-advanced.mjs +82 -0
  389. package/tests/test-asset-errors.mjs +35 -0
  390. package/tests/test-asset-graph.mjs +311 -0
  391. package/tests/test-audio.mjs +417 -0
  392. package/tests/test-automation-timeouts.mjs +98 -0
  393. package/tests/test-behavior-tree.mjs +444 -0
  394. package/tests/test-blueprint-graph.mjs +410 -0
  395. package/tests/test-blueprint.mjs +577 -0
  396. package/tests/test-client-mode.mjs +86 -0
  397. package/tests/test-console-command.mjs +56 -0
  398. package/tests/test-control-actor.mjs +425 -0
  399. package/tests/test-control-editor.mjs +112 -0
  400. package/tests/test-graphql.mjs +372 -0
  401. package/tests/test-input.mjs +349 -0
  402. package/tests/test-inspect.mjs +302 -0
  403. package/tests/test-landscape.mjs +316 -0
  404. package/tests/test-lighting.mjs +428 -0
  405. package/tests/test-manage-asset.mjs +438 -0
  406. package/tests/test-manage-level.mjs +89 -0
  407. package/tests/test-materials.mjs +356 -0
  408. package/tests/test-niagara.mjs +185 -0
  409. package/tests/test-no-inline-python.mjs +122 -0
  410. package/tests/test-performance.mjs +539 -0
  411. package/tests/test-plugin-handshake.mjs +82 -0
  412. package/tests/test-runner.mjs +933 -0
  413. package/tests/test-sequence.mjs +104 -0
  414. package/tests/test-system.mjs +96 -0
  415. package/tests/test-wasm.mjs +283 -0
  416. package/tests/test-world-partition.mjs +215 -0
  417. package/tsconfig.json +3 -3
  418. package/vitest.config.ts +35 -0
  419. package/wasm/Cargo.lock +363 -0
  420. package/wasm/Cargo.toml +42 -0
  421. package/wasm/LICENSE +21 -0
  422. package/wasm/README.md +253 -0
  423. package/wasm/src/dependency_resolver.rs +377 -0
  424. package/wasm/src/lib.rs +153 -0
  425. package/wasm/src/property_parser.rs +271 -0
  426. package/wasm/src/transform_math.rs +396 -0
  427. package/wasm/tests/integration.rs +109 -0
  428. package/.github/workflows/smithery-build.yml +0 -29
  429. package/dist/prompts/index.d.ts +0 -21
  430. package/dist/prompts/index.js +0 -217
  431. package/dist/tools/build_environment_advanced.d.ts +0 -65
  432. package/dist/tools/build_environment_advanced.js +0 -633
  433. package/dist/tools/rc.d.ts +0 -110
  434. package/dist/tools/rc.js +0 -437
  435. package/dist/tools/visual.d.ts +0 -40
  436. package/dist/tools/visual.js +0 -282
  437. package/dist/utils/http.d.ts +0 -6
  438. package/dist/utils/http.js +0 -151
  439. package/dist/utils/python-output.d.ts +0 -18
  440. package/dist/utils/python-output.js +0 -290
  441. package/dist/utils/python.d.ts +0 -2
  442. package/dist/utils/python.js +0 -4
  443. package/dist/utils/stdio-redirect.d.ts +0 -2
  444. package/dist/utils/stdio-redirect.js +0 -20
  445. package/docs/unreal-tool-test-cases.md +0 -574
  446. package/smithery.yaml +0 -29
  447. package/src/prompts/index.ts +0 -249
  448. package/src/tools/build_environment_advanced.ts +0 -732
  449. package/src/tools/rc.ts +0 -515
  450. package/src/tools/visual.ts +0 -281
  451. package/src/utils/http.ts +0 -187
  452. package/src/utils/python-output.ts +0 -351
  453. package/src/utils/python.ts +0 -3
  454. package/src/utils/stdio-redirect.ts +0 -18
@@ -0,0 +1,9 @@
1
+ export declare class CommandValidator {
2
+ private static readonly DANGEROUS_COMMANDS;
3
+ private static readonly FORBIDDEN_TOKENS;
4
+ private static readonly INVALID_PATTERNS;
5
+ static validate(command: string): void;
6
+ static isLikelyInvalid(command: string): boolean;
7
+ static getPriority(command: string): number;
8
+ }
9
+ //# sourceMappingURL=command-validator.d.ts.map
@@ -0,0 +1,68 @@
1
+ export class CommandValidator {
2
+ static DANGEROUS_COMMANDS = [
3
+ 'quit', 'exit', 'delete', 'destroy', 'kill', 'crash',
4
+ 'viewmode visualizebuffer basecolor',
5
+ 'viewmode visualizebuffer worldnormal',
6
+ 'r.gpucrash',
7
+ 'buildpaths',
8
+ 'rebuildnavigation',
9
+ 'obj garbage', 'obj list', 'memreport'
10
+ ];
11
+ static FORBIDDEN_TOKENS = [
12
+ 'rm ', 'rm-', 'del ', 'format ', 'shutdown', 'reboot',
13
+ 'rmdir', 'mklink', 'copy ', 'move ', 'start "', 'system(',
14
+ 'import os', 'import subprocess', 'subprocess.', 'os.system',
15
+ 'exec(', 'eval(', '__import__', 'import sys', 'import importlib',
16
+ 'with open', 'open(', 'write(', 'read('
17
+ ];
18
+ static INVALID_PATTERNS = [
19
+ /^\d+$/,
20
+ /^invalid_command/i,
21
+ /^this_is_not_a_valid/i,
22
+ ];
23
+ static validate(command) {
24
+ if (!command || typeof command !== 'string') {
25
+ throw new Error('Invalid command: must be a non-empty string');
26
+ }
27
+ const cmdTrimmed = command.trim();
28
+ if (cmdTrimmed.length === 0) {
29
+ return;
30
+ }
31
+ if (cmdTrimmed.includes('\n') || cmdTrimmed.includes('\r')) {
32
+ throw new Error('Multi-line console commands are not allowed. Send one command per call.');
33
+ }
34
+ const cmdLower = cmdTrimmed.toLowerCase();
35
+ if (cmdLower === 'py' || cmdLower.startsWith('py ')) {
36
+ throw new Error('Python console commands are blocked from external calls for safety.');
37
+ }
38
+ if (this.DANGEROUS_COMMANDS.some(dangerous => cmdLower.includes(dangerous))) {
39
+ throw new Error(`Dangerous command blocked: ${command}`);
40
+ }
41
+ if (cmdLower.includes('&&') || cmdLower.includes('||')) {
42
+ throw new Error('Command chaining with && or || is blocked for safety.');
43
+ }
44
+ if (this.FORBIDDEN_TOKENS.some(token => cmdLower.includes(token))) {
45
+ throw new Error(`Command contains unsafe token and was blocked: ${command}`);
46
+ }
47
+ }
48
+ static isLikelyInvalid(command) {
49
+ const cmdTrimmed = command.trim();
50
+ return this.INVALID_PATTERNS.some(pattern => pattern.test(cmdTrimmed));
51
+ }
52
+ static getPriority(command) {
53
+ if (command.includes('BuildLighting') || command.includes('BuildPaths')) {
54
+ return 1;
55
+ }
56
+ else if (command.includes('summon') || command.includes('spawn')) {
57
+ return 5;
58
+ }
59
+ else if (command.startsWith('stat')) {
60
+ return 8;
61
+ }
62
+ else if (command.startsWith('show')) {
63
+ return 9;
64
+ }
65
+ return 7;
66
+ }
67
+ }
68
+ //# sourceMappingURL=command-validator.js.map
@@ -36,7 +36,7 @@ export interface ElicitSchema {
36
36
  }
37
37
  export interface ElicitOptions {
38
38
  timeoutMs?: number;
39
- fallback?: () => Promise<{
39
+ alternate?: () => Promise<{
40
40
  ok: boolean;
41
41
  value?: any;
42
42
  error?: string;
@@ -1,7 +1,5 @@
1
1
  export function createElicitationHelper(server, log) {
2
- // We do not require explicit capability detection: we optimistically try once
3
- // and disable on a Method-not-found (-32601) error for the session.
4
- let supported = true; // optimistic; will be set false on first failure
2
+ let supported = true;
5
3
  const MIN_TIMEOUT_MS = 30_000;
6
4
  const MAX_TIMEOUT_MS = 10 * 60 * 1000;
7
5
  const DEFAULT_TIMEOUT_MS = 3 * 60 * 1000;
@@ -31,9 +29,9 @@ export function createElicitationHelper(server, log) {
31
29
  return propertyEntries.every(([, rawSchema]) => {
32
30
  if (!rawSchema || typeof rawSchema !== 'object')
33
31
  return false;
34
- const primitive = rawSchema; // narrow for guards
32
+ const primitive = rawSchema;
35
33
  if ('properties' in primitive || 'items' in primitive)
36
- return false; // nested schemas unsupported
34
+ return false;
37
35
  if (Array.isArray(primitive.enum)) {
38
36
  const enumValues = primitive.enum;
39
37
  const allStrings = enumValues.every((value) => typeof value === 'string');
@@ -52,8 +50,8 @@ export function createElicitationHelper(server, log) {
52
50
  }
53
51
  async function elicit(message, requestedSchema, opts = {}) {
54
52
  if (!supported || !isSafeSchema(requestedSchema)) {
55
- if (opts.fallback)
56
- return opts.fallback();
53
+ if (opts.alternate)
54
+ return opts.alternate();
57
55
  return { ok: false, error: 'elicitation-unsupported' };
58
56
  }
59
57
  const params = { message, requestedSchema };
@@ -71,27 +69,26 @@ export function createElicitationHelper(server, log) {
71
69
  if (action === 'accept')
72
70
  return { ok: true, value: content };
73
71
  if (action === 'decline' || action === 'cancel') {
74
- if (opts.fallback)
75
- return opts.fallback();
72
+ if (opts.alternate)
73
+ return opts.alternate();
76
74
  return { ok: false, error: action };
77
75
  }
78
- if (opts.fallback)
79
- return opts.fallback();
76
+ if (opts.alternate)
77
+ return opts.alternate();
80
78
  return { ok: false, error: 'unexpected-response' };
81
79
  }
82
80
  catch (e) {
83
81
  const msg = String(e?.message || e);
84
82
  const code = e?.code ?? e?.error?.code;
85
- // If client doesn't support it, don’t try again this session
86
83
  if (msg.includes('Method not found') ||
87
84
  msg.includes('elicitInput-not-available') ||
88
85
  msg.includes('request-not-available') ||
89
86
  String(code) === '-32601') {
90
87
  supported = false;
91
88
  }
92
- log.debug('Elicitation failed; falling back', { error: msg, code });
93
- if (opts.fallback)
94
- return opts.fallback();
89
+ log.debug('Elicitation failed; using alternate handler', { error: msg, code });
90
+ if (opts.alternate)
91
+ return opts.alternate();
95
92
  return { ok: false, error: msg.includes('timeout') ? 'timeout' : 'rpc-failed' };
96
93
  }
97
94
  }
@@ -1,7 +1,4 @@
1
1
  import { BaseToolResponse } from '../types/tool-types.js';
2
- /**
3
- * Error types for categorization
4
- */
5
2
  export declare enum ErrorType {
6
3
  VALIDATION = "VALIDATION",
7
4
  CONNECTION = "CONNECTION",
@@ -11,63 +8,17 @@ export declare enum ErrorType {
11
8
  TIMEOUT = "TIMEOUT",
12
9
  UNKNOWN = "UNKNOWN"
13
10
  }
14
- /**
15
- * Consistent error handling for all tools
16
- */
17
11
  export declare class ErrorHandler {
18
- /**
19
- * Create a standardized error response
20
- */
21
12
  static createErrorResponse(error: any, toolName: string, context?: any): BaseToolResponse;
22
- /**
23
- * Categorize error by type
24
- */
25
13
  private static categorizeError;
26
- /**
27
- * Get user-friendly error message
28
- */
29
14
  private static getUserFriendlyMessage;
30
- /** Determine if an error is likely retriable */
31
15
  private static isRetriable;
32
- /**
33
- * Retry an async operation with exponential backoff
34
- * Best practice from TypeScript async programming patterns
35
- * @param operation - Async operation to retry
36
- * @param options - Retry configuration
37
- * @returns Result of the operation
38
- */
39
- static retryWithBackoff<T>(operation: () => Promise<T>, options?: {
16
+ static retryWithBackoff<T>(fn: () => Promise<T>, options?: {
40
17
  maxRetries?: number;
41
18
  initialDelay?: number;
42
19
  maxDelay?: number;
43
20
  backoffMultiplier?: number;
44
- shouldRetry?: (error: unknown) => boolean;
21
+ shouldRetry?: (error: any) => boolean;
45
22
  }): Promise<T>;
46
- /**
47
- * Add timeout to any promise
48
- * @param promise - Promise to add timeout to
49
- * @param timeoutMs - Timeout in milliseconds
50
- * @param errorMessage - Custom error message for timeout
51
- * @returns Promise that rejects on timeout
52
- */
53
- static withTimeout<T>(promise: Promise<T>, timeoutMs: number, errorMessage?: string): Promise<T>;
54
- /**
55
- * Execute multiple operations with Promise.allSettled for better error handling
56
- * Returns detailed results for each operation, including failures
57
- * @param operations - Array of async operations to execute
58
- * @returns Object with successful and failed operations separated
59
- */
60
- static batchExecute<T>(operations: Array<() => Promise<T>>): Promise<{
61
- successful: Array<{
62
- index: number;
63
- value: T;
64
- }>;
65
- failed: Array<{
66
- index: number;
67
- reason: unknown;
68
- }>;
69
- successCount: number;
70
- failureCount: number;
71
- }>;
72
23
  }
73
24
  //# sourceMappingURL=error-handler.d.ts.map
@@ -1,8 +1,5 @@
1
1
  import { Logger } from './logger.js';
2
2
  const log = new Logger('ErrorHandler');
3
- /**
4
- * Error types for categorization
5
- */
6
3
  export var ErrorType;
7
4
  (function (ErrorType) {
8
5
  ErrorType["VALIDATION"] = "VALIDATION";
@@ -13,13 +10,7 @@ export var ErrorType;
13
10
  ErrorType["TIMEOUT"] = "TIMEOUT";
14
11
  ErrorType["UNKNOWN"] = "UNKNOWN";
15
12
  })(ErrorType || (ErrorType = {}));
16
- /**
17
- * Consistent error handling for all tools
18
- */
19
13
  export class ErrorHandler {
20
- /**
21
- * Create a standardized error response
22
- */
23
14
  static createErrorResponse(error, toolName, context) {
24
15
  const errorType = this.categorizeError(error);
25
16
  const userMessage = this.getUserFriendlyMessage(errorType, error);
@@ -38,7 +29,6 @@ export class ErrorHandler {
38
29
  message: `Failed to execute ${toolName}: ${userMessage}`,
39
30
  retriable: retriable,
40
31
  scope: scope,
41
- // Add debug info in development
42
32
  ...(process.env.NODE_ENV === 'development' && {
43
33
  _debug: {
44
34
  errorType,
@@ -51,57 +41,46 @@ export class ErrorHandler {
51
41
  })
52
42
  };
53
43
  }
54
- /**
55
- * Categorize error by type
56
- */
57
44
  static categorizeError(error) {
58
45
  const explicitType = (error?.type || error?.errorType || '').toString().toUpperCase();
59
46
  if (explicitType && Object.values(ErrorType).includes(explicitType)) {
60
47
  return explicitType;
61
48
  }
62
49
  const errorMessage = error?.message?.toLowerCase() || String(error).toLowerCase();
63
- // Connection errors
64
50
  if (errorMessage.includes('econnrefused') ||
65
51
  errorMessage.includes('timeout') ||
66
52
  errorMessage.includes('connection') ||
67
53
  errorMessage.includes('network')) {
68
54
  return ErrorType.CONNECTION;
69
55
  }
70
- // Validation errors
71
56
  if (errorMessage.includes('invalid') ||
72
57
  errorMessage.includes('required') ||
73
58
  errorMessage.includes('must be') ||
74
59
  errorMessage.includes('validation')) {
75
60
  return ErrorType.VALIDATION;
76
61
  }
77
- // Unreal Engine specific errors
78
62
  if (errorMessage.includes('unreal') ||
79
- errorMessage.includes('remote control') ||
63
+ errorMessage.includes('connection failed') ||
80
64
  errorMessage.includes('blueprint') ||
81
65
  errorMessage.includes('actor') ||
82
66
  errorMessage.includes('asset')) {
83
67
  return ErrorType.UNREAL_ENGINE;
84
68
  }
85
- // Parameter errors
86
69
  if (errorMessage.includes('parameter') ||
87
70
  errorMessage.includes('argument') ||
88
71
  errorMessage.includes('missing')) {
89
72
  return ErrorType.PARAMETER;
90
73
  }
91
- // Timeout errors
92
74
  if (errorMessage.includes('timeout')) {
93
75
  return ErrorType.TIMEOUT;
94
76
  }
95
77
  return ErrorType.UNKNOWN;
96
78
  }
97
- /**
98
- * Get user-friendly error message
99
- */
100
79
  static getUserFriendlyMessage(type, error) {
101
80
  const originalMessage = error.message || String(error);
102
81
  switch (type) {
103
82
  case ErrorType.CONNECTION:
104
- return 'Failed to connect to Unreal Engine. Please ensure Remote Control is enabled and the engine is running.';
83
+ return 'Failed to connect to Unreal Engine. Please ensure the Automation Bridge plugin is active and the editor is running.';
105
84
  case ErrorType.VALIDATION:
106
85
  return `Invalid input: ${originalMessage}`;
107
86
  case ErrorType.UNREAL_ENGINE:
@@ -116,7 +95,6 @@ export class ErrorHandler {
116
95
  return originalMessage;
117
96
  }
118
97
  }
119
- /** Determine if an error is likely retriable */
120
98
  static isRetriable(error) {
121
99
  try {
122
100
  const code = (error?.code || '').toString().toUpperCase();
@@ -132,80 +110,26 @@ export class ErrorHandler {
132
110
  catch { }
133
111
  return false;
134
112
  }
135
- /**
136
- * Retry an async operation with exponential backoff
137
- * Best practice from TypeScript async programming patterns
138
- * @param operation - Async operation to retry
139
- * @param options - Retry configuration
140
- * @returns Result of the operation
141
- */
142
- static async retryWithBackoff(operation, options = {}) {
143
- const { maxRetries = 3, initialDelay = 100, maxDelay = 10000, backoffMultiplier = 2, shouldRetry = (error) => this.isRetriable(error) } = options;
144
- let lastError;
113
+ static async retryWithBackoff(fn, options = {}) {
114
+ const maxRetries = options.maxRetries ?? 3;
115
+ const initialDelay = options.initialDelay ?? 1000;
116
+ const maxDelay = options.maxDelay ?? 10000;
117
+ const multiplier = options.backoffMultiplier ?? 2;
118
+ const shouldRetry = options.shouldRetry ?? ((err) => this.isRetriable(err));
145
119
  let delay = initialDelay;
146
120
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
147
121
  try {
148
- return await operation();
122
+ return await fn();
149
123
  }
150
124
  catch (error) {
151
- lastError = error;
152
125
  if (attempt === maxRetries || !shouldRetry(error)) {
153
126
  throw error;
154
127
  }
155
- log.debug(`Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`);
156
128
  await new Promise(resolve => setTimeout(resolve, delay));
157
- delay = Math.min(delay * backoffMultiplier, maxDelay);
129
+ delay = Math.min(delay * multiplier, maxDelay);
158
130
  }
159
131
  }
160
- throw lastError;
161
- }
162
- /**
163
- * Add timeout to any promise
164
- * @param promise - Promise to add timeout to
165
- * @param timeoutMs - Timeout in milliseconds
166
- * @param errorMessage - Custom error message for timeout
167
- * @returns Promise that rejects on timeout
168
- */
169
- static async withTimeout(promise, timeoutMs, errorMessage = 'Operation timed out') {
170
- let timeoutHandle;
171
- const timeoutPromise = new Promise((_, reject) => {
172
- timeoutHandle = setTimeout(() => {
173
- reject(new Error(errorMessage));
174
- }, timeoutMs);
175
- });
176
- try {
177
- return await Promise.race([promise, timeoutPromise]);
178
- }
179
- finally {
180
- if (timeoutHandle !== undefined) {
181
- clearTimeout(timeoutHandle);
182
- }
183
- }
184
- }
185
- /**
186
- * Execute multiple operations with Promise.allSettled for better error handling
187
- * Returns detailed results for each operation, including failures
188
- * @param operations - Array of async operations to execute
189
- * @returns Object with successful and failed operations separated
190
- */
191
- static async batchExecute(operations) {
192
- const results = await Promise.allSettled(operations.map(op => op()));
193
- const successful = [];
194
- const failed = [];
195
- results.forEach((result, index) => {
196
- if (result.status === 'fulfilled') {
197
- successful.push({ index, value: result.value });
198
- }
199
- else {
200
- failed.push({ index, reason: result.reason });
201
- }
202
- });
203
- return {
204
- successful,
205
- failed,
206
- successCount: successful.length,
207
- failureCount: failed.length
208
- };
132
+ throw new Error('Max retries exceeded');
209
133
  }
210
134
  }
211
135
  //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1,3 @@
1
+ export declare function readIniFile(filePath: string): Promise<Record<string, Record<string, string>>>;
2
+ export declare function getProjectSetting(projectPath: string, category: string, sectionName: string, key?: string): Promise<any>;
3
+ //# sourceMappingURL=ini-reader.d.ts.map
@@ -0,0 +1,69 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ export async function readIniFile(filePath) {
4
+ try {
5
+ const content = await fs.readFile(filePath, 'utf-8');
6
+ const result = {};
7
+ let currentSection = '';
8
+ const lines = content.split(/\r?\n/);
9
+ for (const line of lines) {
10
+ const trimmed = line.trim();
11
+ if (!trimmed || trimmed.startsWith(';') || trimmed.startsWith('#')) {
12
+ continue;
13
+ }
14
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
15
+ currentSection = trimmed.substring(1, trimmed.length - 1);
16
+ result[currentSection] = {};
17
+ }
18
+ else if (currentSection) {
19
+ const parts = trimmed.split('=');
20
+ if (parts.length >= 2) {
21
+ const key = parts[0].trim();
22
+ const value = parts.slice(1).join('=').trim();
23
+ result[currentSection][key] = value;
24
+ }
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ catch (error) {
30
+ throw new Error(`Failed to read INI file at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
31
+ }
32
+ }
33
+ export async function getProjectSetting(projectPath, category, sectionName, key) {
34
+ let dirPath = projectPath;
35
+ if (dirPath.toLowerCase().endsWith('.uproject')) {
36
+ dirPath = path.dirname(dirPath);
37
+ }
38
+ const cleanCategory = category.replace(/^Default/, '');
39
+ const candidates = [
40
+ path.join(dirPath, 'Config', `Default${cleanCategory}.ini`),
41
+ path.join(dirPath, 'Saved', 'Config', 'WindowsEditor', `${cleanCategory}.ini`),
42
+ path.join(dirPath, 'Saved', 'Config', 'Windows', `${cleanCategory}.ini`),
43
+ path.join(dirPath, 'Saved', 'Config', 'Mac', `${cleanCategory}.ini`),
44
+ path.join(dirPath, 'Saved', 'Config', 'Linux', `${cleanCategory}.ini`)
45
+ ];
46
+ for (const configPath of candidates) {
47
+ try {
48
+ const iniData = await readIniFile(configPath);
49
+ if (sectionName) {
50
+ const section = iniData[sectionName];
51
+ if (section) {
52
+ if (key) {
53
+ return section[key];
54
+ }
55
+ return section;
56
+ }
57
+ }
58
+ else {
59
+ if (Object.keys(iniData).length > 0) {
60
+ return iniData;
61
+ }
62
+ }
63
+ }
64
+ catch (_e) {
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ //# sourceMappingURL=ini-reader.js.map
@@ -13,16 +13,19 @@ export class Logger {
13
13
  return order.indexOf(level) >= order.indexOf(this.level);
14
14
  }
15
15
  debug(...args) {
16
- if (this.shouldLog('debug'))
17
- console.error(`[${this.scope}]`, ...args);
16
+ if (!this.shouldLog('debug'))
17
+ return;
18
+ console.error(`[${this.scope}]`, ...args);
18
19
  }
19
20
  info(...args) {
20
- if (this.shouldLog('info'))
21
- console.error(`[${this.scope}]`, ...args);
21
+ if (!this.shouldLog('info'))
22
+ return;
23
+ console.error(`[${this.scope}]`, ...args);
22
24
  }
23
25
  warn(...args) {
24
- if (this.shouldLog('warn'))
25
- console.error(`[${this.scope}]`, ...args);
26
+ if (!this.shouldLog('warn'))
27
+ return;
28
+ console.warn(`[${this.scope}]`, ...args);
26
29
  }
27
30
  error(...args) {
28
31
  if (this.shouldLog('error'))
@@ -14,4 +14,7 @@ export declare function toVec3Object(input: any): Vec3Obj | null;
14
14
  export declare function toRotObject(input: any): Rot3Obj | null;
15
15
  export declare function toVec3Tuple(input: any): Vec3Tuple | null;
16
16
  export declare function toRotTuple(input: any): Rot3Tuple | null;
17
+ export declare function toFiniteNumber(raw: unknown): number | undefined;
18
+ export declare function normalizePartialVector(value: any, alternateKeys?: string[]): Record<string, number> | undefined;
19
+ export declare function normalizeTransformInput(transform: any): Record<string, unknown> | undefined;
17
20
  //# sourceMappingURL=normalize.d.ts.map
@@ -54,4 +54,60 @@ export function toRotTuple(input) {
54
54
  const { pitch, yaw, roll } = rot;
55
55
  return [pitch, yaw, roll];
56
56
  }
57
+ export function toFiniteNumber(raw) {
58
+ if (typeof raw === 'number' && Number.isFinite(raw))
59
+ return raw;
60
+ if (typeof raw === 'string') {
61
+ const trimmed = raw.trim();
62
+ if (trimmed.length === 0)
63
+ return undefined;
64
+ const parsed = Number(trimmed);
65
+ if (Number.isFinite(parsed))
66
+ return parsed;
67
+ }
68
+ return undefined;
69
+ }
70
+ export function normalizePartialVector(value, alternateKeys = ['x', 'y', 'z']) {
71
+ if (value === undefined || value === null)
72
+ return undefined;
73
+ const result = {};
74
+ const assignIfPresent = (component, raw) => {
75
+ const num = toFiniteNumber(raw);
76
+ if (num !== undefined)
77
+ result[component] = num;
78
+ };
79
+ if (Array.isArray(value)) {
80
+ if (value.length > 0)
81
+ assignIfPresent('x', value[0]);
82
+ if (value.length > 1)
83
+ assignIfPresent('y', value[1]);
84
+ if (value.length > 2)
85
+ assignIfPresent('z', value[2]);
86
+ }
87
+ else if (typeof value === 'object') {
88
+ const obj = value;
89
+ assignIfPresent('x', obj.x ?? obj[alternateKeys[0]]);
90
+ assignIfPresent('y', obj.y ?? obj[alternateKeys[1]]);
91
+ assignIfPresent('z', obj.z ?? obj[alternateKeys[2]]);
92
+ }
93
+ else {
94
+ assignIfPresent('x', value);
95
+ }
96
+ return Object.keys(result).length > 0 ? result : undefined;
97
+ }
98
+ export function normalizeTransformInput(transform) {
99
+ if (!transform || typeof transform !== 'object')
100
+ return undefined;
101
+ const result = {};
102
+ const location = normalizePartialVector(transform.location);
103
+ if (location)
104
+ result.location = location;
105
+ const rotation = normalizePartialVector(transform.rotation, ['pitch', 'yaw', 'roll']);
106
+ if (rotation)
107
+ result.rotation = rotation;
108
+ const scale = normalizePartialVector(transform.scale);
109
+ if (scale)
110
+ result.scale = scale;
111
+ return Object.keys(result).length > 0 ? result : undefined;
112
+ }
57
113
  //# sourceMappingURL=normalize.js.map
@@ -0,0 +1,2 @@
1
+ export declare function sanitizePath(path: string, allowedRoots?: string[]): string;
2
+ //# sourceMappingURL=path-security.d.ts.map
@@ -0,0 +1,24 @@
1
+ export function sanitizePath(path, allowedRoots = ['/Game', '/Engine']) {
2
+ if (!path || typeof path !== 'string') {
3
+ throw new Error('Invalid path: must be a non-empty string');
4
+ }
5
+ const trimmed = path.trim();
6
+ if (trimmed.length === 0) {
7
+ throw new Error('Invalid path: cannot be empty');
8
+ }
9
+ const normalized = trimmed.replace(/\\/g, '/');
10
+ if (normalized.includes('..')) {
11
+ throw new Error('Invalid path: directory traversal (..) is not allowed');
12
+ }
13
+ const isAllowed = allowedRoots.some(root => normalized.toLowerCase() === root.toLowerCase() ||
14
+ normalized.toLowerCase().startsWith(`${root.toLowerCase()}/`));
15
+ if (!isAllowed) {
16
+ throw new Error(`Invalid path: must start with one of [${allowedRoots.join(', ')}]`);
17
+ }
18
+ const invalidChars = /[<>:"|?*\x00-\x1f]/;
19
+ if (invalidChars.test(normalized)) {
20
+ throw new Error('Invalid path: contains illegal characters');
21
+ }
22
+ return normalized;
23
+ }
24
+ //# sourceMappingURL=path-security.js.map
@@ -0,0 +1,7 @@
1
+ import { StandardActionResponse } from '../types/tool-interfaces.js';
2
+ export declare class ResponseFactory {
3
+ static success(data: any, message?: string): StandardActionResponse;
4
+ static error(error: any, defaultMessage?: string): StandardActionResponse;
5
+ static validationError(message: string): StandardActionResponse;
6
+ }
7
+ //# sourceMappingURL=response-factory.d.ts.map
@@ -0,0 +1,27 @@
1
+ import { cleanObject } from './safe-json.js';
2
+ export class ResponseFactory {
3
+ static success(data, message = 'Operation successful') {
4
+ return {
5
+ success: true,
6
+ message,
7
+ data: cleanObject(data)
8
+ };
9
+ }
10
+ static error(error, defaultMessage = 'Operation failed') {
11
+ const errorMessage = error instanceof Error ? error.message : String(error || defaultMessage);
12
+ console.error('[ResponseFactory] Error:', error);
13
+ return {
14
+ success: false,
15
+ message: errorMessage,
16
+ data: null
17
+ };
18
+ }
19
+ static validationError(message) {
20
+ return {
21
+ success: false,
22
+ message: `Validation Error: ${message}`,
23
+ data: null
24
+ };
25
+ }
26
+ }
27
+ //# sourceMappingURL=response-factory.js.map