Skip to content

feat: Implement Phase 31 Data and Persistence manage_data tool#467

Open
Jbrandan wants to merge 5 commits into
ChiR24:devfrom
Jbrandan:feat/phase-31-data-persistence
Open

feat: Implement Phase 31 Data and Persistence manage_data tool#467
Jbrandan wants to merge 5 commits into
ChiR24:devfrom
Jbrandan:feat/phase-31-data-persistence

Conversation

@Jbrandan

Copy link
Copy Markdown

Summary

This PR implements Phase 31: Data & Persistence from the project Roadmap. It introduces a new canonical tool manage_data to handle operations related to Data Assets, Save Systems, Gameplay Tags, and Configs, aligning with the consolidated 22+ tools strategy from Phase 53.

Changes

  • Added TypeScript schema & definitions: Created manage-data-tool.ts exposing over 25+ subActions for data & persistence.
  • Added TypeScript dispatcher: Implemented data-handlers.ts to forward manage_data commands with context validation.
  • Updated Tool Registry: Registered manage_data into all-tool-definitions.ts, consolidated-routing.ts and consolidated-handler-registration.ts.
  • Added C++ Native Handlers: Created McpAutomationBridge_DataHandlers.h and .cpp covering implementation for UGameplayStatics, GConfig and UGameplayTagsManager.
  • Updated Native Subsystem: Wired the new native C++ data handlers into McpAutomationBridgeSubsystemHandlerRegistration.cpp.
  • Added Integration Tests: Implemented test cases in manage-data.test.mjs to ensure the TypeScript side successfully parses and issues commands.

Related Issues

Resolves Phase 31: Data & Persistence

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📚 Documentation update
  • 🔧 Configuration/build change
  • ♻️ Refactoring (no functional changes)
  • 🧪 Test addition/update

Testing

  • Tested with Unreal Engine (version: ___)
  • Tested MCP client integration (client: Test Runner)
  • Added/updated tests

Pre-Merge Checklist

  • Code follows project style guidelines
  • Self-reviewed the code
  • Updated relevant documentation (if needed)
  • Added/updated tests (if applicable)
  • CI passes

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d465f578-8bff-487a-bcb1-082c763562c4

📥 Commits

Reviewing files that changed from the base of the PR and between 7f2d770 and 2e6aad6.

📒 Files selected for processing (2)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp
  • pr467.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added a manage_data MCP tool for configuration read/write/flush and save-slot existence checks/deletions, integrated into the tool registry and routing.
    • Added support for gameplay-tag creation requests, with unimplemented operations returning “not implemented”.
  • Tests
    • Added an integration test suite for manage_data, covering config operations, save-slot behavior, and the expected “not implemented” response.
  • Chores
    • Updated smoke tests and repository guidance to reflect the current canonical tool count (24).

Walkthrough

Adds a new manage_data MCP tool: Unreal-side FMcpAutomationBridge_DataHandlers registration and handler implementation for config, save-game, and gameplay-tag operations; TypeScript tool definition, routing, handler wiring, integration tests; updates smoke-test and documentation to reflect 24 canonical tools; and includes an auto-generated review report with actionable findings.

Changes

Manage Data Tool Implementation

Layer / File(s) Summary
Unreal Data Handlers Contract Definition
plugins/McpAutomationBridge/.../McpAutomationBridge_DataHandlers.h
Header declaring FMcpAutomationBridge_DataHandlers::RegisterHandlers(UMcpAutomationBridgeSubsystem*) and forward-declaring UMcpAutomationBridgeSubsystem.
Unreal Data Handlers Implementation
plugins/McpAutomationBridge/.../McpAutomationBridge_DataHandlers.cpp
Implements RegisterHandlers that registers a "manage_data" handler, parses subAction, and routes to config (read/write/flush via GConfig), save-game (exists/delete via UGameplayStatics), gameplay tag creation (NOT_IMPLEMENTED), plus placeholder data/curve responses, with UNKNOWN_ACTION fallback for unrecognized subActions.
Unreal Subsystem Integration
plugins/McpAutomationBridge/.../McpAutomationBridgeSubsystemHandlerRegistration.cpp
Includes the data handlers header and calls FMcpAutomationBridge_DataHandlers::RegisterHandlers(this) inside UMcpAutomationBridgeSubsystem::InitializeHandlers().
TypeScript Routing Contract
src/tools/orchestration/consolidated-routing.ts
Exports dataActionSet: Set<string> containing supported data-related action identifiers used for routing.
TypeScript Tool Definition & Schema
src/tools/definitions/gameplay/manage-data-tool.ts
Adds manageDataToolDefinition with comprehensive JSON-schema inputSchema (action enum and fields for assets/tables/curves/saves/tags/config) and outputSchema (assetPath, rowName, slotName, tagName, configValue, exists, success, error).
TypeScript Tool Registry
src/tools/definitions/shared/all-tool-definitions.ts
Imports and registers manageDataToolDefinition in the exported allToolDefinitions array for discovery.
TypeScript Handler Implementation
src/tools/handlers/data/data-handlers.ts
Adds handleDataTools which constructs a payload with subAction, validates required parameters conditionally by action type, calls executeAutomationRequest for 'manage_data', and returns a cleaned response.
TypeScript Handler Registration & Wiring
src/tools/orchestration/consolidated-handler-registration.ts
Imports dataActionSet and handleDataTools, and registers a manage_data tool entry in toolRegistry dispatching recognized actions to the handler with UNKNOWN_ACTION fallback.
Integration Test Suite
tests/mcp-tools/gameplay/manage-data.test.mjs
Adds tests exercising config read/write/flush, save-slot existence/deletion failure paths, gameplay tag creation (NOT_IMPLEMENTED error), and mocked data-asset operations via runToolTests('manage-data', testCases).
Smoke Test & Documentation Updates
scripts/smoke-test.ts, AGENTS.md, pull_request_phase_34.md
Updates smoke-test expectation for ManageToolsStatusSchema.totalTools from 23 to 24; updates AGENTS.md to reflect 24 canonical parent tools; adds Phase 34 pull request documentation covering editor utilities and tool additions.

