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.
- package/.env.example +26 -0
- package/.env.production +38 -7
- package/.eslintrc.json +0 -54
- package/.eslintrc.override.json +8 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +94 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
- package/.github/copilot-instructions.md +478 -45
- package/.github/dependabot.yml +19 -0
- package/.github/labeler.yml +24 -0
- package/.github/labels.yml +70 -0
- package/.github/pull_request_template.md +42 -0
- package/.github/release-drafter-config.yml +51 -0
- package/.github/workflows/auto-merge.yml +38 -0
- package/.github/workflows/ci.yml +38 -0
- package/.github/workflows/dependency-review.yml +17 -0
- package/.github/workflows/gemini-issue-triage.yml +172 -0
- package/.github/workflows/greetings.yml +27 -0
- package/.github/workflows/labeler.yml +17 -0
- package/.github/workflows/links.yml +80 -0
- package/.github/workflows/pr-size-labeler.yml +137 -0
- package/.github/workflows/publish-mcp.yml +13 -7
- package/.github/workflows/release-drafter.yml +23 -0
- package/.github/workflows/release.yml +112 -0
- package/.github/workflows/semantic-pull-request.yml +35 -0
- package/.github/workflows/smoke-test.yml +36 -0
- package/.github/workflows/stale.yml +28 -0
- package/CHANGELOG.md +338 -31
- package/CONTRIBUTING.md +140 -0
- package/GEMINI.md +115 -0
- package/Public/Plugin_setup_guide.mp4 +0 -0
- package/README.md +189 -128
- package/claude_desktop_config_example.json +7 -6
- package/dist/automation/bridge.d.ts +50 -0
- package/dist/automation/bridge.js +452 -0
- package/dist/automation/connection-manager.d.ts +23 -0
- package/dist/automation/connection-manager.js +107 -0
- package/dist/automation/handshake.d.ts +11 -0
- package/dist/automation/handshake.js +89 -0
- package/dist/automation/index.d.ts +3 -0
- package/dist/automation/index.js +3 -0
- package/dist/automation/message-handler.d.ts +12 -0
- package/dist/automation/message-handler.js +149 -0
- package/dist/automation/request-tracker.d.ts +25 -0
- package/dist/automation/request-tracker.js +98 -0
- package/dist/automation/types.d.ts +130 -0
- package/dist/automation/types.js +2 -0
- package/dist/cli.js +32 -5
- package/dist/config.d.ts +26 -0
- package/dist/config.js +59 -0
- package/dist/constants.d.ts +16 -0
- package/dist/constants.js +16 -0
- package/dist/graphql/loaders.d.ts +64 -0
- package/dist/graphql/loaders.js +117 -0
- package/dist/graphql/resolvers.d.ts +268 -0
- package/dist/graphql/resolvers.js +746 -0
- package/dist/graphql/schema.d.ts +5 -0
- package/dist/graphql/schema.js +437 -0
- package/dist/graphql/server.d.ts +26 -0
- package/dist/graphql/server.js +117 -0
- package/dist/graphql/types.d.ts +9 -0
- package/dist/graphql/types.js +2 -0
- package/dist/handlers/resource-handlers.d.ts +20 -0
- package/dist/handlers/resource-handlers.js +180 -0
- package/dist/index.d.ts +33 -18
- package/dist/index.js +130 -619
- package/dist/resources/actors.d.ts +17 -12
- package/dist/resources/actors.js +56 -76
- package/dist/resources/assets.d.ts +6 -14
- package/dist/resources/assets.js +115 -147
- package/dist/resources/levels.d.ts +13 -13
- package/dist/resources/levels.js +25 -34
- package/dist/server/resource-registry.d.ts +20 -0
- package/dist/server/resource-registry.js +37 -0
- package/dist/server/tool-registry.d.ts +23 -0
- package/dist/server/tool-registry.js +322 -0
- package/dist/server-setup.d.ts +20 -0
- package/dist/server-setup.js +71 -0
- package/dist/services/health-monitor.d.ts +34 -0
- package/dist/services/health-monitor.js +105 -0
- package/dist/services/metrics-server.d.ts +11 -0
- package/dist/services/metrics-server.js +105 -0
- package/dist/tools/actors.d.ts +163 -9
- package/dist/tools/actors.js +356 -311
- package/dist/tools/animation.d.ts +135 -4
- package/dist/tools/animation.js +510 -411
- package/dist/tools/assets.d.ts +75 -29
- package/dist/tools/assets.js +265 -284
- package/dist/tools/audio.d.ts +102 -42
- package/dist/tools/audio.js +272 -685
- package/dist/tools/base-tool.d.ts +17 -0
- package/dist/tools/base-tool.js +46 -0
- package/dist/tools/behavior-tree.d.ts +94 -0
- package/dist/tools/behavior-tree.js +39 -0
- package/dist/tools/blueprint.d.ts +208 -126
- package/dist/tools/blueprint.js +685 -832
- package/dist/tools/consolidated-tool-definitions.d.ts +5462 -1781
- package/dist/tools/consolidated-tool-definitions.js +829 -496
- package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
- package/dist/tools/consolidated-tool-handlers.js +198 -1027
- package/dist/tools/debug.d.ts +143 -85
- package/dist/tools/debug.js +234 -180
- package/dist/tools/dynamic-handler-registry.d.ts +13 -0
- package/dist/tools/dynamic-handler-registry.js +23 -0
- package/dist/tools/editor.d.ts +30 -83
- package/dist/tools/editor.js +247 -244
- package/dist/tools/engine.d.ts +10 -4
- package/dist/tools/engine.js +13 -5
- package/dist/tools/environment.d.ts +30 -0
- package/dist/tools/environment.js +267 -0
- package/dist/tools/foliage.d.ts +65 -99
- package/dist/tools/foliage.js +221 -331
- package/dist/tools/handlers/actor-handlers.d.ts +3 -0
- package/dist/tools/handlers/actor-handlers.js +227 -0
- package/dist/tools/handlers/animation-handlers.d.ts +3 -0
- package/dist/tools/handlers/animation-handlers.js +185 -0
- package/dist/tools/handlers/argument-helper.d.ts +16 -0
- package/dist/tools/handlers/argument-helper.js +80 -0
- package/dist/tools/handlers/asset-handlers.d.ts +3 -0
- package/dist/tools/handlers/asset-handlers.js +496 -0
- package/dist/tools/handlers/audio-handlers.d.ts +3 -0
- package/dist/tools/handlers/audio-handlers.js +166 -0
- package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
- package/dist/tools/handlers/blueprint-handlers.js +358 -0
- package/dist/tools/handlers/common-handlers.d.ts +14 -0
- package/dist/tools/handlers/common-handlers.js +56 -0
- package/dist/tools/handlers/editor-handlers.d.ts +3 -0
- package/dist/tools/handlers/editor-handlers.js +119 -0
- package/dist/tools/handlers/effect-handlers.d.ts +3 -0
- package/dist/tools/handlers/effect-handlers.js +171 -0
- package/dist/tools/handlers/environment-handlers.d.ts +3 -0
- package/dist/tools/handlers/environment-handlers.js +170 -0
- package/dist/tools/handlers/graph-handlers.d.ts +3 -0
- package/dist/tools/handlers/graph-handlers.js +90 -0
- package/dist/tools/handlers/input-handlers.d.ts +3 -0
- package/dist/tools/handlers/input-handlers.js +21 -0
- package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
- package/dist/tools/handlers/inspect-handlers.js +383 -0
- package/dist/tools/handlers/level-handlers.d.ts +3 -0
- package/dist/tools/handlers/level-handlers.js +237 -0
- package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
- package/dist/tools/handlers/lighting-handlers.js +144 -0
- package/dist/tools/handlers/performance-handlers.d.ts +3 -0
- package/dist/tools/handlers/performance-handlers.js +130 -0
- package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
- package/dist/tools/handlers/pipeline-handlers.js +110 -0
- package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
- package/dist/tools/handlers/sequence-handlers.js +376 -0
- package/dist/tools/handlers/system-handlers.d.ts +4 -0
- package/dist/tools/handlers/system-handlers.js +506 -0
- package/dist/tools/input.d.ts +19 -0
- package/dist/tools/input.js +89 -0
- package/dist/tools/introspection.d.ts +103 -40
- package/dist/tools/introspection.js +425 -568
- package/dist/tools/landscape.d.ts +54 -93
- package/dist/tools/landscape.js +284 -409
- package/dist/tools/level.d.ts +66 -27
- package/dist/tools/level.js +647 -675
- package/dist/tools/lighting.d.ts +77 -38
- package/dist/tools/lighting.js +445 -943
- package/dist/tools/logs.d.ts +3 -3
- package/dist/tools/logs.js +5 -57
- package/dist/tools/materials.d.ts +91 -24
- package/dist/tools/materials.js +194 -118
- package/dist/tools/niagara.d.ts +149 -39
- package/dist/tools/niagara.js +267 -182
- package/dist/tools/performance.d.ts +27 -13
- package/dist/tools/performance.js +203 -122
- package/dist/tools/physics.d.ts +32 -77
- package/dist/tools/physics.js +175 -582
- package/dist/tools/property-dictionary.d.ts +13 -0
- package/dist/tools/property-dictionary.js +82 -0
- package/dist/tools/sequence.d.ts +85 -60
- package/dist/tools/sequence.js +208 -747
- package/dist/tools/tool-definition-utils.d.ts +59 -0
- package/dist/tools/tool-definition-utils.js +35 -0
- package/dist/tools/ui.d.ts +64 -34
- package/dist/tools/ui.js +134 -214
- package/dist/types/automation-responses.d.ts +115 -0
- package/dist/types/automation-responses.js +2 -0
- package/dist/types/env.d.ts +0 -3
- package/dist/types/env.js +0 -7
- package/dist/types/responses.d.ts +249 -0
- package/dist/types/responses.js +2 -0
- package/dist/types/tool-interfaces.d.ts +898 -0
- package/dist/types/tool-interfaces.js +2 -0
- package/dist/types/tool-types.d.ts +183 -19
- package/dist/types/tool-types.js +0 -4
- package/dist/unreal-bridge.d.ts +24 -131
- package/dist/unreal-bridge.js +364 -1506
- package/dist/utils/command-validator.d.ts +9 -0
- package/dist/utils/command-validator.js +68 -0
- package/dist/utils/elicitation.d.ts +1 -1
- package/dist/utils/elicitation.js +12 -15
- package/dist/utils/error-handler.d.ts +2 -51
- package/dist/utils/error-handler.js +11 -87
- package/dist/utils/ini-reader.d.ts +3 -0
- package/dist/utils/ini-reader.js +69 -0
- package/dist/utils/logger.js +9 -6
- package/dist/utils/normalize.d.ts +3 -0
- package/dist/utils/normalize.js +56 -0
- package/dist/utils/path-security.d.ts +2 -0
- package/dist/utils/path-security.js +24 -0
- package/dist/utils/response-factory.d.ts +7 -0
- package/dist/utils/response-factory.js +27 -0
- package/dist/utils/response-validator.d.ts +3 -24
- package/dist/utils/response-validator.js +130 -81
- package/dist/utils/result-helpers.d.ts +4 -5
- package/dist/utils/result-helpers.js +15 -16
- package/dist/utils/safe-json.js +5 -11
- package/dist/utils/unreal-command-queue.d.ts +24 -0
- package/dist/utils/unreal-command-queue.js +120 -0
- package/dist/utils/validation.d.ts +0 -40
- package/dist/utils/validation.js +1 -78
- package/dist/wasm/index.d.ts +70 -0
- package/dist/wasm/index.js +535 -0
- package/docs/GraphQL-API.md +888 -0
- package/docs/Migration-Guide-v0.5.0.md +684 -0
- package/docs/Roadmap.md +53 -0
- package/docs/WebAssembly-Integration.md +628 -0
- package/docs/editor-plugin-extension.md +370 -0
- package/docs/handler-mapping.md +242 -0
- package/docs/native-automation-progress.md +128 -0
- package/docs/testing-guide.md +423 -0
- package/mcp-config-example.json +6 -6
- package/package.json +67 -28
- package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
- package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
- package/scripts/check-unreal-connection.mjs +19 -0
- package/scripts/clean-tmp.js +23 -0
- package/scripts/patch-wasm.js +26 -0
- package/scripts/run-all-tests.mjs +136 -0
- package/scripts/smoke-test.ts +94 -0
- package/scripts/sync-mcp-plugin.js +143 -0
- package/scripts/test-no-plugin-alternates.mjs +113 -0
- package/scripts/validate-server.js +46 -0
- package/scripts/verify-automation-bridge.js +200 -0
- package/server.json +58 -21
- package/src/automation/bridge.ts +558 -0
- package/src/automation/connection-manager.ts +130 -0
- package/src/automation/handshake.ts +99 -0
- package/src/automation/index.ts +2 -0
- package/src/automation/message-handler.ts +167 -0
- package/src/automation/request-tracker.ts +123 -0
- package/src/automation/types.ts +107 -0
- package/src/cli.ts +33 -6
- package/src/config.ts +73 -0
- package/src/constants.ts +19 -0
- package/src/graphql/loaders.ts +244 -0
- package/src/graphql/resolvers.ts +1008 -0
- package/src/graphql/schema.ts +452 -0
- package/src/graphql/server.ts +156 -0
- package/src/graphql/types.ts +10 -0
- package/src/handlers/resource-handlers.ts +186 -0
- package/src/index.ts +166 -664
- package/src/resources/actors.ts +58 -76
- package/src/resources/assets.ts +148 -134
- package/src/resources/levels.ts +28 -33
- package/src/server/resource-registry.ts +47 -0
- package/src/server/tool-registry.ts +354 -0
- package/src/server-setup.ts +114 -0
- package/src/services/health-monitor.ts +132 -0
- package/src/services/metrics-server.ts +142 -0
- package/src/tools/actors.ts +426 -323
- package/src/tools/animation.ts +672 -461
- package/src/tools/assets.ts +364 -289
- package/src/tools/audio.ts +323 -766
- package/src/tools/base-tool.ts +52 -0
- package/src/tools/behavior-tree.ts +45 -0
- package/src/tools/blueprint.ts +792 -970
- package/src/tools/consolidated-tool-definitions.ts +993 -515
- package/src/tools/consolidated-tool-handlers.ts +258 -1146
- package/src/tools/debug.ts +292 -187
- package/src/tools/dynamic-handler-registry.ts +33 -0
- package/src/tools/editor.ts +329 -253
- package/src/tools/engine.ts +14 -3
- package/src/tools/environment.ts +281 -0
- package/src/tools/foliage.ts +330 -392
- package/src/tools/handlers/actor-handlers.ts +265 -0
- package/src/tools/handlers/animation-handlers.ts +237 -0
- package/src/tools/handlers/argument-helper.ts +142 -0
- package/src/tools/handlers/asset-handlers.ts +532 -0
- package/src/tools/handlers/audio-handlers.ts +194 -0
- package/src/tools/handlers/blueprint-handlers.ts +380 -0
- package/src/tools/handlers/common-handlers.ts +87 -0
- package/src/tools/handlers/editor-handlers.ts +123 -0
- package/src/tools/handlers/effect-handlers.ts +220 -0
- package/src/tools/handlers/environment-handlers.ts +183 -0
- package/src/tools/handlers/graph-handlers.ts +116 -0
- package/src/tools/handlers/input-handlers.ts +28 -0
- package/src/tools/handlers/inspect-handlers.ts +450 -0
- package/src/tools/handlers/level-handlers.ts +252 -0
- package/src/tools/handlers/lighting-handlers.ts +147 -0
- package/src/tools/handlers/performance-handlers.ts +132 -0
- package/src/tools/handlers/pipeline-handlers.ts +127 -0
- package/src/tools/handlers/sequence-handlers.ts +415 -0
- package/src/tools/handlers/system-handlers.ts +564 -0
- package/src/tools/input.ts +101 -0
- package/src/tools/introspection.ts +493 -584
- package/src/tools/landscape.ts +418 -507
- package/src/tools/level.ts +786 -708
- package/src/tools/lighting.ts +588 -984
- package/src/tools/logs.ts +9 -57
- package/src/tools/materials.ts +237 -121
- package/src/tools/niagara.ts +335 -168
- package/src/tools/performance.ts +320 -169
- package/src/tools/physics.ts +274 -613
- package/src/tools/property-dictionary.ts +98 -0
- package/src/tools/sequence.ts +276 -820
- package/src/tools/tool-definition-utils.ts +35 -0
- package/src/tools/ui.ts +205 -283
- package/src/types/automation-responses.ts +119 -0
- package/src/types/env.ts +0 -10
- package/src/types/responses.ts +355 -0
- package/src/types/tool-interfaces.ts +250 -0
- package/src/types/tool-types.ts +243 -21
- package/src/unreal-bridge.ts +460 -1550
- package/src/utils/command-validator.ts +76 -0
- package/src/utils/elicitation.ts +10 -7
- package/src/utils/error-handler.ts +14 -90
- package/src/utils/ini-reader.ts +86 -0
- package/src/utils/logger.ts +8 -3
- package/src/utils/normalize.test.ts +162 -0
- package/src/utils/normalize.ts +60 -0
- package/src/utils/path-security.ts +43 -0
- package/src/utils/response-factory.ts +44 -0
- package/src/utils/response-validator.ts +176 -56
- package/src/utils/result-helpers.ts +21 -19
- package/src/utils/safe-json.test.ts +90 -0
- package/src/utils/safe-json.ts +14 -11
- package/src/utils/unreal-command-queue.ts +152 -0
- package/src/utils/validation.test.ts +184 -0
- package/src/utils/validation.ts +4 -1
- package/src/wasm/index.ts +838 -0
- package/test-server.mjs +100 -0
- package/tests/run-unreal-tool-tests.mjs +242 -14
- package/tests/test-animation.mjs +369 -0
- package/tests/test-asset-advanced.mjs +82 -0
- package/tests/test-asset-errors.mjs +35 -0
- package/tests/test-asset-graph.mjs +311 -0
- package/tests/test-audio.mjs +417 -0
- package/tests/test-automation-timeouts.mjs +98 -0
- package/tests/test-behavior-tree.mjs +444 -0
- package/tests/test-blueprint-graph.mjs +410 -0
- package/tests/test-blueprint.mjs +577 -0
- package/tests/test-client-mode.mjs +86 -0
- package/tests/test-console-command.mjs +56 -0
- package/tests/test-control-actor.mjs +425 -0
- package/tests/test-control-editor.mjs +112 -0
- package/tests/test-graphql.mjs +372 -0
- package/tests/test-input.mjs +349 -0
- package/tests/test-inspect.mjs +302 -0
- package/tests/test-landscape.mjs +316 -0
- package/tests/test-lighting.mjs +428 -0
- package/tests/test-manage-asset.mjs +438 -0
- package/tests/test-manage-level.mjs +89 -0
- package/tests/test-materials.mjs +356 -0
- package/tests/test-niagara.mjs +185 -0
- package/tests/test-no-inline-python.mjs +122 -0
- package/tests/test-performance.mjs +539 -0
- package/tests/test-plugin-handshake.mjs +82 -0
- package/tests/test-runner.mjs +933 -0
- package/tests/test-sequence.mjs +104 -0
- package/tests/test-system.mjs +96 -0
- package/tests/test-wasm.mjs +283 -0
- package/tests/test-world-partition.mjs +215 -0
- package/tsconfig.json +3 -3
- package/vitest.config.ts +35 -0
- package/wasm/Cargo.lock +363 -0
- package/wasm/Cargo.toml +42 -0
- package/wasm/LICENSE +21 -0
- package/wasm/README.md +253 -0
- package/wasm/src/dependency_resolver.rs +377 -0
- package/wasm/src/lib.rs +153 -0
- package/wasm/src/property_parser.rs +271 -0
- package/wasm/src/transform_math.rs +396 -0
- package/wasm/tests/integration.rs +109 -0
- package/.github/workflows/smithery-build.yml +0 -29
- package/dist/prompts/index.d.ts +0 -21
- package/dist/prompts/index.js +0 -217
- package/dist/tools/build_environment_advanced.d.ts +0 -65
- package/dist/tools/build_environment_advanced.js +0 -633
- package/dist/tools/rc.d.ts +0 -110
- package/dist/tools/rc.js +0 -437
- package/dist/tools/visual.d.ts +0 -40
- package/dist/tools/visual.js +0 -282
- package/dist/utils/http.d.ts +0 -6
- package/dist/utils/http.js +0 -151
- package/dist/utils/python-output.d.ts +0 -18
- package/dist/utils/python-output.js +0 -290
- package/dist/utils/python.d.ts +0 -2
- package/dist/utils/python.js +0 -4
- package/dist/utils/stdio-redirect.d.ts +0 -2
- package/dist/utils/stdio-redirect.js +0 -20
- package/docs/unreal-tool-test-cases.md +0 -574
- package/smithery.yaml +0 -29
- package/src/prompts/index.ts +0 -249
- package/src/tools/build_environment_advanced.ts +0 -732
- package/src/tools/rc.ts +0 -515
- package/src/tools/visual.ts +0 -281
- package/src/utils/http.ts +0 -187
- package/src/utils/python-output.ts +0 -351
- package/src/utils/python.ts +0 -3
- 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
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export function createElicitationHelper(server, log) {
|
|
2
|
-
|
|
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;
|
|
32
|
+
const primitive = rawSchema;
|
|
35
33
|
if ('properties' in primitive || 'items' in primitive)
|
|
36
|
-
return false;
|
|
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.
|
|
56
|
-
return opts.
|
|
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.
|
|
75
|
-
return opts.
|
|
72
|
+
if (opts.alternate)
|
|
73
|
+
return opts.alternate();
|
|
76
74
|
return { ok: false, error: action };
|
|
77
75
|
}
|
|
78
|
-
if (opts.
|
|
79
|
-
return opts.
|
|
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;
|
|
93
|
-
if (opts.
|
|
94
|
-
return opts.
|
|
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:
|
|
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('
|
|
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
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
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 *
|
|
129
|
+
delay = Math.min(delay * multiplier, maxDelay);
|
|
158
130
|
}
|
|
159
131
|
}
|
|
160
|
-
throw
|
|
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
|
package/dist/utils/logger.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/utils/normalize.js
CHANGED
|
@@ -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,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
|