@kaitranntt/ccs 2.4.4 → 2.4.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,18 +2,23 @@
2
2
  set -euo pipefail
3
3
 
4
4
  # Version (updated by scripts/bump-version.sh)
5
- CCS_VERSION="2.4.4"
5
+ CCS_VERSION="2.4.5"
6
6
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ readonly CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}"
7
8
 
8
9
  # --- Color/Format Functions ---
9
10
  setup_colors() {
10
- if [[ -t 2 ]] && [[ -z "${NO_COLOR:-}" ]]; then
11
+ # Enable colors if: FORCE_COLOR set OR (TTY detected AND NO_COLOR not set) OR (TERM supports colors AND NO_COLOR not set)
12
+ if [[ -n "${FORCE_COLOR:-}" ]] || \
13
+ ([[ -t 1 || -t 2 ]] && [[ -z "${NO_COLOR:-}" ]]) || \
14
+ ([[ -n "${TERM:-}" && "${TERM}" != "dumb" ]] && [[ -z "${NO_COLOR:-}" ]]); then
11
15
  RED='\033[0;31m'
12
16
  YELLOW='\033[1;33m'
17
+ CYAN='\033[0;36m'
13
18
  BOLD='\033[1m'
14
19
  RESET='\033[0m'
15
20
  else
16
- RED='' YELLOW='' BOLD='' RESET=''
21
+ RED='' YELLOW='' CYAN='' BOLD='' RESET=''
17
22
  fi
18
23
  }
19
24
 
@@ -27,27 +32,72 @@ msg_error() {
27
32
  echo "" >&2
28
33
  }
29
34
 
35
+ show_help() {
36
+ echo -e "${BOLD}CCS (Claude Code Switch) - Instant profile switching for Claude CLI${RESET}"
37
+ echo ""
38
+ echo -e "${CYAN}Usage:${RESET}"
39
+ echo -e " ${YELLOW}ccs${RESET} [profile] [claude-args...]"
40
+ echo -e " ${YELLOW}ccs${RESET} [flags]"
41
+ echo ""
42
+ echo -e "${CYAN}Description:${RESET}"
43
+ echo -e " Switch between Claude models instantly. Stop hitting rate limits."
44
+ echo -e " Maps profile names to Claude settings files via ~/.ccs/config.json"
45
+ echo ""
46
+ echo -e "${CYAN}Profile Switching:${RESET}"
47
+ echo -e " ${YELLOW}ccs${RESET} Use default profile"
48
+ echo -e " ${YELLOW}ccs glm${RESET} Switch to GLM profile"
49
+ echo -e " ${YELLOW}ccs glm${RESET} \"debug this code\" Switch to GLM and run command"
50
+ echo -e " ${YELLOW}ccs glm${RESET} --verbose Switch to GLM with Claude flags"
51
+ echo ""
52
+ echo -e "${CYAN}Flags:${RESET}"
53
+ echo -e " ${YELLOW}-h, --help${RESET} Show this help message"
54
+ echo -e " ${YELLOW}-v, --version${RESET} Show version and installation info"
55
+ echo -e " ${YELLOW}--install${RESET} Install CCS commands to Claude CLI"
56
+ echo -e " ${YELLOW}--uninstall${RESET} Remove CCS commands from Claude CLI"
57
+ echo ""
58
+ echo -e "${CYAN}Configuration:${RESET}"
59
+ echo -e " Config File: ~/.ccs/config.json"
60
+ echo -e " Settings: ~/.ccs/*.settings.json"
61
+ echo -e " Environment: CCS_CONFIG (override config path)"
62
+ echo ""
63
+ echo -e "${CYAN}Examples:${RESET}"
64
+ echo -e " # Use default Claude subscription"
65
+ echo -e " ${YELLOW}ccs${RESET} \"Review this architecture\""
66
+ echo ""
67
+ echo -e " # Switch to GLM for cost-effective tasks"
68
+ echo -e " ${YELLOW}ccs glm${RESET} \"Write unit tests\""
69
+ echo ""
70
+ echo -e " # Use GLM with verbose output"
71
+ echo -e " ${YELLOW}ccs glm${RESET} --verbose \"Debug error\""
72
+ echo ""
73
+ echo -e " # Install CCS task delegation"
74
+ echo -e " ${YELLOW}ccs${RESET} --install"
75
+ echo ""
76
+ echo -e "${YELLOW}Uninstall:${RESET}"
77
+ echo -e " macOS/Linux: curl -fsSL ccs.kaitran.ca/uninstall | bash"
78
+ echo -e " Windows: irm ccs.kaitran.ca/uninstall | iex"
79
+ echo -e " npm: npm uninstall -g @kaitranntt/ccs"
80
+ echo ""
81
+ echo -e "${CYAN}Documentation:${RESET}"
82
+ echo -e " GitHub: ${CYAN}https://github.com/kaitranntt/ccs${RESET}"
83
+ echo -e " Docs: https://github.com/kaitranntt/ccs/blob/main/README.md"
84
+ echo -e " Issues: https://github.com/kaitranntt/ccs/issues"
85
+ echo ""
86
+ echo -e "${CYAN}License:${RESET} MIT"
87
+ }
88
+
30
89
  setup_colors
