# fix-token-config.ps1 (ASCII-only comments to avoid PS5 encoding issues) # Strategy: find "tokenConfig" key, cut back to last } before it, re-inject from UTF-8 file param( [string]$SkillsRoot = (Split-Path $PSScriptRoot -Parent), [string]$InjectionFile = (Join-Path $PSScriptRoot "token-config-injection.txt"), [switch]$DryRun ) $utf8NoBom = New-Object System.Text.UTF8Encoding($false) if (-not (Test-Path $InjectionFile)) { Write-Error "Injection file not found: $InjectionFile" exit 1 } $injection = [System.IO.File]::ReadAllText($InjectionFile, [System.Text.Encoding]::UTF8) $injection = $injection.TrimEnd() $categories = @("voc","social-media","competitor-analysis","review-analysis","synthesis","social-voc","douyin") $fixed = 0 $skipped = 0 foreach ($cat in $categories) { $catPath = Join-Path $SkillsRoot $cat if (-not (Test-Path $catPath)) { continue } Get-ChildItem -Recurse -Filter "api-config.json" -Path $catPath | ForEach-Object { $filePath = $_.FullName $relPath = $filePath.Replace($SkillsRoot + '\', '') $content = Get-Content -Path $filePath -Raw -Encoding UTF8 if ([string]::IsNullOrEmpty($content)) { Write-Warning " [WARN] empty: $relPath" $skipped++ return } $searchKey = [string]'"tokenConfig"' $tcIdx = $content.IndexOf($searchKey) if ($tcIdx -lt 0) { Write-Host " [SKIP] no tokenConfig: $relPath" -ForegroundColor DarkGray $skipped++ return } $cutPos = $content.LastIndexOf([string]'}', $tcIdx - 1) if ($cutPos -lt 0) { Write-Warning " [WARN] no cut point: $relPath" $skipped++ return } $base = $content.Substring(0, $cutPos + 1).TrimEnd() $newContent = $base + ",`r`n" + $injection + "`r`n}" if ($DryRun) { Write-Host " [DRY] $relPath" -ForegroundColor Yellow } else { [System.IO.File]::WriteAllText($filePath, $newContent, $utf8NoBom) Write-Host " [OK] $relPath" -ForegroundColor Green } $fixed++ } } Write-Host "" Write-Host "Done: $fixed fixed, $skipped skipped" if ($DryRun) { Write-Host "Remove -DryRun to apply." -ForegroundColor Yellow }