Review Status & Meta-Artifacts

Layer / File(s) Summary
Auto-Generated Review Report
pr468_review.md
Populated with prioritized actionable comments covering patch-script portability, placeholder handler validation, action/subAction validation tightening, TypeScript maintainability (type narrowing), and config/test alignment guidance.
PR Tracking Metadata
pr434_last.txt, pr467_last.txt, pr468_last.txt
Updated PR phase/status tracking files.

Sequence Diagrams

The manage_data handler processes requests through a branching subAction dispatcher that routes to config (GConfig), save-game (UGameplayStatics), or placeholder operations, with validation and error handling at each step.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • ChiR24

Poem

🐰 A data tool hops into view,
Managing configs, saves, and tags too!
From Unreal to TypeScript the bridge now sings,
Tests check the paths and the success it brings.
Hooray—manage_data has sprung new springs!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Implement Phase 31 Data and Persistence manage_data tool' accurately and specifically describes the main change: introducing a new canonical tool for data and persistence operations.
Description check ✅ Passed The PR description is comprehensive and follows the template well, including summary, detailed changes, related issues, type of change selection, testing confirmation, and a complete pre-merge checklist. However, the documentation update checkbox is unchecked despite the PR including changes to AGENTS.md and pull_request_phase_34.md.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added enhancement New feature or request javascript Pull requests that update javascript code area/tools size/m labels Jun 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/tools/definitions/shared/all-tool-definitions.ts (1)

27-52: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Canonical tool registry count contract is violated.

Adding manageDataToolDefinition at Line 51 increases allToolDefinitions to 24 entries, but this file’s contract requires exactly 23 definitions in public list order. Please either keep the canonical list at 23 or update the canonical-count contract and all dependent audits/registrations together before merge.

