Public/Ccs.ps1
|
# The `ccs` front door — a git-style dispatcher over the cmdlets. # Subcommand names win over profile names in the bare-name shorthand, so a # profile may not be called one of these. $script:CcsReservedNames = @( 'list', 'ls', 'use', 'run', 'status', 'doctor', 'capture', 'remove', 'aws', 'help', 'adopt', 'backup-personal', 'new', 'rename' ) function ccs { <# .SYNOPSIS Switch Claude Code between config profiles (subscription / Bedrock). .EXAMPLE ccs list .EXAMPLE ccs use work .EXAMPLE ccs run personal -- --resume #> [CmdletBinding()] param( [Parameter(Position = 0)][string]$Command = 'status', [Parameter(ValueFromRemainingArguments)][string[]]$Rest ) $args1 = @($Rest | Where-Object { $_ -ne '--' }) switch ($Command.ToLowerInvariant()) { 'list' { Get-CcsProfileList; return } 'ls' { Get-CcsProfileList; return } 'use' { if (-not $args1) { throw 'Usage: ccs use <profile>' } Show-CcsSwitchResult (Use-CcsProfile -Name $args1[0]) return } 'run' { if (-not $args1) { throw 'Usage: ccs run <profile> [-- <claude args>]' } $forwarded = @() if ($Rest.Count -gt 1) { $idx = [Array]::IndexOf($Rest, '--') $forwarded = if ($idx -ge 0) { $Rest[($idx + 1)..($Rest.Count - 1)] } else { $Rest[1..($Rest.Count - 1)] } } Start-CcsClaude -Name $args1[0] -ClaudeArgs $forwarded return } 'status' { if ($args1) { Get-CcsStatus -Name $args1[0] } else { Get-CcsStatus } return } 'doctor' { $findings = @(Test-CcsHealth) if (-not $findings) { Write-Host 'OK — no problems found.' -ForegroundColor Green return } foreach ($f in $findings) { $colour = switch ($f.Severity) { 'Error' { 'Red' } 'Warning' { 'Yellow' } default { 'DarkGray' } } Write-Host ("[{0}] {1}" -f $f.Severity.ToUpper(), $f.Check) -ForegroundColor $colour Write-Host (" {0}" -f $f.Message) if ($f.Fix) { Write-Host (" fix: {0}" -f $f.Fix) -ForegroundColor DarkGray } } return } 'capture' { if (-not $args1) { throw 'Usage: ccs capture <profile> [-From <dir>] [-FromSettingsFile <file>] [-Note <text>] [-SettingsOnly] [-LinkShared] [-Force]' } $params = @{ Name = $args1[0] } foreach ($switchName in @('Force', 'SettingsOnly', 'LinkShared')) { if ($Rest | Where-Object { $_ -eq "-$switchName" }) { $params[$switchName] = $true } } foreach ($valued in @('From', 'FromSettingsFile', 'Note')) { $idx = [Array]::FindIndex([string[]]$Rest, [Predicate[string]] { param($x) $x -eq "-$valued" }) if ($idx -ge 0 -and $idx + 1 -lt $Rest.Count) { $params[$valued] = $Rest[$idx + 1] } } $p = New-CcsProfileFromCurrent @params Write-Host "Captured '$($p.Name)' [$($p.Backend)] → $($p.Dir)" -ForegroundColor Green return } 'new' { if (-not $args1) { throw 'Usage: ccs new <profile> [-Blank] [-Note <text>] [-Force]' } $params = @{ Name = $args1[0] } foreach ($switchName in @('Blank', 'Force')) { if ($Rest | Where-Object { $_ -eq "-$switchName" }) { $params[$switchName] = $true } } $idx = [Array]::FindIndex([string[]]$Rest, [Predicate[string]] { param($x) $x -eq '-Note' }) if ($idx -ge 0 -and $idx + 1 -lt $Rest.Count) { $params['Note'] = $Rest[$idx + 1] } $p = New-CcsBlankProfile @params Write-Host "Created '$($p.Name)' -> $($p.Dir)" -ForegroundColor Green Write-Host " Sign in with: ccs run $($p.Name)" -ForegroundColor DarkGray return } 'rename' { if ($args1.Count -lt 2) { throw 'Usage: ccs rename <old> <new>' } $p = Rename-CcsProfileEntry -Name $args1[0] -NewName $args1[1] Write-Host "Renamed '$($args1[0])' -> '$($p.Name)' [$($p.Backend)] $($p.Dir)" -ForegroundColor Green return } 'backup-personal' { $path = Backup-CcsPersonalSettings -Force:($Rest -contains '-Force') Write-Host "Personal settings baseline saved: $path" -ForegroundColor Green return } 'adopt' { $target = if ($args1) { $args1[0] } else { 'work' } $result = Invoke-CcsAdopt -Name $target -KeepLive:($Rest -contains '-KeepLive') Write-Host "Adopted company settings into '$($result.Profile)' [$($result.Backend)]" -ForegroundColor Green if ($result.PersonalRestored) { Write-Host ' ~/.claude restored to your personal settings' -ForegroundColor DarkGray } $errors = @($result.Findings | Where-Object Severity -eq 'Error') if ($errors) { Write-Host " $($errors.Count) problem(s) found - run: ccs doctor" -ForegroundColor Yellow } return } 'remove' { if (-not $args1) { throw 'Usage: ccs remove <profile> [-DeleteFiles]' } Remove-CcsProfileEntry -Name $args1[0] -DeleteFiles:($Rest -contains '-DeleteFiles') return } 'aws' { if ($args1) { Get-CcsAwsIdentity -Name $args1[0] } else { Get-CcsAwsIdentity } return } 'help' { Show-CcsHelp; return } '--help' { Show-CcsHelp; return } '-h' { Show-CcsHelp; return } default { # A bare profile name is shorthand for `ccs use <name>` - the shape # every other switcher uses, and the one people reach for first. $known = (Get-CcsConfig).profiles.PSObject.Properties.Name if ($Command -in $known) { Show-CcsSwitchResult (Use-CcsProfile -Name $Command) return } throw "Unknown command or profile '$Command'. Profiles: $($known -join ', '). Run 'ccs help'." } } } function Show-CcsSwitchResult { <# Human-facing confirmation shared by `ccs use` and the bare-name shorthand. #> param([Parameter(Mandatory)]$Profile) Write-Host "-> $($Profile.Name) [$($Profile.Backend)] $($Profile.Dir)" -ForegroundColor Green Write-Host ' This shell only. Other terminals and Claude Desktop are unchanged.' -ForegroundColor DarkGray } function Show-CcsHelp { @' ccs — Claude Code profile switcher ccs <profile> Shorthand for 'ccs use <profile>' ccs list Show profiles, backend and which one this shell uses ccs use <profile> Point THIS shell at a profile (CLAUDE_CONFIG_DIR) ccs run <profile> [-- args] Launch claude under a profile, shell untouched ccs status [profile] Backend, model pins, telemetry, AWS state ccs doctor Diagnose conflicts (read-only, never logs in) ccs new <profile> Create an empty profile to sign a second account into ccs rename <old> <new> Rename a profile (moves its folder when managed) ccs capture <profile> Snapshot ~/.claude settings into a new profile ccs backup-personal Save ~/.claude/settings.json as your personal baseline ccs adopt [profile] After the company install.bat: move its settings into the profile (default 'work') and restore your own ccs remove <profile> Unregister a profile (-DeleteFiles to erase it) ccs aws [profile] aws sts get-caller-identity (may open a browser) Profiles live in ~/.claude-profiles; the 'personal' profile is ~/.claude itself. Claude Desktop / Cowork follow a machine policy and are NOT switched by ccs. '@ | Write-Host } |