You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR adds a new Tool under the tools tab that applies all the core fixes which GenPatcher applies aswell.
Greptile Summary
This PR introduces a comprehensive ActionSet orchestration framework that ports GenPatcher functionality into GenHub as a new tool. The implementation adds 36+ automated fixes for Command & Conquer Generals/Zero Hour, including registry fixes, file system operations, DirectX/VC++ redistributable installers, and game configuration optimizations.
Key Changes:
Added IActionSet interface and BaseActionSet abstract class for extensible fix implementation
Implemented ActionSetOrchestrator to manage sequential fix application with crucial fix handling
Created GenPatcherTool plugin with UI (GenPatcherViewModel) for fix management
Added 36+ individual fixes covering registry patches, system compatibility, network optimization, and game configuration
Integrated IHttpClientFactory for downloading patches and redistributables (now properly registered in DI)
Centralized constants in ActionSetConstants, RegistryConstants, ExternalUrls, and GameSettingsConstants
Architecture Strengths:
Clean separation between core logic (GenHub.Core) and Windows-specific implementations
Proper dependency injection with all services registered
Parallel status checks prevent UI blocking
Admin privilege validation before applying registry-based fixes
Comprehensive logging with structured log codes for troubleshooting
Critical Issues Previously Addressed:
IHttpClientFactory registration added to WindowsServicesModule.cs:36
NahimicFix process checking logic corrected
Most path construction and error handling issues have been addressed in previous review rounds
Remaining Concerns:
Several fixes have logic issues documented in previous threads that should be verified as resolved
Documentation in docs/features/actionsets.md contains duplicate sections
Some fixes like RemoveReadOnlyFix have marker file logic inconsistencies
Path escaping vulnerabilities exist in PowerShell command execution
Build Status:
✓ No compiler warnings or errors detected
✓ All dependencies properly registered
✓ Follows conventional commit format in PR title
Confidence Score: 4/5
This PR is generally safe to merge with careful monitoring of reported issues
Score reflects clean build with zero warnings, proper architecture, and comprehensive functionality. However, multiple logic concerns from previous review threads remain documented (serial key handling, path construction issues, PowerShell escaping vulnerabilities, marker file inconsistencies). The core framework is solid but individual fixes need verification that previous feedback was addressed.
Pay close attention to EAAppRegistryFix.cs (serial key logic), OptionsINIFix.cs (resolution reporting), RemoveReadOnlyFix.cs (marker file logic), DirectXRuntimeFix.cs (argument assignment), and OneDriveFix.cs (folder merge handling)
…nd build errors
- Fix non-static Logger access in BaseVCRedistFix.IsProductInstalled
- Add missing System.IO namespace in VCRedist2005Fix
- Reduce cognitive complexity in DownloadSecurityValidator and BasePackageDeploymentFix
- Clean up unused variables and redundant exception rethrows
- Fix StyleCop SA1202 and SA1204 member ordering
- Use await using for SharpCompress archive entry streams
…ests
- Retain backups when rollback restoration encounters errors
- Do not delete backup files until marker persistence succeeds during undo
- Retain destination files and fail safely when a recorded backup is missing
- Add comprehensive unit tests covering transactional undo and missing backups
BasePackageDeploymentFix.ExtractArchiveEntriesAsync passes MaximumAddonPackageSizeBytes as both the per-entry limit and the remaining aggregate budget for every entry. Because that budget resets on each loop iteration, the intended 200 MB archive-wide limit is actually 200 MB per entry; an archive containing N entries can expand to N × 200 MB. Please track cumulative extracted bytes and pass MaximumAddonPackageSizeBytes - expandedBytes, as the existing Map/Replay extraction callers do, with a multi-entry aggregate-limit test.
The reason will be displayed to describe this comment to others. Learn more.
`Using` block can be simplified
The using statement defines a scope at the end of which an object will be disposed. The downside is that this increases the indentation level of your code. However, with C# 8.0, you can use the new using declaration that no longer requires you to explicitly mention the braces. Although this reduces your code's indentation and nesting, the downside of this approach, however, is that the resource's lifetime may increase.
The reason will be displayed to describe this comment to others. Learn more.
`Using` block can be simplified
The using statement defines a scope at the end of which an object will be disposed. The downside is that this increases the indentation level of your code. However, with C# 8.0, you can use the new using declaration that no longer requires you to explicitly mention the braces. Although this reduces your code's indentation and nesting, the downside of this approach, however, is that the resource's lifetime may increase.
The reason will be displayed to describe this comment to others. Learn more.
`Using` block can be simplified
The using statement defines a scope at the end of which an object will be disposed. The downside is that this increases the indentation level of your code. However, with C# 8.0, you can use the new using declaration that no longer requires you to explicitly mention the braces. Although this reduces your code's indentation and nesting, the downside of this approach, however, is that the resource's lifetime may increase.
The reason will be displayed to describe this comment to others. Learn more.
`Using` block can be simplified
The using statement defines a scope at the end of which an object will be disposed. The downside is that this increases the indentation level of your code. However, with C# 8.0, you can use the new using declaration that no longer requires you to explicitly mention the braces. Although this reduces your code's indentation and nesting, the downside of this approach, however, is that the resource's lifetime may increase.
The reason will be displayed to describe this comment to others. Learn more.
[SUGGESTION]: Migrated legacy global marker is never removed, so it resurrects stale records after every completed undo
The migration copies the global marker to the scoped marker, but nothing ever deletes or marks the global marker as consumed. Once UpdateMarkerAfterUndo deletes the scoped marker after a successful undo, the next GetMarkerPath call re-copies the stale global marker, recreating a deployment record for an already-undone installation. In the worst case, records whose backup files were consumed by the first undo now fail TryRestoreBackup (missing backup → record retained forever), so every subsequent undo reports a permanent partial failure until the fix is re-applied. Deleting the global marker after its first successful migration would also stop other installations from inheriting copies of records that point into a different installation's directories — those copies are rejected by the new containment checks and poison their scoped markers the same way.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
The reason will be displayed to describe this comment to others. Learn more.
[SUGGESTION]: Backup-directory emptiness probe can throw inside the exception and cancellation rollback paths
Directory.EnumerateFileSystemEntries(backupDir).Any() sits outside the per-entry try/catch and can throw IOException/UnauthorizedAccessException (ACL or antivirus lock on the backup dir, or the directory disappearing between the Directory.Exists check and the enumeration). RollbackDeployment runs inside ApplyInternalAsync's catch handlers, so a throw here escapes the result-pattern boundary: BaseActionSet.ApplyAsync catches it and returns new ActionSetResult(false, ex.Message), discarding all accumulated details (including the rollback narrative) and masking the original failure. Consider wrapping the probe in the same IOException/UnauthorizedAccessException handling and treating an enumeration failure as "not empty" so the directory is retained.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
The reason will be displayed to describe this comment to others. Learn more.
SUGGESTION: New catch block dereferences discoveredItem without a null guard.
If a caller passes a null discoveredItem (contract violation), the NullReferenceException thrown at the top of ResolveAsync is caught here, but discoveredItem.Name in the LogError call throws a second NRE that escapes the method. The previous catch (LogError(ex, "Failed to resolve Community Outpost content")) still returned a failure result, so this refactor turns a graceful OperationResult failure into an unhandled exception for null input. Per docs/dev/result-pattern.md, contract invariants should fail eagerly, e.g. ArgumentNullException.ThrowIfNull(discoveredItem) at method entry.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
The reason will be displayed to describe this comment to others. Learn more.
SUGGESTION: New genl entry has no test coverage.
GenPatcherContentRegistryTests parameterizes the sibling Tools entries (gent, gena) across GetMetadata, GetKnownContentCodes, and category assertions, but no genl rows were added for the new GenLauncher entry. Without coverage, a typo in the code or a regression in its Tools categorization would go unnoticed.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🚀
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds a new Tool under the tools tab that applies all the core fixes which GenPatcher applies aswell.
Greptile Summary
This PR introduces a comprehensive ActionSet orchestration framework that ports GenPatcher functionality into GenHub as a new tool. The implementation adds 36+ automated fixes for Command & Conquer Generals/Zero Hour, including registry fixes, file system operations, DirectX/VC++ redistributable installers, and game configuration optimizations.
Key Changes:
IActionSetinterface andBaseActionSetabstract class for extensible fix implementationActionSetOrchestratorto manage sequential fix application with crucial fix handlingGenPatcherToolplugin with UI (GenPatcherViewModel) for fix managementIHttpClientFactoryfor downloading patches and redistributables (now properly registered in DI)ActionSetConstants,RegistryConstants,ExternalUrls, andGameSettingsConstantsArchitecture Strengths:
GenHub.Core) and Windows-specific implementationsCritical Issues Previously Addressed:
IHttpClientFactoryregistration added toWindowsServicesModule.cs:36NahimicFixprocess checking logic correctedRemaining Concerns:
docs/features/actionsets.mdcontains duplicate sectionsRemoveReadOnlyFixhave marker file logic inconsistenciesBuild Status:
Confidence Score: 4/5
EAAppRegistryFix.cs(serial key logic),OptionsINIFix.cs(resolution reporting),RemoveReadOnlyFix.cs(marker file logic),DirectXRuntimeFix.cs(argument assignment), andOneDriveFix.cs(folder merge handling)Important Files Changed
Sequence Diagram
sequenceDiagram participant User participant GenPatcherViewModel participant ActionSetOrchestrator participant IActionSet participant RegistryService participant FileSystem participant HttpClient User->>GenPatcherViewModel: Open GenPatcher Tool GenPatcherViewModel->>GenPatcherViewModel: Check Admin Privileges GenPatcherViewModel->>ActionSetOrchestrator: GetAllActionSets() ActionSetOrchestrator-->>GenPatcherViewModel: List of ActionSets loop For each ActionSet GenPatcherViewModel->>IActionSet: IsApplicableAsync(installation) IActionSet-->>GenPatcherViewModel: bool GenPatcherViewModel->>IActionSet: IsAppliedAsync(installation) IActionSet-->>GenPatcherViewModel: bool end GenPatcherViewModel-->>User: Display ActionSets with Status User->>GenPatcherViewModel: Apply All Fixes GenPatcherViewModel->>RegistryService: IsRunningAsAdministrator() alt Not Admin GenPatcherViewModel-->>User: Show Error (Admin Required) else Is Admin loop For each unapplied fix GenPatcherViewModel->>IActionSet: ApplyAsync(installation) alt Registry Fix IActionSet->>RegistryService: SetStringValue/SetIntValue RegistryService-->>IActionSet: Success/Failure else File System Fix IActionSet->>FileSystem: Copy/Move/Create Files FileSystem-->>IActionSet: Success/Failure else Download Fix IActionSet->>HttpClient: Download Patch HttpClient-->>IActionSet: Patch File IActionSet->>FileSystem: Extract & Install FileSystem-->>IActionSet: Success/Failure end IActionSet-->>GenPatcherViewModel: ActionSetResult alt Crucial Fix Failed GenPatcherViewModel-->>User: Abort & Show Error else Non-Crucial Fix Failed GenPatcherViewModel-->>User: Continue & Log Warning else Fix Succeeded GenPatcherViewModel->>IActionSet: IsAppliedAsync(installation) IActionSet-->>GenPatcherViewModel: bool GenPatcherViewModel-->>User: Show Success end end GenPatcherViewModel-->>User: Show Final Summary endContext used (3)
dashboard- What: All compiler warnings and linter warnings across the entire codebase must be resolved before m... (source)dashboard- Custom context (source)dashboard- Use dedicated constants classes instead of hardcoding constants string, integers or variables in ser... (source)