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
package/test-server.mjs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { exec } from 'child_process';
|
|
3
|
+
|
|
4
|
+
const server = spawn('node', ['dist/cli.js'], {
|
|
5
|
+
stdio: ['pipe', 'pipe', 'inherit'],
|
|
6
|
+
cwd: process.cwd()
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
let initialized = false;
|
|
10
|
+
let gotResponse = false;
|
|
11
|
+
|
|
12
|
+
server.stdout.on('data', (data) => {
|
|
13
|
+
const text = data.toString();
|
|
14
|
+
console.log('SERVER OUTPUT:', text);
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(text.trim());
|
|
18
|
+
if (parsed.id === 1 && parsed.result && !initialized) {
|
|
19
|
+
initialized = true;
|
|
20
|
+
console.log('Server initialized successfully');
|
|
21
|
+
|
|
22
|
+
// Send initialized message
|
|
23
|
+
const initializedMsg = JSON.stringify({
|
|
24
|
+
jsonrpc: '2.0',
|
|
25
|
+
method: 'initialized',
|
|
26
|
+
params: {}
|
|
27
|
+
}) + '\n';
|
|
28
|
+
console.log('Sending initialized message...');
|
|
29
|
+
server.stdin.write(initializedMsg);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (parsed.id === 2 && parsed.result) {
|
|
33
|
+
gotResponse = true;
|
|
34
|
+
console.log('Got health response, checking port...');
|
|
35
|
+
|
|
36
|
+
exec('netstat -ano | findstr :8090', (err, stdout) => {
|
|
37
|
+
if (stdout && stdout.trim()) {
|
|
38
|
+
console.log('✅ Port 8090 is listening!');
|
|
39
|
+
console.log('Port details:', stdout.trim());
|
|
40
|
+
} else {
|
|
41
|
+
console.log('❌ Port 8090 is not listening');
|
|
42
|
+
}
|
|
43
|
+
server.kill();
|
|
44
|
+
process.exit(0);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
} catch (e) {
|
|
48
|
+
// Not JSON, ignore
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
server.on('exit', (code) => {
|
|
53
|
+
console.log('Server exited with code:', code);
|
|
54
|
+
if (!gotResponse) {
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
server.on('error', (err) => {
|
|
60
|
+
console.error('Failed to start server:', err);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Send initialize message
|
|
65
|
+
const initMsg = JSON.stringify({
|
|
66
|
+
jsonrpc: '2.0',
|
|
67
|
+
id: 1,
|
|
68
|
+
method: 'initialize',
|
|
69
|
+
params: {
|
|
70
|
+
protocolVersion: '2024-11-05',
|
|
71
|
+
capabilities: {},
|
|
72
|
+
clientInfo: { name: 'test', version: '1.0.0' }
|
|
73
|
+
}
|
|
74
|
+
}) + '\n';
|
|
75
|
+
|
|
76
|
+
console.log('Sending initialize message...');
|
|
77
|
+
server.stdin.write(initMsg);
|
|
78
|
+
|
|
79
|
+
// Send health check after a delay
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
if (initialized && !gotResponse) {
|
|
82
|
+
console.log('Sending health check...');
|
|
83
|
+
const healthMsg = JSON.stringify({
|
|
84
|
+
jsonrpc: '2.0',
|
|
85
|
+
id: 2,
|
|
86
|
+
method: 'resources/read',
|
|
87
|
+
params: { uri: 'ue://health' }
|
|
88
|
+
}) + '\n';
|
|
89
|
+
server.stdin.write(healthMsg);
|
|
90
|
+
}
|
|
91
|
+
}, 1000);
|
|
92
|
+
|
|
93
|
+
// Timeout
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
if (!gotResponse) {
|
|
96
|
+
console.log('Timeout: Server did not respond');
|
|
97
|
+
server.kill();
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
}, 5000);
|
|
@@ -37,13 +37,15 @@ const defaultDocPath = path.resolve(repoRoot, 'docs', 'unreal-tool-test-cases.md
|
|
|
37
37
|
const docPath = path.resolve(repoRoot, process.env.UNREAL_MCP_TEST_DOC ?? defaultDocPath);
|
|
38
38
|
const reportsDir = path.resolve(repoRoot, 'tests', 'reports');
|
|
39
39
|
const resultsPath = path.join(reportsDir, `unreal-tool-test-results-${new Date().toISOString().replace(/[:]/g, '-')}.json`);
|
|
40
|
-
const defaultFbxDir = normalizeWindowsPath(process.env.UNREAL_MCP_FBX_DIR ?? '
|
|
40
|
+
const defaultFbxDir = normalizeWindowsPath(process.env.UNREAL_MCP_FBX_DIR ?? path.join(repoRoot, 'tests', 'assets', 'fbx'));
|
|
41
41
|
const defaultFbxFile = normalizeWindowsPath(process.env.UNREAL_MCP_FBX_FILE ?? path.join(defaultFbxDir, 'test_model.fbx'));
|
|
42
42
|
|
|
43
43
|
const cliOptions = parseCliOptions(process.argv.slice(2));
|
|
44
44
|
const serverCommand = process.env.UNREAL_MCP_SERVER_CMD ?? 'node';
|
|
45
45
|
const serverArgs = parseArgsList(process.env.UNREAL_MCP_SERVER_ARGS) ?? [path.join(repoRoot, 'dist', 'cli.js')];
|
|
46
46
|
const serverCwd = process.env.UNREAL_MCP_SERVER_CWD ?? repoRoot;
|
|
47
|
+
const stressTestMode = process.env.STRESS_TEST_MODE === '1';
|
|
48
|
+
const benchmarkMode = process.env.BENCHMARK_MODE === '1';
|
|
47
49
|
|
|
48
50
|
async function main() {
|
|
49
51
|
await ensureFbxDirectory();
|
|
@@ -70,6 +72,8 @@ async function main() {
|
|
|
70
72
|
|
|
71
73
|
let transport; let client;
|
|
72
74
|
const runResults = [];
|
|
75
|
+
let automationBridgeStatus = { connected: false, summary: null };
|
|
76
|
+
let automationBridgeTestsEnabled = process.env.UNREAL_MCP_AUTOMATION_BRIDGE === '1';
|
|
73
77
|
|
|
74
78
|
if (!cliOptions.dryRun) {
|
|
75
79
|
try {
|
|
@@ -87,6 +91,25 @@ async function main() {
|
|
|
87
91
|
|
|
88
92
|
await client.connect(transport);
|
|
89
93
|
await client.listTools({});
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const bridgeResource = await client.readResource({ uri: 'ue://automation-bridge' });
|
|
97
|
+
const text = bridgeResource.contents?.[0]?.text;
|
|
98
|
+
if (text) {
|
|
99
|
+
const parsed = JSON.parse(text);
|
|
100
|
+
if (parsed && typeof parsed === 'object') {
|
|
101
|
+
const summary = parsed.summary ?? parsed;
|
|
102
|
+
const connected = Boolean(summary?.connected);
|
|
103
|
+
automationBridgeStatus = { connected, summary };
|
|
104
|
+
if (connected) {
|
|
105
|
+
automationBridgeTestsEnabled = true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
// Resource may not exist on older servers; treat as unavailable without failing run
|
|
111
|
+
console.warn('[warn] Unable to query ue://automation-bridge resource:', err?.message ?? String(err));
|
|
112
|
+
}
|
|
90
113
|
} catch (err) {
|
|
91
114
|
console.error('Failed to start or initialize MCP server:', err);
|
|
92
115
|
if (transport) {
|
|
@@ -98,6 +121,22 @@ async function main() {
|
|
|
98
121
|
}
|
|
99
122
|
|
|
100
123
|
for (const testCase of filteredCases) {
|
|
124
|
+
let skipReason = testCase.skipReason;
|
|
125
|
+
|
|
126
|
+
if (!skipReason && testCase.groupName === 'Automation Bridge') {
|
|
127
|
+
if (!automationBridgeTestsEnabled) {
|
|
128
|
+
skipReason = 'Automation bridge tests disabled (set UNREAL_MCP_AUTOMATION_BRIDGE=1 or connect the plugin).';
|
|
129
|
+
} else {
|
|
130
|
+
const requestedTransport = typeof testCase.arguments?.transport === 'string'
|
|
131
|
+
? testCase.arguments.transport.trim().toLowerCase()
|
|
132
|
+
: '';
|
|
133
|
+
const wantsBridge = ['automation_bridge', 'automation', 'bridge'].includes(requestedTransport);
|
|
134
|
+
if (wantsBridge && !automationBridgeStatus.connected) {
|
|
135
|
+
skipReason = 'Automation bridge transport requested but plugin is not connected.';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
101
140
|
if (testCase.skipReason) {
|
|
102
141
|
runResults.push({
|
|
103
142
|
...testCase,
|
|
@@ -108,6 +147,16 @@ async function main() {
|
|
|
108
147
|
continue;
|
|
109
148
|
}
|
|
110
149
|
|
|
150
|
+
if (skipReason) {
|
|
151
|
+
runResults.push({
|
|
152
|
+
...testCase,
|
|
153
|
+
status: 'skipped',
|
|
154
|
+
detail: skipReason
|
|
155
|
+
});
|
|
156
|
+
console.log(formatResultLine(testCase, 'skipped', skipReason));
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
111
160
|
if (cliOptions.dryRun) {
|
|
112
161
|
runResults.push({
|
|
113
162
|
...testCase,
|
|
@@ -162,6 +211,11 @@ async function main() {
|
|
|
162
211
|
await persistResults(runResults);
|
|
163
212
|
summarize(runResults);
|
|
164
213
|
|
|
214
|
+
// Performance statistics if benchmarking
|
|
215
|
+
if (benchmarkMode) {
|
|
216
|
+
generateBenchmarkReport(runResults);
|
|
217
|
+
}
|
|
218
|
+
|
|
165
219
|
if (runResults.some((result) => result.status === 'failed')) {
|
|
166
220
|
process.exitCode = 1;
|
|
167
221
|
}
|
|
@@ -581,12 +635,6 @@ function enrichTestCase(rawCase) {
|
|
|
581
635
|
case 'System Control Tools': {
|
|
582
636
|
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
583
637
|
if (!payloadValue.action) return { ...base, skipReason: 'Missing action in payload' };
|
|
584
|
-
if (payloadValue.action === 'engine_quit' || payloadValue.action === 'engine_start') {
|
|
585
|
-
return {
|
|
586
|
-
...base,
|
|
587
|
-
skipReason: 'Skipping engine process management during automated run'
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
638
|
return {
|
|
591
639
|
...base,
|
|
592
640
|
toolName: 'system_control',
|
|
@@ -604,14 +652,109 @@ function enrichTestCase(rawCase) {
|
|
|
604
652
|
arguments: payloadValue
|
|
605
653
|
};
|
|
606
654
|
}
|
|
607
|
-
case '
|
|
655
|
+
case 'Asset Boundary Tests': {
|
|
608
656
|
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
657
|
+
return { ...base, toolName: 'manage_asset', arguments: payloadValue };
|
|
658
|
+
}
|
|
659
|
+
case 'Actor Boundary Tests': {
|
|
660
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
661
|
+
const args = { ...payloadValue };
|
|
662
|
+
if (Array.isArray(args.location) && args.location.length === 3) {
|
|
663
|
+
args.location = { x: args.location[0], y: args.location[1], z: args.location[2] };
|
|
664
|
+
}
|
|
665
|
+
if (Array.isArray(args.rotation) && args.rotation.length === 3) {
|
|
666
|
+
args.rotation = { pitch: args.rotation[0], yaw: args.rotation[1], roll: args.rotation[2] };
|
|
667
|
+
}
|
|
668
|
+
if (Array.isArray(args.scale) && args.scale.length === 3) {
|
|
669
|
+
args.scale = { x: args.scale[0], y: args.scale[1], z: args.scale[2] };
|
|
670
|
+
}
|
|
671
|
+
if (Array.isArray(args.force) && args.force.length === 3) {
|
|
672
|
+
args.force = { x: args.force[0], y: args.force[1], z: args.force[2] };
|
|
673
|
+
}
|
|
674
|
+
return { ...base, toolName: 'control_actor', arguments: args };
|
|
675
|
+
}
|
|
676
|
+
case 'Editor Boundary Tests':
|
|
677
|
+
case 'Editor Control Boundary Tests': {
|
|
678
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
679
|
+
return { ...base, toolName: 'control_editor', arguments: payloadValue };
|
|
680
|
+
}
|
|
681
|
+
case 'Level Boundary Tests':
|
|
682
|
+
case 'Level Management Boundary Tests': {
|
|
683
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
684
|
+
return { ...base, toolName: 'manage_level', arguments: payloadValue };
|
|
685
|
+
}
|
|
686
|
+
case 'Animation Boundary Tests': {
|
|
687
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
688
|
+
return { ...base, toolName: 'animation_physics', arguments: payloadValue };
|
|
689
|
+
}
|
|
690
|
+
case 'Blueprint Boundary Tests':
|
|
691
|
+
case 'Blueprint Control Boundary Tests': {
|
|
692
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
693
|
+
return { ...base, toolName: 'manage_blueprint', arguments: payloadValue };
|
|
694
|
+
}
|
|
695
|
+
case 'Effects Boundary Tests':
|
|
696
|
+
case 'Effects Control Boundary Tests': {
|
|
697
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
698
|
+
const args = { ...payloadValue };
|
|
699
|
+
if (Array.isArray(args.location) && args.location.length === 3) {
|
|
700
|
+
args.location = { x: args.location[0], y: args.location[1], z: args.location[2] };
|
|
701
|
+
}
|
|
702
|
+
if (Array.isArray(args.start) && args.start.length === 3) {
|
|
703
|
+
args.start = { x: args.start[0], y: args.start[1], z: args.start[2] };
|
|
704
|
+
}
|
|
705
|
+
if (Array.isArray(args.end) && args.end.length === 3) {
|
|
706
|
+
args.end = { x: args.end[0], y: args.end[1], z: args.end[2] };
|
|
707
|
+
}
|
|
708
|
+
return { ...base, toolName: 'create_effect', arguments: args };
|
|
709
|
+
}
|
|
710
|
+
case 'Environment Boundary Tests':
|
|
711
|
+
case 'Environment Building Boundary Tests': {
|
|
712
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
713
|
+
const args = { ...payloadValue };
|
|
714
|
+
if (Array.isArray(args.location) && args.location.length === 3) {
|
|
715
|
+
args.location = { x: args.location[0], y: args.location[1], z: args.location[2] };
|
|
716
|
+
}
|
|
717
|
+
if (args.bounds) {
|
|
718
|
+
const bounds = { ...args.bounds };
|
|
719
|
+
if (Array.isArray(bounds.location) && bounds.location.length === 3) {
|
|
720
|
+
bounds.location = { x: bounds.location[0], y: bounds.location[1], z: bounds.location[2] };
|
|
721
|
+
}
|
|
722
|
+
if (Array.isArray(bounds.size) && bounds.size.length === 3) {
|
|
723
|
+
bounds.size = { x: bounds.size[0], y: bounds.size[1], z: bounds.size[2] };
|
|
724
|
+
}
|
|
725
|
+
args.bounds = bounds;
|
|
726
|
+
}
|
|
727
|
+
return { ...base, toolName: 'build_environment', arguments: args };
|
|
728
|
+
}
|
|
729
|
+
case 'System Boundary Tests':
|
|
730
|
+
case 'System Control Boundary Tests': {
|
|
731
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
732
|
+
return { ...base, toolName: 'system_control', arguments: payloadValue };
|
|
733
|
+
}
|
|
734
|
+
case 'Sequence Boundary Tests':
|
|
735
|
+
case 'Sequence Control Boundary Tests': {
|
|
736
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
737
|
+
return { ...base, toolName: 'manage_sequence', arguments: payloadValue };
|
|
738
|
+
}
|
|
739
|
+
case 'Remote Control Boundary Tests':
|
|
740
|
+
case 'Remote Control Preset Boundary Tests': {
|
|
741
|
+
// No consolidated remote control tool mapping; treated as unsupported group
|
|
742
|
+
return { ...base, skipReason: `Unknown tool group '${rawCase.groupName}'` };
|
|
743
|
+
}
|
|
744
|
+
case 'Python Execution Boundary Tests': {
|
|
745
|
+
// No consolidated Python execution tool; treated as unsupported group
|
|
746
|
+
return { ...base, skipReason: `Unknown tool group '${rawCase.groupName}'` };
|
|
747
|
+
}
|
|
748
|
+
case 'Inspection Boundary Tests': {
|
|
749
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
750
|
+
return { ...base, toolName: 'inspect', arguments: payloadValue };
|
|
751
|
+
}
|
|
752
|
+
case 'Cross-Tool Integration Tests':
|
|
753
|
+
case 'Stress Test Scenarios':
|
|
754
|
+
case 'Error Recovery Tests': {
|
|
755
|
+
if (!payloadValue) return { ...base, skipReason: 'No JSON payload provided' };
|
|
756
|
+
// These require multi-step execution or special handling
|
|
757
|
+
return { ...base, skipReason: 'Multi-step test scenario - requires custom test implementation' };
|
|
615
758
|
}
|
|
616
759
|
default:
|
|
617
760
|
return { ...base, skipReason: `Unknown tool group '${rawCase.groupName}'` };
|
|
@@ -628,7 +771,51 @@ function evaluateExpectation(testCase, response) {
|
|
|
628
771
|
: undefined;
|
|
629
772
|
const actualSuccess = structuredSuccess ?? !response.isError;
|
|
630
773
|
|
|
774
|
+
// Extract actual error/message from response
|
|
775
|
+
let actualError = null;
|
|
776
|
+
let actualMessage = null;
|
|
777
|
+
if (response.structuredContent) {
|
|
778
|
+
actualError = response.structuredContent.error;
|
|
779
|
+
actualMessage = response.structuredContent.message;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// CRITICAL FIX: UE_NOT_CONNECTED errors should ALWAYS fail tests unless explicitly expected
|
|
783
|
+
if (actualError === 'UE_NOT_CONNECTED') {
|
|
784
|
+
const explicitlyExpectsDisconnection = lowerExpected.includes('not connected') ||
|
|
785
|
+
lowerExpected.includes('ue_not_connected') ||
|
|
786
|
+
lowerExpected.includes('disconnected');
|
|
787
|
+
if (!explicitlyExpectsDisconnection) {
|
|
788
|
+
return {
|
|
789
|
+
passed: false,
|
|
790
|
+
reason: `Test requires Unreal Engine connection, but got: ${actualError} - ${actualMessage}`
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// For tests that expect specific error types, validate the actual error matches
|
|
631
796
|
const expectedFailure = containsFailure && !containsSuccess;
|
|
797
|
+
if (expectedFailure && !actualSuccess) {
|
|
798
|
+
// Test expects failure and got failure - but verify it's the RIGHT kind of failure
|
|
799
|
+
const lowerReason = actualMessage?.toLowerCase() || actualError?.toLowerCase() || '';
|
|
800
|
+
const errorTypeMatch = failureKeywords.some(keyword => lowerExpected.includes(keyword) && lowerReason.includes(keyword));
|
|
801
|
+
|
|
802
|
+
// If expected outcome specifies an error type, actual error should match it
|
|
803
|
+
if (lowerExpected.includes('not found') || lowerExpected.includes('invalid') ||
|
|
804
|
+
lowerExpected.includes('missing') || lowerExpected.includes('already exists')) {
|
|
805
|
+
const passed = errorTypeMatch;
|
|
806
|
+
let reason;
|
|
807
|
+
if (response.isError) {
|
|
808
|
+
reason = response.content?.map((entry) => ('text' in entry ? entry.text : JSON.stringify(entry))).join('\n');
|
|
809
|
+
} else if (response.structuredContent) {
|
|
810
|
+
reason = JSON.stringify(response.structuredContent);
|
|
811
|
+
} else {
|
|
812
|
+
reason = 'No structured response returned';
|
|
813
|
+
}
|
|
814
|
+
return { passed, reason };
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Default evaluation logic
|
|
632
819
|
const passed = expectedFailure ? !actualSuccess : !!actualSuccess;
|
|
633
820
|
let reason;
|
|
634
821
|
if (response.isError) {
|
|
@@ -685,6 +872,47 @@ function summarize(results) {
|
|
|
685
872
|
console.log(`Results written to: ${resultsPath}`);
|
|
686
873
|
}
|
|
687
874
|
|
|
875
|
+
function generateBenchmarkReport(results) {
|
|
876
|
+
const passedResults = results.filter(r => r.status === 'passed' && r.durationMs);
|
|
877
|
+
|
|
878
|
+
if (passedResults.length === 0) {
|
|
879
|
+
console.log('\nNo performance data available for benchmarking.');
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
const durations = passedResults.map(r => r.durationMs).sort((a, b) => a - b);
|
|
884
|
+
const sum = durations.reduce((a, b) => a + b, 0);
|
|
885
|
+
const avg = sum / durations.length;
|
|
886
|
+
const median = durations[Math.floor(durations.length / 2)];
|
|
887
|
+
const min = durations[0];
|
|
888
|
+
const max = durations[durations.length - 1];
|
|
889
|
+
const p95 = durations[Math.floor(durations.length * 0.95)];
|
|
890
|
+
const p99 = durations[Math.floor(durations.length * 0.99)];
|
|
891
|
+
|
|
892
|
+
console.log('\nPerformance Benchmark');
|
|
893
|
+
console.log('====================');
|
|
894
|
+
console.log(`Total operations: ${passedResults.length}`);
|
|
895
|
+
console.log(`Average: ${avg.toFixed(2)} ms`);
|
|
896
|
+
console.log(`Median: ${median.toFixed(2)} ms`);
|
|
897
|
+
console.log(`Min: ${min.toFixed(2)} ms`);
|
|
898
|
+
console.log(`Max: ${max.toFixed(2)} ms`);
|
|
899
|
+
console.log(`95th percentile: ${p95.toFixed(2)} ms`);
|
|
900
|
+
console.log(`99th percentile: ${p99.toFixed(2)} ms`);
|
|
901
|
+
|
|
902
|
+
// Group by tool
|
|
903
|
+
const byTool = {};
|
|
904
|
+
passedResults.forEach(r => {
|
|
905
|
+
if (!byTool[r.toolName]) byTool[r.toolName] = [];
|
|
906
|
+
byTool[r.toolName].push(r.durationMs);
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
console.log('\nBy Tool:');
|
|
910
|
+
Object.entries(byTool).forEach(([tool, times]) => {
|
|
911
|
+
const toolAvg = times.reduce((a, b) => a + b, 0) / times.length;
|
|
912
|
+
console.log(` ${tool}: ${toolAvg.toFixed(2)} ms avg (${times.length} ops)`);
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
|
|
688
916
|
function normalizeWindowsPath(value) {
|
|
689
917
|
if (typeof value !== 'string') return value;
|
|
690
918
|
return value.replace(/\\+/g, '\\').replace(/\/+/g, '\\');
|