-
-
Notifications
You must be signed in to change notification settings - Fork 39
feat: implement native multi-account switching with isolated instances #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add account-based profile management system that enables users to run multiple Claude accounts concurrently with complete isolation. Key features: - Profile registry (~/.ccs/profiles.json) tracks account profiles - Instance isolation (~/.ccs/instances/<profile>/) for each account - Auth commands: create, list, show, remove, default - Backward compatible with settings-based profiles (GLM, Kimi) - Auto-copies global .claude configs to new instances Implementation: - Phase 1: Profile detection logic (account vs settings-based) - Phase 2: Instance management (initialization, validation) - Phase 3: Auth CLI commands - Phase 4: Profile registry CRUD operations - Phase 5: Execution routing based on profile type Both lib/ccs (bash) and lib/ccs.ps1 (PowerShell) updated for cross-platform support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # Priority 1: Check settings-based profiles (backward compatibility) | ||
| if [[ -f "$CONFIG_FILE" ]]; then | ||
| local settings_path=$(jq -r ".profiles.\"$profile_name\" // empty" "$CONFIG_FILE" 2>/dev/null || true) | ||
| if [[ -n "$settings_path" ]]; then | ||
| PROFILE_TYPE="settings" | ||
| PROFILE_PATH="$settings_path" | ||
| PROFILE_NAME="$profile_name" | ||
| return 0 | ||
| fi | ||
| fi | ||
|
|
||
| # Priority 2: Check account-based profiles | ||
| if [[ -f "$PROFILES_JSON" ]] && profile_exists "$profile_name"; then | ||
| PROFILE_TYPE="account" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check account registry before legacy profiles
The new detection routine still queries config.json for settings profiles before looking at profiles.json. When a profile name exists in both locations—as happens during migration when legacy entries have not yet been removed—the command always takes the settings-based path and the account instance (and its isolation) is never used. This contradicts the documented priority “account-based → settings-based → error” and forces users to manually clean the legacy config to use the new feature. Reordering the checks so the account registry is consulted first would honor the advertised behavior.
Useful? React with 👍 / 👎.
| # Priority 1: Check settings-based profiles (backward compatibility) | ||
| if (Test-Path $ConfigFile) { | ||
| try { | ||
| $Config = Get-Content $ConfigFile -Raw | ConvertFrom-Json | ||
| $SettingsPath = $Config.profiles.$ProfileName | ||
|
|
||
| if ($SettingsPath) { | ||
| return @{ | ||
| Type = "settings" | ||
| Path = $SettingsPath | ||
| Name = $ProfileName | ||
| } | ||
| } | ||
| } catch {} | ||
| } | ||
|
|
||
| # Priority 2: Check account-based profiles | ||
| if ((Test-Path $ProfilesJson) -and (Test-ProfileExists $ProfileName)) { | ||
| return @{ | ||
| Type = "account" | ||
| Name = $ProfileName |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check account registry before legacy profiles (PS)
The PowerShell implementation mirrors the same order: Get-ProfileType reads the legacy settings config before testing profiles.json. If a profile name is present in both, the call will always resolve to the settings file and skip the account-based instance, despite the commit promising the opposite precedence. Users with leftover entries cannot benefit from isolated instances until they delete the legacy profile manually. Account profiles should be checked before settings profiles here as well.
Useful? React with 👍 / 👎.
| # Check if exists | ||
| if ! $force && profile_exists "$profile_name"; then | ||
| msg_error "Profile already exists: $profile_name" | ||
| echo "Use ${YELLOW}--force${RESET} to overwrite" | ||
| return 1 | ||
| fi | ||
|
|
||
| echo "└─" | ||
| # Create instance | ||
| echo "[i] Creating profile: $profile_name" | ||
| local instance_path=$(ensure_instance "$profile_name") | ||
| echo "[i] Instance directory: $instance_path" | ||
| echo "" | ||
|
|
||
| # Register profile | ||
| register_profile "$profile_name" | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement actual overwrite when --force is supplied
The auth create command advertises --force to overwrite an existing profile, but the code still calls register_profile unconditionally. register_profile refuses to add a duplicate and exits with “Profile already exists”, so the force option never succeeds and users must manually run auth remove or edit profiles.json after a failed setup. To make the flag meaningful the function should delete or overwrite the existing entry before re-registering (or skip register_profile when the profile already exists).
Useful? React with 👍 / 👎.
|
|
||
| if (-not $Force -and (Test-ProfileExists $ProfileName)) { | ||
| Write-ErrorMsg "Profile already exists: $ProfileName`nUse --force to overwrite" | ||
| return 1 | ||
| } | ||
|
|
||
| # Create instance | ||
| Write-Host "[i] Creating profile: $ProfileName" | ||
| $InstancePath = Ensure-Instance $ProfileName | ||
| Write-Host "[i] Instance directory: $InstancePath" | ||
| Write-Host "" | ||
|
|
||
| # Register profile | ||
| Register-Profile $ProfileName | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make --force overwrite profiles in PowerShell path
The PowerShell Invoke-AuthCreate code path likewise bypasses the initial existence check when --force is passed but still calls Register-Profile, which immediately throws if the profile already exists. Users following the CLI hint (“Use --force to overwrite”) will continue to receive a fatal error and cannot recreate the profile without manually removing it first. The function needs to delete or replace the existing registry entry before calling Register-Profile so that --force performs as advertised.
Useful? React with 👍 / 👎.
The branch protection rule requires "Deploy ccs-installer to CloudFlare" status check to pass, but the workflow only ran on push to main branch. This caused PRs to wait indefinitely for a status that never reported. Changes: - Add pull_request trigger with same path filters - Split deployment into conditional steps: - PR mode: dry-run validation only (--dry-run flag) - Production: actual deployment (push to main only) - Keeps same job name to satisfy branch protection requirement Security: - No deployment from PR branches (dry-run only) - Production deploy only when push to main AND ref check - Secrets used safely in both contexts This fixes PR #3 which was stuck waiting for status.
The path filter prevented workflow from running on PRs that don't modify worker/installer files, causing required status check to never report. This blocked PR #3 indefinitely. Changes: - Remove paths filter from pull_request trigger - Keep paths filter on push to main (optimize deployments) - Workflow now runs on ALL PRs to satisfy branch protection Trade-off: - PRs changing non-worker files will trigger unnecessary dry-run - But this ensures required status check always reports - Small cost for reliability and simpler configuration Alternatives considered: - Path-aware required checks: Not supported by GitHub - Remove required check: Loses CI validation - Add all paths to filter: Makes config brittle
Summary
Implement complete native multi-account profile management system for CCS v3.0.0.
Changes
~/.ccs/profiles.json) for account-based profile mappings~/.ccs/instances/<profile>/) for concurrent sessionscreate,list,show,remove,defaultlib/ccs) and PowerShell (lib/ccs.ps1) implementationsProfile Types
Account-based profiles (v3.0): Each profile gets isolated instance directory
ccs work,ccs personal,ccs teamCLAUDE_CONFIG_DIRenvironment variableSettings-based profiles (legacy): Uses settings files
ccs glm,ccs kimi,ccs default--settingsflagFeatures
ccs auth create/list/show/remove/default)Implementation
Testing