31
90
 
91
+ # Check dependencies early
92
+ command -v jq &>/dev/null || {
93
+ msg_error "jq required but not installed. Install: brew install jq (macOS) or apt install jq (Ubuntu)"
94
+ exit 1
95
+ }
96
+
32
97
  # --- Claude CLI Detection Logic ---
33
98
 
34
99
  detect_claude_cli() {
35
- # Priority 1: CCS_CLAUDE_PATH environment variable (if user wants custom path)
36
- if [[ -n "${CCS_CLAUDE_PATH:-}" ]]; then
37
- # Basic validation: file exists
38
- if [[ -f "$CCS_CLAUDE_PATH" ]]; then
39
- echo "$CCS_CLAUDE_PATH"
40
- return 0
41
- fi
42
- # Invalid CCS_CLAUDE_PATH - show warning and fall back to PATH
43
- echo "[!] Warning: CCS_CLAUDE_PATH is set but file not found: $CCS_CLAUDE_PATH" >&2
44
- echo " Falling back to system PATH lookup..." >&2
45
- fi
46
-
47
- # Priority 2: Use 'claude' from PATH (trust the system)
48
- # This is the standard case - if user installed Claude CLI, it's in their PATH
49
- echo "claude"
50
- return 0
100
+ echo "${CCS_CLAUDE_PATH:-claude}"
51
101
  }
52
102
 
53
103
  show_claude_not_found_error() {
@@ -72,8 +122,6 @@ Solutions:
72
122
  Restart your terminal after installation."
73
123
  }
74
124
 
75
- CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}"
76
-
77
125
  # Installation function for commands and skills
