@kaitranntt/ccs 4.1.3 → 4.1.5

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/lib/ccs CHANGED
@@ -2,7 +2,7 @@
2
2
  set -euo pipefail
3
3
 
4
4
  # Version (updated by scripts/bump-version.sh)
5
- CCS_VERSION="4.1.3"
5
+ CCS_VERSION="4.1.5"
6
6
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
7
  readonly CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}"
8
8
  readonly PROFILES_JSON="$HOME/.ccs/profiles.json"
@@ -165,74 +165,82 @@ find_similar_strings() {
165
165
  show_help() {
166
166
  echo -e "${BOLD}CCS (Claude Code Switch) - Instant profile switching for Claude CLI${RESET}"
167
167
  echo ""
168
+
168
169
  echo -e "${CYAN}Usage:${RESET}"
169
170
  echo -e " ${YELLOW}ccs${RESET} [profile] [claude-args...]"
170
- echo -e " ${YELLOW}ccs auth${RESET} <command> [options]"
171
171
  echo -e " ${YELLOW}ccs${RESET} [flags]"
172
172
  echo ""
173
+
173
174
  echo -e "${CYAN}Description:${RESET}"
174
- echo -e " Switch between multiple Claude accounts (work, personal, team) and"
175
- echo -e " alternative models (GLM, Kimi) instantly. Concurrent sessions with"
176
- echo -e " auto-recovery. Zero downtime."
175
+ echo -e " Switch between multiple Claude accounts and alternative models"
176
+ echo -e " (GLM, Kimi) instantly. Run different Claude CLI sessions concurrently"
177
+ echo -e " with auto-recovery. Zero downtime."
177
178
  echo ""
179
+
178
180
  echo -e "${CYAN}Model Switching:${RESET}"
179
181
  echo -e " ${YELLOW}ccs${RESET} Use default Claude account"
180
182
  echo -e " ${YELLOW}ccs glm${RESET} Switch to GLM 4.6 model"
181
183
  echo -e " ${YELLOW}ccs glmt${RESET} Switch to GLM with thinking mode"
184
+ echo -e " ${YELLOW}ccs glmt --verbose${RESET} Enable debug logging"
182
185
  echo -e " ${YELLOW}ccs kimi${RESET} Switch to Kimi for Coding"
183
186
  echo -e " ${YELLOW}ccs glm${RESET} \"debug this code\" Use GLM and run command"
184
187
  echo ""
188
+
185
189
  echo -e "${CYAN}Account Management:${RESET}"
186
- echo -e " ${YELLOW}ccs auth --help${RESET} Manage multiple Claude accounts"
187
- echo -e " ${YELLOW}ccs work${RESET} Switch to work account"
188
- echo -e " ${YELLOW}ccs personal${RESET} Switch to personal account"
190
+ echo -e " ${YELLOW}ccs auth --help${RESET} Run multiple Claude accounts concurrently"
189
191
  echo ""
190
- echo -e "${CYAN}Delegation (Token Optimization):${RESET}"
191
- echo -e " ${YELLOW}/ccs:glm \"task\"${RESET} Delegate to GLM-4.6 within Claude session"
192
+
193
+ echo -e "${CYAN}Delegation (inside Claude Code CLI):${RESET}"
194
+ echo -e " ${YELLOW}/ccs:glm \"task\"${RESET} Delegate to GLM-4.6 for simple tasks"
192
195
  echo -e " ${YELLOW}/ccs:kimi \"task\"${RESET} Delegate to Kimi for long context"
193
- echo -e " ${YELLOW}/ccs:create m2${RESET} Create custom delegation command"
194
- echo -e " Use delegation to save tokens on simple tasks"
195
- echo -e " Commands work inside Claude Code sessions only"
196
+ echo -e " Save tokens by delegating simple tasks to cost-optimized models"
196
197
  echo ""
198
+
197
199
  echo -e "${CYAN}Diagnostics:${RESET}"
198
200
  echo -e " ${YELLOW}ccs doctor${RESET} Run health check and diagnostics"
201
+ echo -e " ${YELLOW}ccs sync${RESET} Sync delegation commands and skills"
199
202
  echo ""
203
+
200
204
  echo -e "${CYAN}Flags:${RESET}"
201
205
  echo -e " ${YELLOW}-h, --help${RESET} Show this help message"
202
206
  echo -e " ${YELLOW}-v, --version${RESET} Show version and installation info"
203
- echo -e " ${YELLOW}--shell-completion${RESET} Install shell auto-completion"
207
+ echo -e " ${YELLOW}-sc, --shell-completion${RESET} Install shell auto-completion"
204
208
  echo ""
209
+
205
210
  echo -e "${CYAN}Configuration:${RESET}"
206
- echo -e " Config: ~/.ccs/config.json"
207
- echo -e " Profiles: ~/.ccs/profiles.json"
208
- echo -e " Instances: ~/.ccs/instances/"
209
- echo -e " Settings: ~/.ccs/*.settings.json"
211
+ echo -e " Config File: ~/.ccs/config.json"
212
+ echo -e " Profiles: ~/.ccs/profiles.json"
213
+ echo -e " Instances: ~/.ccs/instances/"
214
+ echo -e " Settings: ~/.ccs/*.settings.json"
215
+ echo -e " Environment: CCS_CONFIG (override config path)"
210
216
  echo ""
217
+
211
218
  echo -e "${CYAN}Shared Data:${RESET}"
212
- echo -e " Commands: ~/.ccs/shared/commands/"
213
- echo -e " Skills: ~/.ccs/shared/skills/"
219
+ echo -e " Commands: ~/.ccs/shared/commands/"
220
+ echo -e " Skills: ~/.ccs/shared/skills/"
221
+ echo -e " Agents: ~/.ccs/shared/agents/"
214
222
  echo -e " Note: Commands, skills, and agents are symlinked across all profiles"
215
223
  echo ""
224
+
216
225
  echo -e "${CYAN}Examples:${RESET}"
217
- echo -e " Quick start:"
218
- echo -e " ${YELLOW}\$ ccs${RESET} # Use default account"
219
- echo -e " ${YELLOW}\$ ccs glm \"implement API\"${RESET} # Cost-optimized model"
220
- echo ""
221
- echo -e " Multi-account workflow:"
222
- echo -e " ${YELLOW}\$ ccs auth create work${RESET} # Create work profile"
223
- echo -e " ${YELLOW}\$ ccs work \"review PR\"${RESET} # Use work account"
226
+ echo -e " ${YELLOW}\$ ccs${RESET} # Use default account"
227
+ echo -e " ${YELLOW}\$ ccs glm \"implement API\"${RESET} # Cost-optimized model"
224
228
  echo ""
225
- echo -e " For more: ${CYAN}https://github.com/kaitranntt/ccs#usage${RESET}"
229
+ echo -e " For more: ${CYAN}https://github.com/kaitranntt/ccs/blob/main/README.md${RESET}"
226
230
  echo ""
231
+
227
232
  echo -e "${YELLOW}Uninstall:${RESET}"
228
- echo " npm: npm uninstall -g @kaitranntt/ccs"
229
- echo " macOS/Linux: curl -fsSL ccs.kaitran.ca/uninstall | bash"
230
- echo " Windows: irm ccs.kaitran.ca/uninstall | iex"
233
+ echo -e " npm: npm uninstall -g @kaitranntt/ccs"
234
+ echo -e " macOS/Linux: curl -fsSL ccs.kaitran.ca/uninstall | bash"
235
+ echo -e " Windows: irm ccs.kaitran.ca/uninstall | iex"
231
236
  echo ""
237
+
232
238
  echo -e "${CYAN}Documentation:${RESET}"
233
239
  echo -e " GitHub: ${CYAN}https://github.com/kaitranntt/ccs${RESET}"
234
240
  echo -e " Docs: https://github.com/kaitranntt/ccs/blob/main/README.md"
241
+ echo -e " Issues: https://github.com/kaitranntt/ccs/issues"
235
242
  echo ""
243
+
236
244
  echo -e "${CYAN}License:${RESET} MIT"
237
245
  }
238
246
 
@@ -489,6 +497,100 @@ doctor_run() {
489
497
  $has_errors && exit 1 || exit 0
490
498
  }
491
499
 
500
+ # --- Sync Command ---
501
+
502
+ sync_run() {
503
+ local ccs_claude_dir="$HOME/.ccs/.claude"
504
+ local user_claude_dir="$HOME/.claude"
505
+
506
+ echo -e "${CYAN}Syncing delegation commands and skills to ~/.claude/...${RESET}"
507
+ echo ""
508
+
509
+ # Check if source directory exists
510
+ if [[ ! -d "$ccs_claude_dir" ]]; then
511
+ msg_error "CCS .claude/ directory not found at $ccs_claude_dir"
512
+ echo "Reinstall CCS: npm install -g @kaitranntt/ccs --force"
513
+ exit 1
514
+ fi
515
+
516
+ # Create ~/.claude/ if missing
517
+ if [[ ! -d "$user_claude_dir" ]]; then
518
+ echo -e "${CYAN}[i]${RESET} Creating ~/.claude/ directory"
519
+ mkdir -p "$user_claude_dir"
520
+ chmod 700 "$user_claude_dir"
521
+ fi
522
+
523
+ # Items to symlink (source:target:type)
524
+ local items=(
525
+ "commands/ccs:commands/ccs:dir"
526
+ "skills/ccs-delegation:skills/ccs-delegation:dir"
527
+ "agents/ccs-delegator.md:agents/ccs-delegator.md:file"
528
+ )
529
+
530
+ local installed=0
531
+ local skipped=0
532
+
533
+ for item in "${items[@]}"; do
534
+ IFS=':' read -r source target type <<< "$item"
535
+ local source_path="$ccs_claude_dir/$source"
536
+ local target_path="$user_claude_dir/$target"
537
+ local target_dir="$(dirname "$target_path")"
538
+
539
+ # Check source exists
540
+ if [[ ! -e "$source_path" ]]; then
541
+ echo -e "${YELLOW}[!]${RESET} Source not found: $source, skipping"
542
+ continue
543
+ fi
544
+
545
+ # Create parent directory if needed
546
+ if [[ ! -d "$target_dir" ]]; then
547
+ mkdir -p "$target_dir"
548
+ chmod 700 "$target_dir"
549
+ fi
550
+
551
+ # Check if already correct symlink
552
+ if [[ -L "$target_path" ]]; then
553
+ local link_target="$(readlink "$target_path")"
554
+ local resolved_target="$(cd "$(dirname "$target_path")" && cd "$(dirname "$link_target")" && pwd)/$(basename "$link_target")"
555
+
556
+ if [[ "$resolved_target" == "$source_path" ]]; then
557
+ ((skipped++))
558
+ continue
559
+ fi
560
+ fi
561
+
562
+ # Backup existing file/directory
563
+ if [[ -e "$target_path" ]]; then
564
+ local timestamp="$(date +%Y-%m-%d)"
565
+ local backup_path="${target_path}.backup-${timestamp}"
566
+ local counter=1
567
+
568
+ while [[ -e "$backup_path" ]]; do
569
+ backup_path="${target_path}.backup-${timestamp}-${counter}"
570
+ ((counter++))
571
+ done
572
+
573
+ mv "$target_path" "$backup_path"
574
+ echo -e "${CYAN}[i]${RESET} Backed up existing to $(basename "$backup_path")"
575
+ fi
576
+
577
+ # Create symlink
578
+ ln -s "$source_path" "$target_path" 2>/dev/null
579
+ if [[ $? -eq 0 ]]; then
580
+ echo -e "${GREEN}[OK]${RESET} Installed $target"
581
+ ((installed++))
582
+ else
583
+ echo -e "${RED}[X]${RESET} Failed to install $target"
584
+ fi
585
+ done
586
+
587
+ echo ""
588
+ echo -e "${GREEN}✓ Update complete${RESET}"
589
+ echo " Installed: $installed"
590
+ echo " Already up-to-date: $skipped"
591
+ echo ""
592
+ }
593
+
492
594
  # --- Claude CLI Detection Logic ---
493
595
 
494
596
  detect_claude_cli() {
@@ -518,49 +620,81 @@ Restart your terminal after installation."
518
620
  }
519
621
 
520
622
  show_version() {
623
+ # Title
521
624
  echo -e "${BOLD}CCS (Claude Code Switch) v${CCS_VERSION}${RESET}"
522
625
  echo ""
626
+
627
+ # Installation section with table-like formatting
523
628
  echo -e "${CYAN}Installation:${RESET}"
524
629
 
525
- # Simple location - just show what 'command -v' returns
526
- local location=$(command -v ccs 2>/dev/null || echo "(not installed)")
527
- echo -e " ${CYAN}Location:${RESET} ${location}"
528
-
529
- # Simple config display
530
- local config="${CCS_CONFIG:-$HOME/.ccs/config.json}"
531
- echo -e " ${CYAN}Config:${RESET} ${config}"
532
-
533
- # Delegation status
534
- local delegation_rules="$HOME/.ccs/delegation-rules.json"
535
- if [[ -f "$delegation_rules" ]]; then
536
- echo -e " ${CYAN}Delegation:${RESET} Enabled"
537
-
538
- # Check which profiles are delegation-ready
539
- local ready_profiles=()
540
- for profile in glm kimi; do
541
- local settings_file="$HOME/.ccs/profiles/$profile/settings.json"
542
- if [[ -f "$settings_file" ]]; then
543
- # Check if API key is configured (not a placeholder)
544
- local api_key=$(jq -r '.env.ANTHROPIC_AUTH_TOKEN // empty' "$settings_file" 2>/dev/null)
545
- if [[ -n "$api_key" ]] && [[ ! "$api_key" =~ YOUR_.*_API_KEY_HERE ]]; then
546
- ready_profiles+=("$profile")
547
- fi
548
- fi
549
- done
630
+ # Location - prioritize script location over command location
631
+ local script_location="$(readlink -f "${BASH_SOURCE[0]}")"
632
+ local command_location=$(command -v ccs 2>/dev/null || echo "(not found)")
550
633
 
551
- if [[ ${#ready_profiles[@]} -gt 0 ]]; then
552
- echo -e " ${CYAN}Ready:${RESET} ${ready_profiles[*]}"
553
- else
554
- echo -e " ${CYAN}Ready:${RESET} None (configure profiles first)"
634
+ # Show script location if running from source
635
+ if [[ "$script_location" == *"ccs"* ]]; then
636
+ printf " ${CYAN}%-16s${RESET} %s\n" "Location:" "${script_location}"
637
+ else
638
+ printf " ${CYAN}%-16s${RESET} %s\n" "Location:" "${command_location}"
639
+ fi
640
+
641
+ # .ccs/ directory location
642
+ printf " ${CYAN}%-16s${RESET} %s\n" "CCS Directory:" "$HOME/.ccs/"
643
+
644
+ # Config path
645
+ printf " ${CYAN}%-16s${RESET} %s\n" "Config:" "${CONFIG_FILE}"
646
+
647
+ # Profiles.json location
648
+ printf " ${CYAN}%-16s${RESET} %s\n" "Profiles:" "${PROFILES_JSON}"
649
+
650
+ # Delegation status - check multiple indicators
651
+ local delegation_configured=false
652
+ local ready_profiles=()
653
+
654
+ # Check for delegation-sessions.json (primary indicator)
655
+ local delegation_sessions="$HOME/.ccs/delegation-sessions.json"
656
+ if [[ -f "$delegation_sessions" ]]; then
657
+ delegation_configured=true
658
+ fi
659
+
660
+ # Check for profiles with valid API keys (secondary indicator)
661
+ for profile in glm kimi; do
662
+ local settings_file="$HOME/.ccs/$profile.settings.json"
663
+ if [[ -f "$settings_file" ]]; then
664
+ # Check if API key is configured (not a placeholder)
665
+ local api_key=$(jq -r '.env.ANTHROPIC_AUTH_TOKEN // empty' "$settings_file" 2>/dev/null)
666
+ if [[ -n "$api_key" ]] && [[ ! "$api_key" =~ YOUR_.*_API_KEY_HERE ]] && [[ ! "$api_key" =~ sk-test.* ]]; then
667
+ ready_profiles+=("$profile")
668
+ delegation_configured=true
669
+ fi
555
670
  fi
671
+ done
672
+
673
+ if $delegation_configured; then
674
+ printf " ${CYAN}%-16s${RESET} %s\n" "Delegation:" "Enabled"
556
675
  else
557
- echo -e " ${CYAN}Delegation:${RESET} Not configured"
676
+ printf " ${CYAN}%-16s${RESET} %s\n" "Delegation:" "Not configured"
558
677
  fi
678
+
559
679
  echo ""
560
680
 
681
+ # Ready Profiles section - make it more prominent
682
+ if [[ ${#ready_profiles[@]} -gt 0 ]]; then
683
+ echo -e "${CYAN}Delegation Ready:${RESET}"
684
+ echo " ${YELLOW}✓${RESET} ${ready_profiles[*]} profiles are ready for delegation"
685
+ echo ""
686
+ elif $delegation_configured; then
687
+ echo -e "${CYAN}Delegation Ready:${RESET}"
688
+ echo " ${YELLOW}!${RESET} Delegation configured but no valid API keys found"
689
+ echo ""
690
+ fi
691
+
692
+ # Documentation
561
693
  echo -e "${CYAN}Documentation:${RESET} https://github.com/kaitranntt/ccs"
562
694
  echo -e "${CYAN}License:${RESET} MIT"
563
695
  echo ""
696
+
697
+ # Help hint
564
698
  echo -e "${YELLOW}Run 'ccs --help' for usage information${RESET}"
565
699
  }
566
700
 
@@ -966,7 +1100,7 @@ detect_profile_type() {
966
1100
  # --- Auth Commands (Phase 3) ---
967
1101
 
968
1102
  auth_help() {
969
- echo -e "${BOLD}CCS Account Management${RESET}"
1103
+ echo -e "${BOLD}CCS Concurrent Account Management${RESET}"
970
1104
  echo ""
971
1105
  echo -e "${CYAN}Usage:${RESET}"
972
1106
  echo -e " ${YELLOW}ccs auth${RESET} <command> [options]"
@@ -1518,7 +1652,7 @@ if [[ $# -gt 0 ]] && [[ "${1}" == "auth" ]]; then
1518
1652
  fi
1519
1653
 
1520
1654
  # Special case: shell completion installer
1521
- if [[ $# -gt 0 ]] && [[ "${1}" == "--shell-completion" ]]; then
1655
+ if [[ $# -gt 0 ]] && [[ "${1}" == "--shell-completion" || "${1}" == "-sc" ]]; then
1522
1656
  install_shell_completion "$@"
1523
1657
  exit $?
1524
1658
  fi
@@ -1529,6 +1663,12 @@ if [[ $# -gt 0 ]] && [[ "${1}" == "doctor" || "${1}" == "--doctor" ]]; then
1529
1663
  exit $?
1530
1664
  fi
1531
1665
 
1666
+ # Special case: sync command
1667
+ if [[ $# -gt 0 ]] && [[ "${1}" == "sync" || "${1}" == "--sync" ]]; then
1668
+ sync_run
1669
+ exit $?
1670
+ fi
1671
+
1532
1672
  # Run auto-recovery before main logic
1533
1673
  auto_recover || {
1534
1674
  msg_error "Auto-recovery failed. Check permissions."