Windows
ag-cleanup.ps1
# =====================================================================================
# Antigravity Aggressive Cleanup for Windows
# =====================================================================================
function Clear-HostWrite-Header {
Clear-Host
Write-Host ""
Write-Host " ============================================================" -ForegroundColor Cyan
Write-Host " Antigravity Aggressive Cleanup for Windows" -ForegroundColor Cyan
Write-Host " ============================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host " This script is based on the amazing research by DuctTapedGoat" -ForegroundColor Yellow
Write-Host " from the r/google_antigravity community." -ForegroundColor Yellow
Write-Host ""
}
# --- Main Script ---
Clear-HostWrite-Header
Write-Host " This script will perform the Aggressive Cleanup to remove all"
Write-Host " Antigravity cache and data files from your system."
Write-Host ""
Write-Host " Please ensure you have UNINSTALLED Antigravity before proceeding." -ForegroundColor Yellow
Write-Host ""
$confirmation = Read-Host " Are you ready to proceed? (y/n)"
if ($confirmation -ne 'y') {
Write-Host ""
Write-Host " Aborting script. No files were changed." -ForegroundColor Red
Write-Host ""
exit
}
$foldersToDelete = @()
$foldersToDelete += Join-Path $env:LOCALAPPDATA 'Programs\Antigravity'
$foldersToDelete += Join-Path $env:APPDATA 'Antigravity'
$foldersToDelete += Join-Path $env:USERPROFILE '.gemini'
$foldersToDelete += Join-Path $env:USERPROFILE '.antigravity'
Clear-HostWrite-Header
Write-Host " The following directories (and all their contents) will be deleted:" -ForegroundColor White
Write-Host ""
foreach ($folder in $foldersToDelete) {
if (Test-Path $folder) {
Write-Host " - $folder" -ForegroundColor Yellow
} else {
Write-Host " - $folder (Not Found)" -ForegroundColor DarkGray
}
}
Write-Host ""
$finalConfirmation = Read-Host " THIS IS YOUR FINAL WARNING. Continue? (y/n)"
if ($finalConfirmation -ne 'y') {
Write-Host ""
Write-Host " Aborting script. No files were changed." -ForegroundColor Red
Write-Host ""
exit
}
Write-Host ""
Write-Host " Deleting files..." -ForegroundColor Green
foreach ($folder in $foldersToDelete) {
if (Test-Path $folder) {
try {
Remove-Item -Path $folder -Recurse -Force -ErrorAction Stop
Write-Host " - DELETED: $folder" -ForegroundColor Green
} catch {
Write-Host " - FAILED to delete: $folder" -ForegroundColor Red
Write-Host " Error: $_" -ForegroundColor DarkRed
}
}
}
Write-Host ""
Write-Host " ============================================================" -ForegroundColor Cyan
Write-Host " CLEANUP COMPLETE!" -ForegroundColor Cyan
Write-Host " ============================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host " What to do next:" -ForegroundColor White
Write-Host ""
Write-Host " 1. Set your DEFAULT SYSTEM BROWSER to a clean new browser"
Write-Host " with ONLY your paid Antigravity Google account signed in."
Write-Host " (Using Chrome Canary is a great way to keep this separate)."
Write-Host ""
Write-Host " 2. Reinstall Google Antigravity (do NOT run as Administrator)."
Write-Host ""
Write-Host " 3. Launch Antigravity and sign in. Your timers should now be truthful!"
Write-Host ""
Write-Host " 4. Once Antigravity is reinstalled, you can run the 'bigint-patch.bat'"
Write-Host " to fix the BigInt serialization bug."
Write-Host ""
Write-Host " 5. If that doesn't work try creating a new OS user account and sign in."
Write-Host ""
Read-Host " Press Enter to exit."
bigint-patcher.ps1
# =====================================================================================
# Antigravity BigInt Patcher for Windows
# =====================================================================================
$targetFile = Join-Path $env:LOCALAPPDATA 'Programs\Antigravity\resources\app\out\main.js'
$backupFile = "$targetFile.bak"
$patchedLogic = '(_k, v) => typeof v === "bigint" ? v.toString() : v'
# --- Utility Functions ---
function Write-Header($title) {
Clear-Host
Write-Host ""
Write-Host " ==============================================================" -ForegroundColor Cyan
Write-Host " $title" -ForegroundColor Cyan
Write-Host " ==============================================================" -ForegroundColor Cyan
Write-Host ""
}
function Get-Classification {
param($text)
if ($text -notmatch '^JSON\.stringify\((.*)\)$') { return @{ Type = 'unknown' } }
$argsContent = $Matches[1].Trim()
# If it contains any of these characters, it's not a simple variable, so it's risky.
if ($argsContent -match '[\{\(\[\]\}\,]') {
return @{ Type = 'risky' }
} else {
return @{ Type = 'easy' }
}
}
# --- Main Application Loop ---
if (-not (Test-Path $targetFile)) {
Write-Header "Error"
Write-Host " Antigravity main.js not found at $targetFile" -ForegroundColor Red
exit
}
$content = Get-Content -Raw $targetFile
while ($true) {
Write-Header "Windows BigInt Omni-Patcher v8 (Final)"
# --- Analysis Phase ---
# This section is now IDENTICAL to the checker and unpatcher for unified logic.
$allRegex = 'JSON\.stringify\((?:[^()]|\([^()]*\))*\)'
$allFoundMatches = [regex]::Matches($content, $allRegex)
$allItems = @()
$lineNumber = 1
$currentPos = 0
foreach ($m in $allFoundMatches) {
$text = $m.Value
$index = $m.Index
$gap = $content.Substring($currentPos, $index - $currentPos)
$lineNumber += ($gap -split "`n").Length - 1
$currentPos = $index
$item = [PSCustomObject]@{ Line = $lineNumber; Position = $index; Text = $text; Type = ''; Color = 'Gray' }
if ($text -like '*(typeof _r ===*bigint*)*') { # Check for the most specific patch first (Risky-Wrapped)
$item.Type = 'Patched (Risky-Wrapped)'; $item.Color = 'Cyan'
} elseif ($text -like 'JSON.stringify(*, (_k, v) => typeof v === "bigint"*') { # Easy or Risky-Added
$unpatchedVersion = $text -replace ',\s*\(_k, v\) => typeof v === "bigint" \? v\.toString\(\) : v', ''
$classification = Get-Classification -text $unpatchedVersion
if ($classification.Type -eq 'easy') {
$item.Type = 'Patched (Easy)'; $item.Color = 'Green'
} else {
$item.Type = 'Patched (Risky-Added)'; $item.Color = 'Yellow'
}
} else { # Unpatched
$classification = Get-Classification -text $text
if ($classification.Type -eq 'easy') {
$item.Type = 'Unpatched (Easy)'; $item.Color = 'Red'
} else {
$item.Type = 'Unpatched (Risky)'; $item.Color = 'Yellow'
}
}
$allItems += $item
}
# --- Count Categories ---
$patchedEasyCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Easy)' }).Count
$patchedRiskyAddedCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Risky-Added)' }).Count
$patchedRiskyWrappedCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Risky-Wrapped)' }).Count
$unpatchedEasyCount = ($allItems | Where-Object { $_.Type -eq 'Unpatched (Easy)' }).Count
$unpatchedRiskyCount = ($allItems | Where-Object { $_.Type -eq 'Unpatched (Risky)' }).Count
Write-Host " Scan Complete!"
Write-Host " - Patched (Easy): $patchedEasyCount" -ForegroundColor Green
Write-Host " - Patched (Risky-Added): $patchedRiskyAddedCount" -ForegroundColor Yellow
Write-Host " - Patched (Risky-Wrapped): $patchedRiskyWrappedCount" -ForegroundColor Cyan
Write-Host " - Unpatched (Easy): $unpatchedEasyCount" -ForegroundColor Red
Write-Host " - Unpatched (Risky): $unpatchedRiskyCount" -ForegroundColor Yellow
Write-Host ""
Write-Host " OPTIONS:" -ForegroundColor Gray
Write-Host " 1. Bulk Patch all EASY ($unpatchedEasyCount)"
Write-Host " 2. Bulk Patch all RISKY ($unpatchedRiskyCount)" -ForegroundColor Yellow
Write-Host " 3. Exit"
Write-Host ""
$choice = Read-Host " Enter Option#"
if ($choice -eq "3") { exit }
if (-not (Test-Path $backupFile)) {
Write-Host " Creating backup of fresh install..." -ForegroundColor Yellow
Copy-Item $targetFile $backupFile -Force
}
$patcherRegex = '^JSON\.stringify\((.*)\)$';
if ($choice -eq "1") {
if ($unpatchedEasyCount -eq 0) { Write-Host " No easy patches available."; Start-Sleep 1; continue }
$newContent = $content
$sortedEasy = $allItems | Where-Object { $_.Type -eq 'Unpatched (Easy)' } | Sort-Object Position -Descending
foreach ($h in $sortedEasy) {
if ($h.Text -match $patcherRegex) {
$argsContent = $Matches[1]
$replacement = "JSON.stringify($argsContent, $patchedLogic)"
$newContent = $newContent.Remove($h.Position, $h.Text.Length).Insert($h.Position, $replacement)
}
}
$content = $newContent
Set-Content -Path $targetFile -Value $content -NoNewline -Encoding UTF8
Write-Host " Easy Bulk Patch Applied!" -ForegroundColor Green; Start-Sleep 2
}
if ($choice -eq "2") {
if ($unpatchedRiskyCount -eq 0) { Write-Host " No risky patches available."; Start-Sleep 1; continue }
$riskyHits = $allItems | Where-Object { $_.Type -eq 'Unpatched (Risky)' }
$lineSum = ($riskyHits | Measure-Object -Property Line -Sum).Sum
$indexSum = ($riskyHits | Measure-Object -Property Position -Sum).Sum
$securityKey = "${lineSum}:${indexSum}"
Write-Host ""
Write-Host " DANGEROUS: To confirm this risky patch, type the following key and press Enter:" -ForegroundColor Yellow
Write-Host " $securityKey" -ForegroundColor Cyan
$userInput = Read-Host " Enter security key"
if ($userInput -ne $securityKey) { Write-Host " Incorrect key."; Start-Sleep 2; continue }
$newContent = $content
$sortedRisky = $riskyHits | Sort-Object Position -Descending
foreach ($h in $sortedRisky) {
if ($h.Text -match $patcherRegex) {
$argsContent = $Matches[1]
# Determine if this is a single-arg or multi-arg risky call
$isSingleArg = $true
if ($argsContent -match '[\{\(\[\]\}]\s*,.+') {
$isSingleArg = $false
}
if ($isSingleArg) {
# It's a single, complex argument. Add our replacer.
$newText = "JSON.stringify($argsContent, $patchedLogic)"
$newContent = $newContent.Remove($h.Position, $h.Text.Length).Insert($h.Position, $newText)
} else {
# It's a multi-argument call. Wrap the existing replacer.
$depth = 0; $inString = $false; $stringChar = ''; $isEscaped = $false; ${first_comm-index} = -1
for ($i = 0; $i -lt $argsContent.Length; $i++) {
$char = $argsContent[$i]
if ($isEscaped) { $isEscaped = $false; continue }
if ($char -eq '\') { $isEscaped = $true; continue }
if (($char -eq "'" -or $char -eq '"' -or $char -eq '`')) {
if ($inString -and $char -eq $stringChar) { $inString = $false } elseif (-not $inString) { $inString = $true; $stringChar = $char }
}
if ($inString) { continue }
if ($char -eq '(' -or $char -eq '{' -or $char -eq '[') { $depth++ }
elseif ($char -eq ')' -or $char -eq '}' -or $char -eq ']') { $depth-- }
if ($char -eq ',' -and $depth -eq 0) { ${first_comm-index} = $i; break }
}
if (${first_comm-index} -ne -1) {
$arg1 = $argsContent.Substring(0, ${first_comm-index}).Trim()
$rest = $argsContent.Substring(${first_comm-index} + 1).Trim()
$replacer = $rest
$restOfArgs = ''
# Find the second comma to isolate the replacer
$depth = 0; $inString = $false; $stringChar = ''; $isEscaped = $false; ${second_comm-index} = -1
for ($i = 0; $i -lt $rest.Length; $i++) {
$char = $rest[$i]
if ($isEscaped) { $isEscaped = $false; continue }
if ($char -eq '\') { $isEscaped = $true; continue }
if (($char -eq "'" -or $char -eq '"' -or $char -eq '`')) {
if ($inString -and $char -eq $stringChar) { $inString = $false } elseif (-not $inString) { $inString = $true; $stringChar = $char }
}
if ($inString) { continue }
if ($char -eq '(' -or $char -eq '{' -or $char -eq '[') { $depth++ }
elseif ($char -eq ')' -or $char -eq '}' -or $char -eq ']') { $depth-- }
if ($char -eq ',' -and $depth -eq 0) { ${second_comm-index} = $i; break }
}
if (${second_comm-index} -ne -1) {
$replacer = $rest.Substring(0, ${second_comm-index}).Trim()
$restOfArgs = $rest.Substring(${second_comm-index})
}
$wrappedReplacer = "(_k, v) => { let _r = ($replacer)(_k, v); return typeof _r === `"bigint`" ? _r.toString() : _r; }"
$newText = "JSON.stringify($arg1, $wrappedReplacer$restOfArgs)"
$newContent = $newContent.Remove($h.Position, $h.Text.Length).Insert($h.Position, $newText)
}
}
}
}
$content = $newContent
Set-Content -Path $targetFile -Value $content -NoNewline -Encoding UTF8
Write-Host " Risky Bulk Patch Applied!" -ForegroundColor Green; Start-Sleep 2
}
}
bigint-checker.ps1
# =====================================================================================
# Antigravity BigInt Checker for Windows
# =====================================================================================
$targetFile = Join-Path $env:LOCALAPPDATA 'Programs\Antigravity\resources\app\out\main.js'
$logFile = "$PSScriptRoot\bigint-scan.log"
# --- Regex for DETECTION ---
$easyPatchRegex = 'JSON\.stringify\(([^,]*?),\s*\(_k, v\) => typeof v === "bigint" \? v\.toString\(\) : v\)'
$riskyWrappedUnpatchRegex = 'JSON\.stringify\((.*?),\s*\(_k, v\)\s*=>\s*{\s*let\s*_r\s*=\s*\((.*?)\)\(_k, v\);\s*return\s*typeof\s*_r\s*===\s*"bigint"\s*\?\s*_r\.toString\(\)\s*:\s*_r;\s*}(,.*?)?\)'
$riskyAddedUnpatchRegex = 'JSON\.stringify\(([\{\(\[].*?[\}\)\]]),\s*\(_k, v\) => typeof v === "bigint" \? v\.toString\(\) : v\)'
# --- Utility Functions ---
function Write-Header($title) {
Clear-Host
Write-Host ""
Write-Host " ==============================================================" -ForegroundColor Cyan
Write-Host " $title" -ForegroundColor Cyan
Write-Host " ==============================================================" -ForegroundColor Cyan
Write-Host ""
}
# --- Main Application Loop ---
if (-not (Test-Path $targetFile)) { Write-Header "Error"; Write-Host " Antigravity main.js not found at $targetFile" -ForegroundColor Red; exit }
while ($true) {
Write-Header "Windows BigInt Checker"
$content = Get-Content -Raw $targetFile
# --- Analysis Phase ---
$allRegex = 'JSON\.stringify\((?:[^()]|\([^()]*\))*\)'
$allFoundMatches = [regex]::Matches($content, $allRegex)
$allItems = @()
$lineNumber = 1
$currentPos = 0
# This classification function must be IDENTICAL to the one in the patcher.
function Get-Classification {
param($text)
if ($text -notmatch '^JSON\.stringify\((.*)\)$') { return @{ Type = 'unknown' } }
$argsContent = $Matches[1].Trim()
if ($argsContent -match '[\{\(\[\]\}\,]') { return @{ Type = 'risky' } } else { return @{ Type = 'easy' } }
}
foreach ($m in $allFoundMatches) {
$text = $m.Value
$index = $m.Index
$gap = $content.Substring($currentPos, $index - $currentPos)
$lineNumber += ($gap -split "`n").Length - 1
$currentPos = $index
$item = [PSCustomObject]@{ Line = $lineNumber; Position = $index; Text = $text; Type = ''; Color = 'Gray' }
if ($text -like '*(typeof _r ===*bigint*)*') { # Check for the most specific patch first
$item.Type = 'Patched (Risky-Wrapped)'; $item.Color = 'Cyan'
} elseif ($text -like 'JSON.stringify(*, (_k, v) => typeof v === "bigint"*)') {
# This is a broad check. We need to see if it was a risky-add or an easy-add.
$unpatchedVersion = $text -replace ',\s*\(_k, v\) => typeof v === "bigint" \? v\.toString\(\) : v', ''
$classification = Get-Classification -text $unpatchedVersion
if ($classification.Type -eq 'easy') {
$item.Type = 'Patched (Easy)'; $item.Color = 'Green'
} else {
$item.Type = 'Patched (Risky-Added)'; $item.Color = 'Yellow'
}
} else {
$classification = Get-Classification -text $text
if ($classification.Type -eq 'easy') {
$item.Type = 'Unpatched (Easy)'; $item.Color = 'Red'
} else {
$item.Type = 'Unpatched (Risky)'; $item.Color = 'Yellow'
}
}
$allItems += $item
}
# --- UI & Menu ---
$patchedEasyCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Easy)' }).Count
$patchedRiskyAddedCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Risky-Added)' }).Count
$patchedRiskyWrappedCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Risky-Wrapped)' }).Count
$unpatchedEasyCount = ($allItems | Where-Object { $_.Type -eq 'Unpatched (Easy)' }).Count
$unpatchedRiskyCount = ($allItems | Where-Object { $_.Type -eq 'Unpatched (Risky)' }).Count
Write-Host " Scan Complete!"
Write-Host " - Patched (Easy): $patchedEasyCount" -ForegroundColor Green
Write-Host " - Patched (Risky-Added): $patchedRiskyAddedCount" -ForegroundColor Yellow
Write-Host " - Patched (Risky-Wrapped): $patchedRiskyWrappedCount" -ForegroundColor Cyan
Write-Host " - Unpatched (Easy): $unpatchedEasyCount" -ForegroundColor Red
Write-Host " - Unpatched (Risky): $unpatchedRiskyCount" -ForegroundColor Yellow
Write-Host ""
Write-Host " OPTIONS:" -ForegroundColor Gray
Write-Host " 1. Show All items"
Write-Host " 2. Show Patched items"
Write-Host " 3. Show Unpatched items"
Write-Host " 4. Save log and Exit"
$choice = Read-Host " Enter Option#"
switch ($choice) {
'1' {
Write-Header "All JSON.stringify Calls ($($allItems.Count))"
$allItems | ForEach-Object { Write-Host " [L:$($_.Line)|P:$($_.Position)] $($_.Text)" -ForegroundColor $_.Color }
Read-Host "`n Press Enter to return to menu"
}
'2' {
Write-Header "Patched Calls ($($patchedEasyCount + $patchedRiskyAddedCount + $patchedRiskyWrappedCount))"
($allItems | Where-Object { $_.Type -like 'Patched*' }) | ForEach-Object { Write-Host " [L:$($_.Line)|P:$($_.Position)] $($_.Text)" -ForegroundColor $_.Color }
Read-Host "`n Press Enter to return to menu"
}
'3' {
Write-Header "Unpatched Calls ($unpatchedCount)"
($allItems | Where-Object { $_.Type -eq 'Unpatched' }) | ForEach-Object { Write-Host " [L:$($_.Line)|P:$($_.Position)] $($_.Text)" -ForegroundColor $_.Color }
Read-Host "`n Press Enter to return to menu"
}
''' '4' {
$logContent = @()
$logContent += "Antigravity BigInt Scan Results"
$logContent += "================================================="
$logContent += "Scan Date: $(Get-Date)"
$logContent += "Target File: $targetFile"
$logContent += ""
$logContent += "Summary:"
$logContent += "- Patched (Easy): $patchedEasyCount"
$logContent += "- Patched (Risky-Added): $patchedRiskyAddedCount"
$logContent += "- Patched (Risky-Wrapped): $patchedRiskyWrappedCount"
$logContent += "- Unpatched (Easy): $unpatchedEasyCount"
$logContent += "- Unpatched (Risky): $unpatchedRiskyCount"
$logContent += ""
$logContent += "Details:"
$logContent += "================================================="
$allItems | ForEach-Object {
$logContent += "[L:$($_.Line)|P:$($_.Position)] [$($_.Type)] - $($_.Text)"
}
$logContent | Set-Content -Path $logFile -Encoding UTF8
Write-Host "`n Log saved to $logFile" -ForegroundColor Green
Start-Sleep 2
exit
}'''}
}
}
bigint-unpatcher.ps1
# =====================================================================================
# Antigravity BigInt Unpatcher for Windows
# =====================================================================================
$targetFile = Join-Path $env:LOCALAPPDATA 'Programs\Antigravity\resources\app\out\main.js'
$backupFile = "$targetFile.bak"
$patchedBackupFile = "$targetFile.patched.bak" # A backup of the patched file, if one exists
$easyPatchLogic = '(_k, v) => typeof v === "bigint" ? v.toString() : v'
# --- Regex for UNPATCHING ---
# This will find an easy patch and capture the single argument before it.
$easyUnpatchRegex = 'JSON\.stringify\(([^,]*?),\s*' + [regex]::escape($easyPatchLogic) + '\)'
# This will find a risky patch where we wrapped a replacer, and extract the original three parts.
$riskyWrappedUnpatchRegex = 'JSON\.stringify\((.*?),\s*\(_k, v\)\s*=>\s*{\s*let\s*_r\s*=\s*\((.*?)\)\(_k, v\);\s*return\s*typeof\s*_r\s*===\s*"bigint"\s*\?\s*_r\.toString\(\)\s*:\s*_r;\s*}(,.*?)?\)'
# This will find a risky patch where we ADDED a replacer to a complex single argument.
$riskyAddedUnpatchRegex = 'JSON\.stringify\(([\{\(\[].*?[\}\)\]]),\s*' + [regex]::escape($easyPatchLogic) + '\)'
# --- Utility Functions ---
function Write-Header($title) {
Clear-Host
Write-Host ""
Write-Host " ==============================================================" -ForegroundColor Cyan
Write-Host " $title" -ForegroundColor Cyan
Write-Host " ==============================================================" -ForegroundColor Cyan
Write-Host ""
}
# --- Main Application Loop ---
if (-not (Test-Path $targetFile)) { Write-Header "Error"; Write-Host " Antigravity main.js not found at $targetFile" -ForegroundColor Red; exit }
while ($true) {
Write-Header "Windows BigInt Omni-Unpatcher"
$content = Get-Content -Raw $targetFile
# --- Analysis Phase ---
$allRegex = 'JSON\.stringify\((?:[^()]|\([^()]*\))*\)'
$allFoundMatches = [regex]::Matches($content, $allRegex)
$allItems = @()
$lineNumber = 1
$currentPos = 0
# This classification function must be IDENTICAL to the one in the patcher and checker.
function Get-Classification {
param($text)
if ($text -notmatch '^JSON\.stringify\((.*)\)$') { return @{ Type = 'unknown' } }
$argsContent = $Matches[1].Trim()
if ($argsContent -match '[\{\(\[\]\}\,]') { return @{ Type = 'risky' } } else { return @{ Type = 'easy' } }
}
foreach ($m in $allFoundMatches) {
$text = $m.Value
$index = $m.Index
$gap = $content.Substring($currentPos, $index - $currentPos)
$lineNumber += ($gap -split "`n").Length - 1
$currentPos = $index
$item = [PSCustomObject]@{ Line = $lineNumber; Position = $index; Text = $text; Type = ''; Color = 'Gray' }
if ($text -like '*(typeof _r ===*bigint*)*') { # Check for the most specific patch first (Risky-Wrapped)
$item.Type = 'Patched (Risky-Wrapped)'; $item.Color = 'Cyan'
} elseif ($text -like 'JSON.stringify(*, (_k, v) => typeof v === "bigint"*') { # Easy or Risky-Added
$unpatchedVersion = $text -replace ',\s*\(_k, v\) => typeof v === "bigint" \? v\.toString\(\) : v', ''
$classification = Get-Classification -text $unpatchedVersion
if ($classification.Type -eq 'easy') {
$item.Type = 'Patched (Easy)'; $item.Color = 'Green'
} else {
$item.Type = 'Patched (Risky-Added)'; $item.Color = 'Yellow'
}
} else { # Unpatched
$classification = Get-Classification -text $text
if ($classification.Type -eq 'easy') {
$item.Type = 'Unpatched (Easy)'; $item.Color = 'Red'
} else {
$item.Type = 'Unpatched (Risky)'; $item.Color = 'Yellow'
}
}
$allItems += $item
}
# --- Count Categories ---
$patchedEasyCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Easy)' }).Count
$patchedRiskyAddedCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Risky-Added)' }).Count
$patchedRiskyWrappedCount = ($allItems | Where-Object { $_.Type -eq 'Patched (Risky-Wrapped)' }).Count
$unpatchedEasyCount = ($allItems | Where-Object { $_.Type -eq 'Unpatched (Easy)' }).Count
$unpatchedRiskyCount = ($allItems | Where-Object { $_.Type -eq 'Unpatched (Risky)' }).Count
$totalPatchedCount = $patchedEasyCount + $patchedRiskyAddedCount + $patchedRiskyWrappedCount
# --- UI & Menu ---
Write-Host " File Scan Results:"
Write-Host " - Patched (Easy): $patchedEasyCount" -ForegroundColor Green
Write-Host " - Patched (Risky-Added): $patchedRiskyAddedCount" -ForegroundColor Yellow
Write-Host " - Patched (Risky-Wrapped): $patchedRiskyWrappedCount" -ForegroundColor Cyan
Write-Host " - Unpatched (Easy): $unpatchedEasyCount" -ForegroundColor Red
Write-Host " - Unpatched (Risky): $unpatchedRiskyCount" -ForegroundColor Yellow
Write-Host ""
Write-Host " OPTIONS:" -ForegroundColor Gray
Write-Host " 1. Unpatch ALL ($totalPatchedCount found)"
Write-Host " 2. Unpatch Easy only ($patchedEasyCount found)"
Write-Host " 3. Unpatch Risky-Added only ($patchedRiskyAddedCount found)"
Write-Host " 4. Unpatch Risky-Wrapped only ($patchedRiskyWrappedCount found)"
Write-Host " 5. Restore from backup ($backupFile)"
Write-Host " 6. Exit"
$choice = Read-Host " Enter Option#"
switch ($choice) {
'1' { # UNPATCH ALL
if ($totalPatchedCount -eq 0) { Write-Host " No patches to remove."; Start-Sleep 1; continue }
Write-Host " Unpatching all found patches..." -ForegroundColor Yellow
if (-not (Test-Path $patchedBackupFile)) { Copy-Item $targetFile $patchedBackupFile -Force -Encoding UTF8 }
$newContent = $content
# Order matters: Go from most specific to least specific regex.
$newContent = $newContent -replace $riskyWrappedUnpatchRegex, 'JSON.stringify($1, $2$3)'
$newContent = $newContent -replace $riskyAddedUnpatchRegex, 'JSON.stringify($1)'
$newContent = $newContent -replace $easyUnpatchRegex, 'JSON.stringify($1)'
Set-Content -Path $targetFile -Value $newContent -NoNewline -Encoding UTF8
Write-Host " Bulk Unpatch Applied!" -ForegroundColor Green; Start-Sleep 2
}
'2' { # UNPATCH EASY
if ($patchedEasyCount -eq 0) { Write-Host " No easy patches to remove."; Start-Sleep 1; continue }
if (-not (Test-Path $patchedBackupFile)) { Copy-Item $targetFile $patchedBackupFile -Force -Encoding UTF8 }
$newContent = $content -replace $easyUnpatchRegex, 'JSON.stringify($1)'
Set-Content -Path $targetFile -Value $newContent -NoNewline -Encoding UTF8
Write-Host " Easy patches removed!" -ForegroundColor Green; Start-Sleep 2
}
'3' { # UNPATCH RISKY-ADDED
if ($patchedRiskyAddedCount -eq 0) { Write-Host " No risky-added patches to remove."; Start-Sleep 1; continue }
if (-not (Test-Path $patchedBackupFile)) { Copy-Item $targetFile $patchedBackupFile -Force -Encoding UTF8 }
$newContent = $content -replace $riskyAddedUnpatchRegex, 'JSON.stringify($1)'
Set-Content -Path $targetFile -Value $newContent -NoNewline -Encoding UTF8
Write-Host " Risky-added patches removed!" -ForegroundColor Green; Start-Sleep 2
}
'4' { # UNPATCH RISKY-WRAPPED
if ($patchedRiskyWrappedCount -eq 0) { Write-Host " No risky-wrapped patches to remove."; Start-Sleep 1; continue }
if (-not (Test-Path $patchedBackupFile)) { Copy-Item $targetFile $patchedBackupFile -Force -Encoding UTF8 }
$newContent = $content -replace $riskyWrappedUnpatchRegex, 'JSON.stringify($1, $2$3)'
Set-Content -Path $targetFile -Value $newContent -NoNewline -Encoding UTF8
Write-Host " Risky-wrapped patches removed!" -ForegroundColor Green; Start-Sleep 2
}
'5' { # RESTORE BACKUP
if (Test-Path $backupFile) {
Write-Host " Restoring original file from $backupFile..." -ForegroundColor Yellow
Copy-Item $backupFile $targetFile -Force
(Get-Content $targetFile -Raw) | Set-Content -Path $targetFile -NoNewline -Encoding utf8 # Ensure encoding is correct after restore
Write-Host " Restore complete!" -ForegroundColor Green
} else {
Write-Host " Backup file not found ($backupFile)." -ForegroundColor Red
}
Start-Sleep 2
}
'6' { exit }
}
}