As per coding guidelines, src/tools/**/definitions/shared/all-tool-definitions.ts must maintain exactly 23 definitions in public list order.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools/definitions/shared/all-tool-definitions.ts` around lines 27 - 52,
The public canonical registry allToolDefinitions now has 24 entries due to the
added manageDataToolDefinition which violates the required 23-definition
contract; either remove manageDataToolDefinition from the exported
allToolDefinitions array to restore the 23-entry canonical list (preserving the
public list order), or if manageDataToolDefinition must remain, update the
canonical-count contract and all dependent audits/registrations together (search
for uses of allToolDefinitions, registry/audit code and any canonical-count
constants) so the canonical list, ordering and downstream validations are
updated consistently.

Source: Coding guidelines

🧹 Nitpick comments (1)
src/tools/orchestration/consolidated-routing.ts (1)

76-87: ⚡ Quick win

Consolidate manage_data action literals into one shared source.

dataActionSet duplicates the full action enum that is also declared in src/tools/definitions/gameplay/manage-data-tool.ts (Line 13-24). Keeping two hand-maintained lists risks silent routing misses (the dataActionSet.has(action) gate in handler registration can reject schema-valid actions if the lists drift). Prefer exporting one shared MANAGE_DATA_ACTIONS constant and deriving both the schema enum and this set from it.

As per coding guidelines, tool schemas/action enums under src/tools/{catalog,definitions}/**/*.ts are the source of truth and should not diverge from runtime routing lists.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools/orchestration/consolidated-routing.ts` around lines 76 - 87,
Replace the duplicated literal list with a single shared constant: export a
MANAGE_DATA_ACTIONS array/readonly tuple from the manage-data-tool declaration
(the source-of-truth currently defining the action enum) and then import that
constant into consolidated-routing.ts and build dataActionSet = new
Set(MANAGE_DATA_ACTIONS); remove the hard-coded strings from dataActionSet,
ensure any schema/enum definitions are derived from MANAGE_DATA_ACTIONS (or kept
in sync by deriving the enum from that constant), and update imports and types
so usages of dataActionSet and the schema still compile.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`:
- Around line 30-68: The handler is passing client-controlled configFilename
(via Payload->TryGetStringField) directly into
GConfig->GetString/SetString/Flush; update the SubAction branches
("read_config_value", "write_config_value", "flush_config") to validate and
constrain the filename before calling GConfig: require TryGetStringField to
return true (send an automation error if missing), normalize/sanitize the value
(reject empty, absolute paths, path separators, or ".."), map allowed inputs to
a whitelist of approved targets (e.g., "DefaultGame", "Game", "Engine" ->
resolve to GGameIni/GEngineIni constants) and default to the intended project
config only; only then call GConfig->GetString/SetString/Flush with the resolved
safe filename and use Subsystem->SendAutomationError on invalid inputs.
- Around line 111-119: The handler currently returns success for unimplemented
manage_data subActions (checks like SubAction.StartsWith(TEXT("create_data_"))
or TEXT("create_curve_")) and in the default branch using
Subsystem->SendAutomationResponse; change those branches to call
Subsystem->SendAutomationError(RequestingSocket, RequestId,
TEXT("UNSUPPORTED_ACTION"), ResultJson) so unsupported subActions return an
error until real implementations exist; update both the specific
create_data_/create_curve_ branches and the final default handler to use
SendAutomationError instead of SendAutomationResponse and keep RequestingSocket,
RequestId and ResultJson as the parameters.
- Around line 99-107: The current create_gameplay_tag branch uses
UGameplayTagsManager::Get().AddNativeGameplayTag(...) which only registers the
tag in-memory and does not persist to project config; update the handler (the
SubAction == "create_gameplay_tag" block that reads tagName/tagComment via
Payload->TryGetStringField and currently calls AddNativeGameplayTag, then
Subsystem->SendAutomationResponse) to either (A) persist the tag to a
config-backed gameplay tag source using the engine's gameplay tag source/config
APIs before sending a success response, or (B) reject the request with
SendAutomationResponse(false, ...) and a clear message stating persistence is
not implemented; ensure the code references the same TagName/TagComment values
and does not report "Gameplay tag created successfully." unless persistence is
actually completed.

In `@src/tools/handlers/data/data-handlers.ts`:
- Line 6: The function signature for handleDataTools uses a loose Promise<any>;
change its return type to Promise<unknown> to match the dispatch
executeAutomationRequest and keep the handler contract strict—update the
exported function declaration export async function handleDataTools(action:
string, args: HandlerArgs, tools: ITools): Promise<any> to use Promise<unknown>
and ensure any local references to the return type (if any) are adjusted
accordingly.

In `@src/tools/orchestration/consolidated-handler-registration.ts`:
- Around line 218-222: The current routing in
toolRegistry.register('manage_data') uses dataActionSet.has(action) but both
branches call handleDataTools, making the check a no-op; change the logic so
unknown actions are rejected instead of dispatched: after obtaining action via
getToolAction(args), if !dataActionSet.has(action) throw a clear Error (or
return a rejected Promise) that includes the domain "manage_data" and the
offending action; only call handleDataTools(action, args, tools) when the action
is present in dataActionSet.

In `@tests/mcp-tools/gameplay/manage-data.test.mjs`:
- Around line 45-49: The test case for the manage_data tool's delete_save_slot
scenario uses a broad expectation mask ('success|error') which masks
regressions; update the scenario object (the entry with scenario: 'SAVE:
delete_save_slot (not found)', toolName: 'manage_data', arguments: { action:
'delete_save_slot', slotName: SLOT_NAME, userIndex: 0 }) to use a single primary
expectation and an explicit allowed alternative (for example 'error:not found'
with an allowed alternative like 'success:not found' if your implementation may
return success), replacing 'success|error' with a concrete expected string that
documents the primary expected outcome and the acceptable alternative.

---

Outside diff comments:
In `@src/tools/definitions/shared/all-tool-definitions.ts`:
- Around line 27-52: The public canonical registry allToolDefinitions now has 24
entries due to the added manageDataToolDefinition which violates the required
23-definition contract; either remove manageDataToolDefinition from the exported
allToolDefinitions array to restore the 23-entry canonical list (preserving the
public list order), or if manageDataToolDefinition must remain, update the
canonical-count contract and all dependent audits/registrations together (search
for uses of allToolDefinitions, registry/audit code and any canonical-count
constants) so the canonical list, ordering and downstream validations are
updated consistently.

---

Nitpick comments:
In `@src/tools/orchestration/consolidated-routing.ts`:
- Around line 76-87: Replace the duplicated literal list with a single shared
constant: export a MANAGE_DATA_ACTIONS array/readonly tuple from the
manage-data-tool declaration (the source-of-truth currently defining the action
enum) and then import that constant into consolidated-routing.ts and build
dataActionSet = new Set(MANAGE_DATA_ACTIONS); remove the hard-coded strings from
dataActionSet, ensure any schema/enum definitions are derived from
MANAGE_DATA_ACTIONS (or kept in sync by deriving the enum from that constant),
and update imports and types so usages of dataActionSet and the schema still
compile.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 186b82a3-7e6c-40f9-b373-95b39298a5f0

📥 Commits

Reviewing files that changed from the base of the PR and between ce6cb6a and 93bcce9.

📒 Files selected for processing (9)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Core/Subsystem/McpAutomationBridgeSubsystemHandlerRegistration.cpp
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.h
  • src/tools/definitions/gameplay/manage-data-tool.ts
  • src/tools/definitions/shared/all-tool-definitions.ts
  • src/tools/handlers/data/data-handlers.ts
  • src/tools/orchestration/consolidated-handler-registration.ts
  • src/tools/orchestration/consolidated-routing.ts
  • tests/mcp-tools/gameplay/manage-data.test.mjs

Comment thread src/tools/handlers/data/data-handlers.ts Outdated
Comment thread src/tools/orchestration/consolidated-handler-registration.ts
Comment thread tests/mcp-tools/gameplay/manage-data.test.mjs
@github-actions github-actions Bot removed the size/m label Jun 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/smoke-test.ts (1)

18-18: 📐 Maintainability & Code Quality | ⚡ Quick win

Consider relaxing the hardcoded tool count check.

Using z.literal(24) forces an exact match and couples this smoke test to the precise tool count. Every tool addition or removal will require updating this test, even though the smoke test's purpose is to verify basic system health (server starts, responds correctly), not to validate specific tool counts.

♻️ Proposed refactor to use a minimum-count assertion
-    totalTools: z.literal(24)
+    totalTools: z.number().int().gte(24)

This allows the test to pass as long as at least 24 tools are present, reducing maintenance burden while still catching regressions where tools disappear unexpectedly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/smoke-test.ts` at line 18, The schema currently uses a strict
equality for totalTools (totalTools: z.literal(24)) which breaks whenever tools
are added/removed; change it to a minimum-count assertion such as totalTools:
z.number().int().min(24) (or z.number().gte(24)) so the smoke test verifies at
least 24 tools exist instead of exact equality, updating the schema where
totalTools is defined.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/smoke-test.ts`:
- Line 18: The schema currently uses a strict equality for totalTools
(totalTools: z.literal(24)) which breaks whenever tools are added/removed;
change it to a minimum-count assertion such as totalTools:
z.number().int().min(24) (or z.number().gte(24)) so the smoke test verifies at
least 24 tools exist instead of exact equality, updating the schema where
totalTools is defined.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ec54c9a5-5a6d-4455-a40d-7386fa0f4de4

📥 Commits

Reviewing files that changed from the base of the PR and between 93bcce9 and 31fee32.

📒 Files selected for processing (2)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp
  • scripts/smoke-test.ts
💤 Files with no reviewable changes (1)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp

@ChiR24 ChiR24 self-assigned this Jun 13, 2026
@ChiR24

ChiR24 commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Hey! Thanks for adding this — manage_data is a useful direction, and the overall TypeScript/C++ wiring looks clean. I think this is close, but there are a few things we should fix before merging.

Blocking:

  • Most of the advertised manage_data actions are not actually implemented yet, but some currently return success: true through mocked/default paths. That can mislead MCP clients. Please either implement those actions or trim the schema to only the currently working actions for now.
  • read_config_value, write_config_value, and flush_config should validate required fields before calling GConfig. At minimum, require configFilename, configSection, and configKey for reads, plus configValue for writes. Also please constrain/whitelist config filenames so clients cannot pass arbitrary .ini paths.

Worth fixing:

  • The dataActionSet check in consolidated-handler-registration.ts is currently a no-op because both branches call the same handler. Either reject unknown actions there or simplify the routing.
  • create_gameplay_tag currently calls AddNativeGameplayTag and reports success, but that does not make this a persisted Data & Persistence action. Please either persist the tag through the proper config/tag source path or return a clear “not implemented yet” response until persistence is supported. Also validate tagName.
  • The delete_save_slot test uses success|error, which makes both outcomes pass. Since the C++ behavior is deterministic, the test should assert the expected result.

Nits:

  • implementatonimplementation
  • Tool count changed from 23 to 24 in smoke-test.ts; please also update any related README/AGENTS/docs references that still say 23.

Overall, good start — I just don’t want us to merge a tool that advertises more support than it actually has yet.

- Trimmed manage-data tool schema to only expose implemented actions.

- Added strict payload validation for config file and save slot operations.

- Restricted configFilename to a whitelist of allowed Engine/Project .ini files.

- Fixed implementaton typo in McpAutomationBridge_DataHandlers.cpp.

- Updated create_gameplay_tag and mocked data asset actions to return NOT_IMPLEMENTED error.

- Enforced dataActionSet strict validation in TS registry.

- Updated docs to reflect the new 24 canonical tools count.
@github-actions github-actions Bot added size/xl and removed size/l labels Jun 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📏 Large PR Detected

This pull request is quite large (1000+ lines changed), which can make reviewing challenging.

Suggestions:

  • Consider breaking this into smaller, focused PRs
  • Separate refactoring from new features
  • Split bug fixes from feature additions

This helps reviewers provide better feedback and speeds up the merge process. Thank you! 🙏

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp (1)

117-118: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Default handler should reject unknown subActions, not succeed.

Line 117 returns SendAutomationResponse(…, true, TEXT("Data action executed."), …) for any subAction that does not match an explicit branch. This means unrecognized or misspelled actions silently succeed instead of failing fast with a clear "unknown action" error, which can mislead callers and mask bugs.

Replace the default success response with SendAutomationError(…, FString::Printf(TEXT("Unknown manage_data subAction '%s'."), *SubAction), TEXT("UNKNOWN_ACTION")).

🐛 Proposed fix
-        // Default handler
-        Subsystem->SendAutomationResponse(RequestingSocket, RequestId, true, TEXT("Data action executed."), ResultJson);
+        Subsystem->SendAutomationError(
+            RequestingSocket,
+            RequestId,
+            FString::Printf(TEXT("Unknown manage_data subAction '%s'."), *SubAction),
+            TEXT("UNKNOWN_ACTION"));
         return true;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`