78
126
  install_commands_and_skills() {
79
127
  # Try both possible locations for .claude directory
@@ -261,35 +309,37 @@ uninstall_commands_and_skills() {
261
309
  echo "To reinstall: ccs --install"
262
310
  }
263
311
 
312
+ show_version() {
313
+ echo -e "${BOLD}CCS (Claude Code Switch) v${CCS_VERSION}${RESET}"
314
+ echo ""
315
+ echo -e "${CYAN}Installation:${RESET}"
316
+
317
+ # Simple location - just show what 'command -v' returns
318
+ local location=$(command -v ccs 2>/dev/null || echo "(not installed)")
319
+ echo -e " ${CYAN}Location:${RESET} ${location}"
320
+
321
+ # Simple config display
322
+ local config="${CCS_CONFIG:-$HOME/.ccs/config.json}"
323
+ echo -e " ${CYAN}Config:${RESET} ${config}"
324
+ echo ""
325
+
326
+ echo -e "${CYAN}Documentation:${RESET} https://github.com/kaitranntt/ccs"
327
+ echo -e "${CYAN}License:${RESET} MIT"
328
+ echo ""
329
+ echo -e "${YELLOW}Run 'ccs --help' for usage information${RESET}"
330
+ }
331
+
264
332
  # Special case: version command (check BEFORE profile detection)
265
333
  if [[ $# -gt 0 ]] && [[ "${1}" == "version" || "${1}" == "--version" || "${1}" == "-v" ]]; then
266
- echo "CCS (Claude Code Switch) version $CCS_VERSION"
267
-
268
- # Show install location if we can determine it
269
- INSTALL_LOCATION=$(command -v ccs 2>/dev/null || echo "unknown")
270
- if [[ "$INSTALL_LOCATION" != "unknown" ]]; then
271
- # Resolve symlink to actual file
272
- if [[ -L "$INSTALL_LOCATION" ]]; then
273
- ACTUAL_LOCATION=$(readlink "$INSTALL_LOCATION" 2>/dev/null || echo "$INSTALL_LOCATION")
274
- echo "Installed at: $INSTALL_LOCATION -> $ACTUAL_LOCATION"
275
- else
276
- echo "Installed at: $INSTALL_LOCATION"
277
- fi
278
- fi
279
-
280
- echo "https://github.com/kaitranntt/ccs"
334
+ show_version
281
335
  exit 0
282
336
  fi
283
337
 
284
338
  # Special case: help command (check BEFORE profile detection)
285
339
  if [[ $# -gt 0 ]] && [[ "${1}" == "--help" || "${1}" == "-h" || "${1}" == "help" ]]; then
286
- shift # Remove the help argument
287
- CLAUDE_CLI=$(detect_claude_cli)
288
-
289
- if ! exec "$CLAUDE_CLI" --help "$@"; then
290
- show_claude_not_found_error
291
- exit 1
292
- fi
340
+ setup_colors
341
+ show_help
342
+ exit 0
293
343
  fi
294
344
 
295
345
  # Special case: install command (check BEFORE profile detection)
@@ -334,16 +384,6 @@ EOF"
334
384
  exit 1
335
385
  fi
336
386
 
337
- # Check jq installed
338
- if ! command -v jq &> /dev/null; then
339
- msg_error "jq is required but not installed
340
-
341
- Install jq:
342
- macOS: brew install jq
343
- Ubuntu: sudo apt install jq
344
- Fedora: sudo dnf install jq"
345
- exit 1
346
- fi
347
387
 
348
388
  # Validate profile name (alphanumeric, dash, underscore only)
349
389
  if [[ "$PROFILE" =~ [^a-zA-Z0-9_-] ]]; then
@@ -353,34 +393,30 @@ Use only alphanumeric characters, dash, or underscore."
353
393
  exit 1
354
394
  fi
355
395
 
356
- # Validate JSON syntax
357
- if ! jq -e . "$CONFIG_FILE" &>/dev/null; then
358
- msg_error "Invalid JSON in $CONFIG_FILE
396
+ # Single check gets profile path, validates JSON + structure in one step
397
+ SETTINGS_PATH=$(jq -r --arg profile "$PROFILE" '.profiles[$profile] // empty' "$CONFIG_FILE" 2>/dev/null)
398
+
399
+ if [[ -z "$SETTINGS_PATH" ]]; then
400
+ # Could be: invalid JSON, no profiles object, or profile not found
401
+ # Show helpful error based on what we can detect
402
+ if ! jq -e . "$CONFIG_FILE" &>/dev/null; then
403
+ msg_error "Invalid JSON in $CONFIG_FILE
359
404
 
360
405
  Fix the JSON syntax or reinstall:
361
406
  curl -fsSL ccs.kaitran.ca/install | bash"
362
- exit 1
363
- fi
364
-
365
- # Validate config has profiles object
366
- if ! jq -e '.profiles' "$CONFIG_FILE" &>/dev/null; then
367
- msg_error "Config must have 'profiles' object
407
+ elif ! jq -e '.profiles' "$CONFIG_FILE" &>/dev/null; then
408
+ msg_error "Config must have 'profiles' object
368
409
 
369
410
  See config/config.example.json for correct format
370
411
  Or reinstall:
371
412
  curl -fsSL ccs.kaitran.ca/install | bash"
372
- exit 1
373
- fi
374
-
375
- # Get settings path for profile (using --arg to prevent injection)
376
- SETTINGS_PATH=$(jq -r --arg profile "$PROFILE" '.profiles[$profile] // empty' "$CONFIG_FILE")
377
-
378
- if [[ -z "$SETTINGS_PATH" ]]; then
379
- AVAILABLE_PROFILES=$(jq -r '.profiles | keys[]' "$CONFIG_FILE" 2>/dev/null | sed 's/^/ - /')
380
- msg_error "Profile '$PROFILE' not found in $CONFIG_FILE
413
+ else
414
+ AVAILABLE_PROFILES=$(jq -r '.profiles | keys[]' "$CONFIG_FILE" 2>/dev/null | sed 's/^/ - /')
415
+ msg_error "Profile '$PROFILE' not found in $CONFIG_FILE
381
416
 
382
417
  Available profiles:
383
418
  $AVAILABLE_PROFILES"
419
+ fi
384
420
  exit 1
385
421
  fi
386
422