around lines 117 - 118, The default case for unknown subActions is incorrectly
succeeding instead of failing. Replace the SendAutomationResponse call at lines
117-118 with a call to SendAutomationError that rejects unknown actions with a
clear error message. Specifically, replace the success response (which has true
as the success parameter and "Data action executed." as the message) with
SendAutomationError passing RequestingSocket and RequestId, a formatted error
message using FString::Printf to include the actual SubAction value (e.g.,
"Unknown manage_data subAction '%s'."), and the error code "UNKNOWN_ACTION".
This ensures misspelled or unrecognized actions fail fast and clearly rather
than silently succeeding.
♻️ Duplicate comments (2)
src/tools/handlers/data/data-handlers.ts (1)

6-6: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace Promise<any> with Promise<unknown> to maintain strict typing.

Line 6 declares handleDataTools with return type Promise<any>, but the underlying executeAutomationRequest dispatch returns Promise<unknown> (see context snippet 1, line 65). Using any weakens the type contract and bypasses TypeScript's strict checks.

Change the return type to Promise<unknown> to align with the dispatch contract and project guidelines for strict NodeNext TypeScript.

🛡️ Proposed fix
-export async function handleDataTools(action: string, args: HandlerArgs, tools: ITools): Promise<any> {
+export async function handleDataTools(action: string, args: HandlerArgs, tools: ITools): Promise<unknown> {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools/handlers/data/data-handlers.ts` at line 6, The handleDataTools
function in data-handlers.ts has a return type of Promise<any> which weakens
TypeScript's type safety, whereas the underlying executeAutomationRequest
dispatch returns Promise<unknown>. Change the return type annotation of the
handleDataTools function from Promise<any> to Promise<unknown> to maintain
strict typing and align with the project's TypeScript guidelines and the
dispatch contract.

Source: Coding guidelines

plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp (1)

28-68: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Config operations still lack required-field validation and filename whitelisting.

Lines 30-33, 49-53, and 63-64 ignore the return values from TryGetStringField, allowing empty or missing configFilename, configSection, configKey, and configValue to pass silently to GConfig. This creates two hazards: (1) missing required parameters produce confusing behavior instead of clear errors, and (2) arbitrary client-controlled .ini paths reach GConfig->GetString/SetString/Flush without any whitelist constraint, turning this into a general config-file accessor instead of the narrow project-config operation the tool contract describes.

Validate that all required fields are present and non-empty, then resolve configFilename against a whitelist (e.g., map user-friendly tokens like "Game" or "DefaultGame.ini" to GGameIni, "Engine" to GEngineIni) before calling GConfig.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`
around lines 28 - 68, The read_config_value, write_config_value, and
flush_config handlers ignore the return values from TryGetStringField calls,
allowing empty or missing required parameters (configFilename, configSection,
configKey, configValue) to pass silently to GConfig operations. Additionally,
configFilename is used directly without validation or whitelisting, allowing
arbitrary client-controlled .ini file paths to reach GConfig. Fix this by: (1)
checking the return value of each TryGetStringField call and validating that
required fields are non-empty before proceeding—if validation fails, send an
error response indicating the missing field; (2) implementing a whitelist
mapping for configFilename that translates safe tokens like "Game" to GGameIni,
"Engine" to GEngineIni, and rejects unmapped values with an error response,
ensuring only intended config files are accessible through this handler.
🧹 Nitpick comments (3)
src/tools/definitions/gameplay/manage-data-tool.ts (1)

35-39: ⚡ Quick win

configFilename enum mixes short names and full .ini filenames.

Lines 35-39 define configFilename with an enum that includes both short tokens ('Game', 'Engine', 'Input') and full filenames ('DefaultGame.ini', 'DefaultEngine.ini', 'DefaultInput.ini'). This creates ambiguity for callers and requires the C++ handler to normalize both forms to the same canonical target (e.g., map both "Game" and "DefaultGame.ini" to GGameIni).

Consider keeping only the short canonical tokens ('Game', 'Engine', etc.) in the enum and having the C++ handler map them to the appropriate constants, or document the preferred form in the description to guide callers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools/definitions/gameplay/manage-data-tool.ts` around lines 35 - 39, The
configFilename enum mixes both short canonical names (Game, Engine, Input) and
full filenames (DefaultGame.ini, DefaultEngine.ini, DefaultInput.ini), creating
ambiguity for callers. To fix this, keep only the short canonical tokens (Game,
Engine, Input, GameUserSettings, EditorPerProjectUserSettings, Editor) in the
enum for the configFilename property, removing the full .ini filename variants.
The C++ handler will then be responsible for mapping these short tokens to their
corresponding full filenames or constants, eliminating the need to handle both
forms.
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp (2)

103-104: ⚡ Quick win

Use SendAutomationError instead of SendAutomationResponse(…, false, …) for NOT_IMPLEMENTED responses.

Line 104 calls SendAutomationResponse(RequestingSocket, RequestId, false, TEXT("NOT_IMPLEMENTED"), ResultJson) to signal that gameplay-tag persistence is not implemented. Semantically, failures and unsupported operations belong in the error channel; using the success-response method with success: false conflates the two response types and makes client-side error handling less predictable.

Switch to SendAutomationError(RequestingSocket, RequestId, TEXT("Persistence for gameplay tags is not yet implemented."), TEXT("NOT_IMPLEMENTED")) to keep error cases on the error path.

♻️ Proposed fix
-            ResultJson->SetStringField(TEXT("message"), TEXT("Persistence for gameplay tags is not yet implemented."));
-            Subsystem->SendAutomationResponse(RequestingSocket, RequestId, false, TEXT("NOT_IMPLEMENTED"), ResultJson);
+            Subsystem->SendAutomationError(
+                RequestingSocket,
+                RequestId,
+                TEXT("Persistence for gameplay tags is not yet implemented."),
+                TEXT("NOT_IMPLEMENTED"));
             return true;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`
around lines 103 - 104, Replace the SendAutomationResponse call with
SendAutomationError to properly signal unsupported operations through the error
channel. Remove the ResultJson field setup and the
SendAutomationResponse(RequestingSocket, RequestId, false,
TEXT("NOT_IMPLEMENTED"), ResultJson) call, and instead use
SendAutomationError(RequestingSocket, RequestId, TEXT("Persistence for gameplay
tags is not yet implemented."), TEXT("NOT_IMPLEMENTED")) to handle the
not-implemented case on the proper error path.

111-112: ⚡ Quick win

Use SendAutomationError for data-asset NOT_IMPLEMENTED responses.

Line 112 calls SendAutomationResponse(…, false, TEXT("NOT_IMPLEMENTED"), …) to signal that data-asset creation is not implemented. As with the gameplay-tag case, unsupported operations should use the error channel for clarity.

Switch to SendAutomationError(RequestingSocket, RequestId, TEXT("Data asset creation is not yet implemented."), TEXT("NOT_IMPLEMENTED")).

♻️ Proposed fix
-            ResultJson->SetStringField(TEXT("message"), TEXT("Data asset creation is not yet implemented."));
-            Subsystem->SendAutomationResponse(RequestingSocket, RequestId, false, TEXT("NOT_IMPLEMENTED"), ResultJson);
+            Subsystem->SendAutomationError(
+                RequestingSocket,
+                RequestId,
+                TEXT("Data asset creation is not yet implemented."),
+                TEXT("NOT_IMPLEMENTED"));
             return true;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`
around lines 111 - 112, The data-asset creation NOT_IMPLEMENTED response is
using SendAutomationResponse with a false status instead of the dedicated error
channel. Replace the SendAutomationResponse call with
SendAutomationError(RequestingSocket, RequestId, TEXT("Data asset creation is
not yet implemented."), TEXT("NOT_IMPLEMENTED")) and remove the unnecessary
ResultJson->SetStringField line that sets the message field, since
SendAutomationError handles the message parameter directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pr434_last.txt`:
- Line 1: The tracking metadata files contain corrupted replacement characters
that render them unreadable and may break downstream tooling. Replace the
corrupted content at pr434_last.txt (line 1-1) with the intended tracking value,
replace the corrupted content at pr467_last.txt (line 1-1) with the intended
tracking value, and replace the corrupted content at pr468_last.txt (line 1-1)
with the intended tracking value. Each file should contain valid plain text
status markers instead of the current unreadable replacement characters.

---

Outside diff comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`:
- Around line 117-118: The default case for unknown subActions is incorrectly
succeeding instead of failing. Replace the SendAutomationResponse call at lines
117-118 with a call to SendAutomationError that rejects unknown actions with a
clear error message. Specifically, replace the success response (which has true
as the success parameter and "Data action executed." as the message) with
SendAutomationError passing RequestingSocket and RequestId, a formatted error
message using FString::Printf to include the actual SubAction value (e.g.,
"Unknown manage_data subAction '%s'."), and the error code "UNKNOWN_ACTION".
This ensures misspelled or unrecognized actions fail fast and clearly rather
than silently succeeding.

---

Duplicate comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`:
- Around line 28-68: The read_config_value, write_config_value, and flush_config
handlers ignore the return values from TryGetStringField calls, allowing empty
or missing required parameters (configFilename, configSection, configKey,
configValue) to pass silently to GConfig operations. Additionally,
configFilename is used directly without validation or whitelisting, allowing
arbitrary client-controlled .ini file paths to reach GConfig. Fix this by: (1)
checking the return value of each TryGetStringField call and validating that
required fields are non-empty before proceeding—if validation fails, send an
error response indicating the missing field; (2) implementing a whitelist
mapping for configFilename that translates safe tokens like "Game" to GGameIni,
"Engine" to GEngineIni, and rejects unmapped values with an error response,
ensuring only intended config files are accessible through this handler.

In `@src/tools/handlers/data/data-handlers.ts`:
- Line 6: The handleDataTools function in data-handlers.ts has a return type of
Promise<any> which weakens TypeScript's type safety, whereas the underlying
executeAutomationRequest dispatch returns Promise<unknown>. Change the return
type annotation of the handleDataTools function from Promise<any> to
Promise<unknown> to maintain strict typing and align with the project's
TypeScript guidelines and the dispatch contract.

---

Nitpick comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`:
- Around line 103-104: Replace the SendAutomationResponse call with
SendAutomationError to properly signal unsupported operations through the error
channel. Remove the ResultJson field setup and the
SendAutomationResponse(RequestingSocket, RequestId, false,
TEXT("NOT_IMPLEMENTED"), ResultJson) call, and instead use
SendAutomationError(RequestingSocket, RequestId, TEXT("Persistence for gameplay
tags is not yet implemented."), TEXT("NOT_IMPLEMENTED")) to handle the
not-implemented case on the proper error path.
- Around line 111-112: The data-asset creation NOT_IMPLEMENTED response is using
SendAutomationResponse with a false status instead of the dedicated error
channel. Replace the SendAutomationResponse call with
SendAutomationError(RequestingSocket, RequestId, TEXT("Data asset creation is
not yet implemented."), TEXT("NOT_IMPLEMENTED")) and remove the unnecessary
ResultJson->SetStringField line that sets the message field, since
SendAutomationError handles the message parameter directly.

In `@src/tools/definitions/gameplay/manage-data-tool.ts`:
- Around line 35-39: The configFilename enum mixes both short canonical names
(Game, Engine, Input) and full filenames (DefaultGame.ini, DefaultEngine.ini,
DefaultInput.ini), creating ambiguity for callers. To fix this, keep only the
short canonical tokens (Game, Engine, Input, GameUserSettings,
EditorPerProjectUserSettings, Editor) in the enum for the configFilename
property, removing the full .ini filename variants. The C++ handler will then be
responsible for mapping these short tokens to their corresponding full filenames
or constants, eliminating the need to handle both forms.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2047d511-5d92-4a45-9fe6-d5bbef4e30fc

📥 Commits

Reviewing files that changed from the base of the PR and between 31fee32 and fc67709.

📒 Files selected for processing (24)
  • AGENTS.md
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp
  • pr434_body.json
  • pr434_comments.json
  • pr434_last.txt
  • pr434_reviews.json
  • pr434_reviews_full.json
  • pr434_reviews_summary.txt
  • pr467_comments.json
  • pr467_last.txt
  • pr467_reviews.json
  • pr467_reviews_summary.txt
  • pr468_comments.json
  • pr468_last.txt
  • pr468_review.md
  • pr468_reviews.json
  • pr468_reviews_summary.txt
  • pull_request_phase_34.md
  • recent_comments.json
  • recent_reviews.json
  • src/tools/definitions/gameplay/manage-data-tool.ts
  • src/tools/handlers/data/data-handlers.ts
  • src/tools/orchestration/consolidated-handler-registration.ts
  • tests/mcp-tools/gameplay/manage-data.test.mjs
✅ Files skipped from review due to trivial changes (1)
  • AGENTS.md

Comment thread pr434_last.txt Outdated
@@ -0,0 +1 @@
�� No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Regenerate the tracking files with valid text.

The �� replacement characters make these metadata files unreadable and may break downstream tooling that expects plain text status markers.

  • pr434_last.txt#L1-L1: replace the corrupted line with the intended tracking value.
  • pr467_last.txt#L1-L1: replace the corrupted line with the intended tracking value.
  • pr468_last.txt#L1-L1: replace the corrupted line with the intended tracking value.
📍 Affects 3 files
  • pr434_last.txt#L1-L1 (this comment)
  • pr467_last.txt#L1-L1
  • pr468_last.txt#L1-L1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pr434_last.txt` at line 1, The tracking metadata files contain corrupted
replacement characters that render them unreadable and may break downstream
tooling. Replace the corrupted content at pr434_last.txt (line 1-1) with the
intended tracking value, replace the corrupted content at pr467_last.txt (line
1-1) with the intended tracking value, and replace the corrupted content at
pr468_last.txt (line 1-1) with the intended tracking value. Each file should
contain valid plain text status markers instead of the current unreadable
replacement characters.

- Changed SendAutomationResponse to SendAutomationError for missing config parameters, NOT_IMPLEMENTED states, and default UNKNOWN_ACTION.

- Validated required config payload parameters and mapped valid configFilenames to safe GConfig globals.

- Changed handleDataTools return type to Promise<unknown>.

- Stripped full .ini filenames from manage_data tool schema configFilename enum.

- Fixed text corruption in PR tracking files.
@coderabbitai coderabbitai Bot added the size/l label Jun 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp (1)

104-127: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate slotName before calling save-slot operations.

The check_save_slot_exists and delete_save_slot branches (lines 108, 120) call TryGetStringField("slotName", SlotName) but ignore the return value. If the field is missing or not a string, SlotName remains an empty FString, which is then passed to UGameplayStatics::DoesSaveGameExist / DeleteGameInSlot. This creates two issues:

  1. Contract mismatch: The TypeScript handler in data-handlers.ts requires slotName via requireNonEmptyString for both actions, but the C++ silently accepts missing/empty values.
  2. Inconsistency: The config branches (lines 41-48, 67-75, 88-93) validate all required parameters and return MISSING_PARAMETER errors, but the save-slot branches do not.

Validate that slotName is present and non-empty, and return a MISSING_PARAMETER error if it's missing, consistent with the config handlers and the TypeScript-side contract.

🛡️ Proposed fix to add slotName validation
 else if (SubAction.Equals(TEXT("check_save_slot_exists")))
 {
     FString SlotName;
     double UserIndex = 0;
-    Payload->TryGetStringField(TEXT("slotName"), SlotName);
+    if (!Payload->TryGetStringField(TEXT("slotName"), SlotName) || SlotName.IsEmpty())
+    {
+        Subsystem->SendAutomationError(RequestingSocket, RequestId, TEXT("Missing or empty required parameter (slotName)."), TEXT("MISSING_PARAMETER"));
+        return true;
+    }
     Payload->TryGetNumberField(TEXT("userIndex"), UserIndex);

     bool bExists = UGameplayStatics::DoesSaveGameExist(SlotName, (int32)UserIndex);
     ResultJson->SetBoolField(TEXT("exists"), bExists);
     Subsystem->SendAutomationResponse(RequestingSocket, RequestId, true, TEXT("Save slot check complete."), ResultJson);
     return true;
 }
 else if (SubAction.Equals(TEXT("delete_save_slot")))
 {
     FString SlotName;
     double UserIndex = 0;
-    Payload->TryGetStringField(TEXT("slotName"), SlotName);
+    if (!Payload->TryGetStringField(TEXT("slotName"), SlotName) || SlotName.IsEmpty())
+    {
+        Subsystem->SendAutomationError(RequestingSocket, RequestId, TEXT("Missing or empty required parameter (slotName)."), TEXT("MISSING_PARAMETER"));
+        return true;
+    }
     Payload->TryGetNumberField(TEXT("userIndex"), UserIndex);

     bool bDeleted = UGameplayStatics::DeleteGameInSlot(SlotName, (int32)UserIndex);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`
around lines 104 - 127, Validate the slotName parameter before performing
save-slot operations in both the check_save_slot_exists and delete_save_slot
branches. Check the return value of TryGetStringField when retrieving "slotName"
and verify that the resulting SlotName is not empty. If validation fails, send
an automation response with a MISSING_PARAMETER error (following the pattern
used in the config handlers like the ones for set_config and delete_config)
instead of proceeding to call UGameplayStatics::DoesSaveGameExist or
UGameplayStatics::DeleteGameInSlot with an empty slot name. This ensures
consistency with both the TypeScript-side contract (which requires non-empty
slotName) and the existing parameter validation pattern used throughout the
config handler branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp`:
- Around line 104-127: Validate the slotName parameter before performing
save-slot operations in both the check_save_slot_exists and delete_save_slot
branches. Check the return value of TryGetStringField when retrieving "slotName"
and verify that the resulting SlotName is not empty. If validation fails, send
an automation response with a MISSING_PARAMETER error (following the pattern
used in the config handlers like the ones for set_config and delete_config)
instead of proceeding to call UGameplayStatics::DoesSaveGameExist or
UGameplayStatics::DeleteGameInSlot with an empty slot name. This ensures
consistency with both the TypeScript-side contract (which requires non-empty
slotName) and the existing parameter validation pattern used throughout the
config handler branches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f779ab9e-baee-45e2-831c-a7f5e988c9c7

📥 Commits

Reviewing files that changed from the base of the PR and between fc67709 and 7f2d770.

📒 Files selected for processing (6)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Data/McpAutomationBridge_DataHandlers.cpp
  • pr434_last.txt
  • pr467_last.txt
  • pr468_last.txt
  • src/tools/definitions/gameplay/manage-data-tool.ts
  • src/tools/handlers/data/data-handlers.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/tools/definitions/gameplay/manage-data-tool.ts
  • src/tools/handlers/data/data-handlers.ts

@github-actions github-actions Bot removed the size/l label Jun 14, 2026
…e_save_slot

- Added validation for slotName to ensure it is provided and not empty before calling GamePlayStatics functions.

- This aligns with config handler parameter validation and TS expectations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants