@kaitranntt/ccs 2.4.4 → 2.4.6

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.ps1 CHANGED
@@ -3,9 +3,8 @@
3
3
  # https://github.com/kaitranntt/ccs
4
4
 
5
5
  param(
6
- [Parameter(Position=0)]
7
- [string]$ProfileOrFlag = "default",
8
-
6
+ [switch]$Help,
7
+ [switch]$Version,
9
8
  [Parameter(ValueFromRemainingArguments=$true)]
10
9
  [string[]]$RemainingArgs
11
10
  )
@@ -16,419 +15,295 @@ $ErrorActionPreference = "Stop"
16
15
  function Write-ErrorMsg {
17
16
  param([string]$Message)
18
17
  Write-Host ""
19
- Write-Host "╔═════════════════════════════════════════════╗" -ForegroundColor Red
20
- Write-Host " ERROR" -ForegroundColor Red
21
- Write-Host "╚═════════════════════════════════════════════╝" -ForegroundColor Red
18
+ Write-Host "=============================================" -ForegroundColor Red
19
+ Write-Host " ERROR" -ForegroundColor Red
20
+ Write-Host "=============================================" -ForegroundColor Red
22
21
  Write-Host ""
23
22
  Write-Host $Message -ForegroundColor Red
24
23
  Write-Host ""
25
24
  }
26
25
 
27
- # --- Claude CLI Detection Logic ---
26
+ function Write-ColoredText {
27
+ param(
28
+ [string]$Text,
29
+ [string]$Color = "White",
30
+ [switch]$NoNewline
31
+ )
28
32
 
29
- function Find-ClaudeCli {
30
- [OutputType([string])]
31
- param()
32
-
33
- # Priority 1: CCS_CLAUDE_PATH environment variable (if user wants custom path)
34
- $CcsClaudePath = $env:CCS_CLAUDE_PATH
35
- if ($CcsClaudePath) {
36
- # Basic validation: file exists
37
- if (Test-Path $CcsClaudePath -PathType Leaf) {
38
- return $CcsClaudePath
33
+ $UseColors = $env:FORCE_COLOR -or ([Console]::IsOutputRedirected -eq $false -and -not $env:NO_COLOR)
34
+
35
+ if ($UseColors -and $Color) {
36
+ if ($NoNewline) {
37
+ Write-Host $Text -ForegroundColor $Color -NoNewline
38
+ } else {
39
+ Write-Host $Text -ForegroundColor $Color
40
+ }
41
+ } else {
42
+ if ($NoNewline) {
43
+ Write-Host $Text -NoNewline
44
+ } else {
45
+ Write-Host $Text
39
46
  }
40
- # Invalid CCS_CLAUDE_PATH - show warning and fall back to PATH
41
- Write-Host "[!] Warning: CCS_CLAUDE_PATH is set but file not found: $CcsClaudePath" -ForegroundColor Yellow
42
- Write-Host " Falling back to system PATH lookup..." -ForegroundColor Yellow
43
47
  }
44
-
45
- # Priority 2: Use 'claude' from PATH (trust the system)
46
- # This is the standard case - if user installed Claude CLI, it's in their PATH
47
- return "claude"
48
48
  }
49
49
 
50
- function Show-ClaudeNotFoundError {
51
- Write-ErrorMsg @"
52
- Claude CLI not found in PATH
53
-
54
- CCS requires Claude CLI to be installed and available in your PATH.
50
+ # --- Claude CLI Detection Logic ---
55
51
 
56
- Solutions:
57
- 1. Install Claude CLI:
58
- https://docs.claude.com/en/docs/claude-code/installation
52
+ function Find-ClaudeCli {
53
+ if ($env:CCS_CLAUDE_PATH) {
54
+ return $env:CCS_CLAUDE_PATH
55
+ } else {
56
+ return "claude"
57
+ }
58
+ }
59
59
 
60
- 2. Verify installation:
61
- Get-Command claude
60
+ function Show-ClaudeNotFoundError {
61
+ $Message = "Claude CLI not found in PATH" + "`n`n" +
62
+ "CCS requires Claude CLI to be installed and available in your PATH." + "`n`n" +
63
+ "Solutions:" + "`n" +
64
+ " 1. Install Claude CLI:" + "`n" +
65
+ " https://docs.claude.com/en/docs/claude-code/installation" + "`n`n" +
66
+ " 2. Verify installation:" + "`n" +
67
+ " Get-Command claude" + "`n`n" +
68
+ " 3. If installed but not in PATH, add it:" + "`n" +
69
+ " # Find Claude installation" + "`n" +
70
+ " where.exe claude" + "`n`n" +
71
+ " # Or set custom path" + "`n" +
72
+ " `$env:CCS_CLAUDE_PATH = 'C:\path\to\claude.exe'" + "`n`n" +
73
+ "Restart your terminal after installation."
74
+
75
+ Write-ErrorMsg $Message
76
+ }
62
77
 
63
- 3. If installed but not in PATH, add it:
64
- # Find Claude installation
65
- where.exe claude
78
+ function Show-Help {
79
+ $UseColors = $env:FORCE_COLOR -or ([Console]::IsOutputRedirected -eq $false -and -not $env:NO_COLOR)
66
80
 
67
- # Or set custom path
68
- `$env:CCS_CLAUDE_PATH = 'C:\path\to\claude.exe'
81
+ # Helper for colored output
82
+ function Write-ColorLine {
83
+ param([string]$Text, [string]$Color = "White")
84
+ if ($UseColors) { Write-Host $Text -ForegroundColor $Color }
85
+ else { Write-Host $Text }
86
+ }
69
87
 
70
- Restart your terminal after installation.
71
- "@
88
+ Write-ColorLine "CCS (Claude Code Switch) - Instant profile switching for Claude CLI" "White"
89
+ Write-Host ""
90
+ Write-ColorLine "Usage:" "Cyan"
91
+ Write-ColorLine " ccs [profile] [claude-args...]" "Yellow"
92
+ Write-ColorLine " ccs [flags]" "Yellow"
93
+ Write-Host ""
94
+ Write-ColorLine "Description:" "Cyan"
95
+ Write-Host " Switch between Claude models instantly. Stop hitting rate limits."
96
+ Write-Host " Maps profile names to Claude settings files via ~/.ccs/config.json"
97
+ Write-Host ""
98
+ Write-ColorLine "Profile Switching:" "Cyan"
99
+ Write-ColorLine " ccs Use default profile" "Yellow"
100
+ Write-ColorLine " ccs glm Switch to GLM profile" "Yellow"
101
+ Write-ColorLine " ccs glm 'debug this code' Switch to GLM and run command" "Yellow"
102
+ Write-ColorLine " ccs glm --verbose Switch to GLM with Claude flags" "Yellow"
103
+ Write-Host ""
104
+ Write-ColorLine "Flags:" "Cyan"
105
+ Write-ColorLine " -h, --help Show this help message" "Yellow"
106
+ Write-ColorLine " -v, --version Show version and installation info" "Yellow"
107
+ Write-Host ""
108
+ Write-ColorLine "Configuration:" "Cyan"
109
+ Write-Host " Config File: ~/.ccs/config.json"
110
+ Write-Host " Settings: ~/.ccs/*.settings.json"
111
+ Write-Host " Environment: CCS_CONFIG (override config path)"
112
+ Write-Host ""
113
+ Write-ColorLine "Examples:" "Cyan"
114
+ Write-Host " # Use default Claude subscription"
115
+ Write-ColorLine " ccs 'Review this architecture'" "Yellow"
116
+ Write-Host ""
117
+ Write-Host " # Switch to GLM for cost-effective tasks"
118
+ Write-ColorLine " ccs glm 'Write unit tests'" "Yellow"
119
+ Write-Host ""
120
+ Write-Host " # Use GLM with verbose output"
121
+ Write-ColorLine " ccs glm --verbose 'Debug error'" "Yellow"
122
+ Write-Host ""
123
+ Write-ColorLine "Uninstall:" "Cyan"
124
+ Write-Host " macOS/Linux: curl -fsSL ccs.kaitran.ca/uninstall | bash"
125
+ Write-Host " Windows: irm ccs.kaitran.ca/uninstall | iex"
126
+ Write-Host " npm: npm uninstall -g @kaitranntt/ccs"
127
+ Write-Host ""
128
+ Write-ColorLine "Documentation:" "Cyan"
129
+ Write-Host " GitHub: https://github.com/kaitranntt/ccs"
130
+ Write-Host " Docs: https://github.com/kaitranntt/ccs/blob/main/README.md"
131
+ Write-Host " Issues: https://github.com/kaitranntt/ccs/issues"
132
+ Write-Host ""
133
+ Write-ColorLine "License: MIT" "Cyan"
72
134
  }
73
135
 
74
136
  # Version (updated by scripts/bump-version.sh)
75
- $CcsVersion = "2.4.4"
137
+ $CcsVersion = "2.4.6"
76
138
  $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
139
+ $ConfigFile = if ($env:CCS_CONFIG) { $env:CCS_CONFIG } else { "$env:USERPROFILE\.ccs\config.json" }
77
140
 
78
- # Installation function for commands and skills
79
- function Install-CommandsAndSkills {
80
- # Try both possible locations for .claude directory
81
- $SourceDir = $null
82
- $PossibleDirs = @(
83
- (Join-Path $ScriptDir ".claude"), # Development: tools/ccs/.claude
84
- (Join-Path $env:USERPROFILE ".ccs\.claude") # Installed: ~/.ccs/.claude
85
- )
141
+ function Show-Version {
142
+ $UseColors = $env:FORCE_COLOR -or ([Console]::IsOutputRedirected -eq $false -and -not $env:NO_COLOR)
86
143
 
87
- foreach ($Dir in $PossibleDirs) {
88
- if (Test-Path $Dir) {
89
- $SourceDir = $Dir
90
- break
91
- }
92
- }
93
-
94
- $HomeDir = if ($env:HOME) { $env:HOME } else { $env:USERPROFILE }
95
- $TargetDir = Join-Path $HomeDir ".claude"
96
-
97
- Write-Host "[Installing CCS Commands and Skills]" -ForegroundColor Cyan
98
- Write-Host "│ Source: $SourceDir"
99
- Write-Host "│ Target: $TargetDir"
100
- Write-Host "│"
101
-
102
- # Check if source directory exists
103
- if (-not $SourceDir) {
104
- Write-Host "│"
105
- $DevelopmentPath = Join-Path $ScriptDir ".claude"
106
- $InstalledPath = Join-Path $env:USERPROFILE ".ccs\.claude"
107
- Write-ErrorMsg @"
108
- Source directory not found.
109
-
110
- Checked locations:
111
- - $DevelopmentPath (development)
112
- - $InstalledPath (installed)
113
-
114
- Solution:
115
- 1. If developing: Ensure you're in the CCS repository
116
- 2. If installed: Reinstall CCS with: irm ccs.kaitran.ca/install | iex
117
- "@
118
- exit 1
144
+ # Title
145
+ if ($UseColors) {
146
+ Write-Host "CCS (Claude Code Switch) v$CcsVersion" -ForegroundColor White
147
+ } else {
148
+ Write-Host "CCS (Claude Code Switch) v$CcsVersion"
119
149
  }
150
+ Write-Host ""
120
151
 
121
- # Create target directories if they don't exist
122
- $CommandsDir = Join-Path $TargetDir "commands"
123
- $SkillsDir = Join-Path $TargetDir "skills"
152
+ # Installation
153
+ if ($UseColors) { Write-Host "Installation:" -ForegroundColor Cyan }
154
+ else { Write-Host "Installation:" }
124
155
 
125
- if (-not (Test-Path $CommandsDir)) {
126
- New-Item -ItemType Directory -Path $CommandsDir -Force | Out-Null
127
- }
128
- if (-not (Test-Path $SkillsDir)) {
129
- New-Item -ItemType Directory -Path $SkillsDir -Force | Out-Null
130
- }
131
-
132
- $InstalledCount = 0
133
- $SkippedCount = 0
134
-
135
- # Install commands
136
- $SourceCommandsDir = Join-Path $SourceDir "commands"
137
- if (Test-Path $SourceCommandsDir) {
138
- Write-Host "│ Installing commands..." -ForegroundColor Yellow
139
- Get-ChildItem $SourceCommandsDir -Filter "*.md" | ForEach-Object {
140
- $CmdName = $_.BaseName
141
- $TargetFile = Join-Path $CommandsDir "$CmdName.md"
142
-
143
- if (Test-Path $TargetFile) {
144
- Write-Host "│ | [i] Skipping existing command: $CmdName.md" -ForegroundColor Yellow
145
- $SkippedCount++
146
- } else {
147
- try {
148
- Copy-Item $_.FullName $TargetFile -ErrorAction Stop
149
- Write-Host "│ | [OK] Installed command: $CmdName.md" -ForegroundColor Green
150
- $InstalledCount++
151
- } catch {
152
- Write-Host "│ | [!] Failed to install command: $CmdName.md" -ForegroundColor Red
153
- Write-Host "│ Error: $($_.Exception.Message)" -ForegroundColor Red
154
- }
155
- }
156
+ # Location
157
+ $InstallLocation = (Get-Command ccs -ErrorAction SilentlyContinue).Source
158
+ if ($InstallLocation) {
159
+ if ($UseColors) {
160
+ Write-Host " Location: " -ForegroundColor Cyan -NoNewline
161
+ Write-Host $InstallLocation
162
+ } else {
163
+ Write-Host " Location: $InstallLocation"
156
164
  }
157
165
  } else {
158
- Write-Host "│ [i] No commands directory found" -ForegroundColor Gray
166
+ if ($UseColors) {
167
+ Write-Host " Location: " -ForegroundColor Cyan -NoNewline
168
+ Write-Host "(not found - run from current directory)" -ForegroundColor Gray
169
+ } else {
170
+ Write-Host " Location: (not found - run from current directory)"
171
+ }
159
172
  }
160
173
 
161
- Write-Host "│"
162
-
163
- # Install skills
164
- $SourceSkillsDir = Join-Path $SourceDir "skills"
165
- if (Test-Path $SourceSkillsDir) {
166
- Write-Host "│ Installing skills..." -ForegroundColor Yellow
167
- Get-ChildItem $SourceSkillsDir -Directory | ForEach-Object {
168
- $SkillName = $_.Name
169
- $TargetSkillDir = Join-Path $SkillsDir $SkillName
170
-
171
- if (Test-Path $TargetSkillDir) {
172
- Write-Host "│ | [i] Skipping existing skill: $SkillName" -ForegroundColor Yellow
173
- $SkippedCount++
174
- } else {
175
- try {
176
- Copy-Item $_.FullName $TargetSkillDir -Recurse -ErrorAction Stop
177
- Write-Host "│ | [OK] Installed skill: $SkillName" -ForegroundColor Green
178
- $InstalledCount++
179
- } catch {
180
- Write-Host "│ | [!] Failed to install skill: $SkillName" -ForegroundColor Red
181
- Write-Host "│ Error: $($_.Exception.Message)" -ForegroundColor Red
182
- }
183
- }
184
- }
174
+ # Config
175
+ if ($UseColors) {
176
+ Write-Host " Config: " -ForegroundColor Cyan -NoNewline
177
+ Write-Host $ConfigFile
185
178
  } else {
186
- Write-Host " [i] No skills directory found" -ForegroundColor Gray
179
+ Write-Host " Config: $ConfigFile"
187
180
  }
188
181
 
189
- Write-Host "[DONE]"
190
182
  Write-Host ""
191
- Write-Host "[OK] Installation complete!" -ForegroundColor Green
192
- Write-Host " Installed: $InstalledCount items"
193
- Write-Host " Skipped: $SkippedCount items (already exist)"
194
- Write-Host ""
195
- Write-Host "You can now use the /ccs command in Claude CLI for task delegation." -ForegroundColor Cyan
196
- Write-Host "Example: /ccs glm /plan 'add user authentication'" -ForegroundColor Cyan
197
- }
198
-
199
- # Uninstallation function for commands and skills
200
- function Uninstall-CommandsAndSkills {
201
- $HomeDir = if ($env:HOME) { $env:HOME } else { $env:USERPROFILE }
202
- $TargetDir = Join-Path $HomeDir ".claude"
203
- $RemovedCount = 0
204
- $NotFoundCount = 0
205
-
206
- Write-Host "[Uninstalling CCS Commands and Skills]" -ForegroundColor Cyan
207
- Write-Host "│ Target: $TargetDir"
208
- Write-Host "│"
209
-
210
- # Check if target directory exists
211
- if (-not (Test-Path $TargetDir)) {
212
- Write-Host "│"
213
- Write-Host "│ [i] Claude directory not found: $TargetDir" -ForegroundColor Gray
214
- Write-Host "│ Nothing to uninstall."
215
- Write-Host "[DONE]"
216
- Write-Host ""
217
- Write-Host "[OK] Uninstall complete!" -ForegroundColor Green
218
- Write-Host " Removed: 0 items (nothing was installed)"
219
- return
220
- }
221
183
 
222
- # Remove commands
223
- $CommandsDir = Join-Path $TargetDir "commands"
224
- if (Test-Path $CommandsDir) {
225
- Write-Host "│ Removing commands..." -ForegroundColor Yellow
226
- $CmdFile = Join-Path $CommandsDir "ccs.md"
227
- if (Test-Path $CmdFile) {
228
- try {
229
- Remove-Item $CmdFile -Force -ErrorAction Stop
230
- Write-Host "│ | [OK] Removed command: ccs.md" -ForegroundColor Green
231
- $RemovedCount++
232
- } catch {
233
- Write-Host "│ | [!] Failed to remove command: ccs.md" -ForegroundColor Red
234
- Write-Host "│ Error: $($_.Exception.Message)" -ForegroundColor Red
235
- }
236
- } else {
237
- Write-Host "│ | [i] CCS command not found" -ForegroundColor Gray
238
- $NotFoundCount++
239
- }
184
+ # Documentation
185
+ if ($UseColors) {
186
+ Write-Host "Documentation: https://github.com/kaitranntt/ccs" -ForegroundColor Cyan
187
+ Write-Host "License: MIT" -ForegroundColor Cyan
240
188
  } else {
241
- Write-Host "│ [i] Commands directory not found" -ForegroundColor Gray
242
- $NotFoundCount++
189
+ Write-Host "Documentation: https://github.com/kaitranntt/ccs"
190
+ Write-Host "License: MIT"
243
191
  }
192
+ Write-Host ""
244
193
 
245
- Write-Host "│"
246
-
247
- # Remove skills
248
- $SkillsDir = Join-Path $TargetDir "skills"
249
- if (Test-Path $SkillsDir) {
250
- Write-Host "│ Removing skills..." -ForegroundColor Yellow
251
- $SkillDir = Join-Path $SkillsDir "ccs-delegation"
252
- if (Test-Path $SkillDir) {
253
- try {
254
- Remove-Item $SkillDir -Recurse -Force -ErrorAction Stop
255
- Write-Host "│ | [OK] Removed skill: ccs-delegation" -ForegroundColor Green
256
- $RemovedCount++
257
- } catch {
258
- Write-Host "│ | [!] Failed to remove skill: ccs-delegation" -ForegroundColor Red
259
- Write-Host "│ Error: $($_.Exception.Message)" -ForegroundColor Red
260
- }
261
- } else {
262
- Write-Host "│ | [i] CCS skill not found" -ForegroundColor Gray
263
- $NotFoundCount++
264
- }
194
+ if ($UseColors) {
195
+ Write-Host "Run 'ccs --help' for usage information" -ForegroundColor Yellow
265
196
  } else {
266
- Write-Host "│ [i] Skills directory not found" -ForegroundColor Gray
267
- $NotFoundCount++
197
+ Write-Host "Run 'ccs --help' for usage information"
268
198
  }
269
-
270
- Write-Host "[DONE]"
271
- Write-Host ""
272
- Write-Host "[OK] Uninstall complete!" -ForegroundColor Green
273
- Write-Host " Removed: $RemovedCount items"
274
- Write-Host " Not found: $NotFoundCount items (already removed)"
275
- Write-Host ""
276
- Write-Host "The /ccs command is no longer available in Claude CLI." -ForegroundColor Cyan
277
- Write-Host "To reinstall: ccs --install" -ForegroundColor Cyan
278
199
  }
279
200
 
280
201
  # Special case: version command (check BEFORE profile detection)
281
- # Check both $ProfileOrFlag and first element of $RemainingArgs
282
- $FirstArg = if ($ProfileOrFlag -ne "default") { $ProfileOrFlag } elseif ($RemainingArgs.Count -gt 0) { $RemainingArgs[0] } else { $null }
283
- if ($FirstArg -eq "version" -or $FirstArg -eq "--version" -or $FirstArg -eq "-v") {
284
- Write-Host "CCS (Claude Code Switch) version $CcsVersion"
285
-
286
- # Show install location
287
- $InstallLocation = (Get-Command ccs -ErrorAction SilentlyContinue).Source
288
- if ($InstallLocation) {
289
- Write-Host "Installed at: $InstallLocation"
290
- }
291
-
292
- Write-Host "https://github.com/kaitranntt/ccs"
202
+ # Handle switch parameters and remaining arguments
203
+ if ($Version) {
204
+ Show-Version
293
205
  exit 0
206
+ } elseif ($RemainingArgs.Count -gt 0) {
207
+ $FirstArg = $RemainingArgs[0]
208
+ if ($FirstArg -eq "version" -or $FirstArg -eq "--version" -or $FirstArg -eq "-v") {
209
+ Show-Version
210
+ exit 0
211
+ }
294
212
  }
295
213
 
296
214
  # Special case: help command (check BEFORE profile detection)
297
- if ($FirstArg -eq "--help" -or $FirstArg -eq "-h" -or $FirstArg -eq "help") {
298
- $ClaudeCli = Find-ClaudeCli
299
-
300
- try {
301
- if ($RemainingArgs) {
302
- & $ClaudeCli --help @RemainingArgs
303
- } else {
304
- & $ClaudeCli --help
305
- }
306
- exit $LASTEXITCODE
307
- } catch {
308
- Show-ClaudeNotFoundError
309
- exit 1
215
+ if ($Help) {
216
+ Show-Help
217
+ exit 0
218
+ } elseif ($RemainingArgs.Count -gt 0) {
219
+ $FirstArg = $RemainingArgs[0]
220
+ if ($FirstArg -eq "--help" -or $FirstArg -eq "-h" -or $FirstArg -eq "help") {
221
+ Show-Help
222
+ exit 0
310
223
  }
311
224
  }
312
225
 
313
226
  # Special case: install command (check BEFORE profile detection)
314
227
  if ($FirstArg -eq "--install") {
315
- Install-CommandsAndSkills
316
- exit $LASTEXITCODE
228
+ Write-Host ""
229
+ Write-Host "Feature not available" -ForegroundColor Yellow
230
+ Write-Host ""
231
+ Write-Host "The --install flag is currently under development."
232
+ Write-Host ".claude/ integration testing is not complete."
233
+ Write-Host ""
234
+ Write-Host "For updates: https://github.com/kaitranntt/ccs/issues"
235
+ Write-Host ""
236
+ exit 0
317
237
  }
318
238
 
319
239
  # Special case: uninstall command (check BEFORE profile detection)
320
240
  if ($FirstArg -eq "--uninstall") {
321
- Uninstall-CommandsAndSkills
322
- exit $LASTEXITCODE
241
+ Write-Host ""
242
+ Write-Host "Feature not available" -ForegroundColor Yellow
243
+ Write-Host ""
244
+ Write-Host "The --uninstall flag is currently under development."
245
+ Write-Host ".claude/ integration testing is not complete."
246
+ Write-Host ""
247
+ Write-Host "For updates: https://github.com/kaitranntt/ccs/issues"
248
+ Write-Host ""
249
+ exit 0
323
250
  }
324
251
 
325
252
  # Smart profile detection: if first arg starts with '-', it's a flag not a profile
326
- if ($ProfileOrFlag -match '^-') {
327
- # First arg is a flag → use default profile, keep all args
253
+ if ($RemainingArgs.Count -eq 0 -or $RemainingArgs[0] -match '^-') {
254
+ # No args or first arg is a flag → use default profile
328
255
  $Profile = "default"
329
- # Prepend $ProfileOrFlag to $RemainingArgs (it's actually a flag, not a profile)
330
- if ($RemainingArgs) {
331
- $RemainingArgs = @($ProfileOrFlag) + $RemainingArgs
332
- } else {
333
- $RemainingArgs = @($ProfileOrFlag)
334
- }
256
+ # $RemainingArgs already contains the remaining args correctly
335
257
  } else {
336
258
  # First arg is a profile name
337
- $Profile = $ProfileOrFlag
338
- # $RemainingArgs already contains correct args (PowerShell handles this)
339
- }
340
-
341
- # Special case: "default" profile just runs claude directly (no profile switching)
342
- if ($Profile -eq "default") {
343
- try {
344
- if ($RemainingArgs) {
345
- & claude @RemainingArgs
346
- } else {
347
- & claude
348
- }
349
- exit $LASTEXITCODE
350
- } catch {
351
- Write-Host "Error: Failed to execute claude" -ForegroundColor Red
352
- Write-Host $_.Exception.Message
353
- exit 1
354
- }
355
- }
356
-
357
- # Config file location (supports environment variable override)
358
- $ConfigFile = if ($env:CCS_CONFIG) {
359
- $env:CCS_CONFIG
360
- } else {
361
- "$env:USERPROFILE\.ccs\config.json"
259
+ $Profile = $RemainingArgs[0]
260
+ $RemainingArgs = if ($RemainingArgs.Count -gt 1) { $RemainingArgs | Select-Object -Skip 1 } else { @() }
362
261
  }
363
262
 
364
263
  # Check config exists
365
264
  if (-not (Test-Path $ConfigFile)) {
366
- Write-ErrorMsg @"
367
- Config file not found: $ConfigFile
368
-
369
- Solutions:
370
- 1. Reinstall CCS:
371
- irm ccs.kaitran.ca/install | iex
372
-
373
- 2. Or create config manually:
374
- New-Item -ItemType Directory -Force -Path '$env:USERPROFILE\.ccs'
375
- Set-Content -Path '$env:USERPROFILE\.ccs\config.json' -Value '{
376
- "profiles": {
377
- "glm": "~/.ccs/glm.settings.json",
378
- "default": "~/.claude/settings.json"
379
- }
380
- }'
381
- "@
265
+ $ErrorMessage = "Config file not found: $ConfigFile" + "`n`n" +
266
+ "Solutions:" + "`n" +
267
+ " 1. Reinstall CCS:" + "`n" +
268
+ " irm ccs.kaitran.ca/install | iex" + "`n`n" +
269
+ " 2. Or create config manually:" + "`n" +
270
+ " New-Item -ItemType Directory -Force -Path '$env:USERPROFILE\.ccs'" + "`n" +
271
+ " Set-Content -Path '$env:USERPROFILE\.ccs\config.json' -Value '{`"profiles`":{`"glm`":`"~/.ccs/glm.settings.json`",`"default`":`"~/.claude/settings.json`"}}'"
272
+
273
+ Write-ErrorMsg $ErrorMessage
382
274
  exit 1
383
275
  }
384
276
 
385
277
  # Validate profile name (alphanumeric, dash, underscore only)
386
278
  if ($Profile -notmatch '^[a-zA-Z0-9_-]+$') {
387
- Write-ErrorMsg @"
388
- Invalid profile name: $Profile
279
+ $ErrorMessage = "Invalid profile name: $Profile" + "`n`n" +
280
+ "Use only alphanumeric characters, dash, or underscore."
389
281
 
390
- Use only alphanumeric characters, dash, or underscore.
391
- "@
282
+ Write-ErrorMsg $ErrorMessage
392
283
  exit 1
393
284
  }
394
285
 
395
- # Read and parse JSON config
286
+ # Read and parse JSON config, get profile path in one step
396
287
  try {
397
288
  $ConfigContent = Get-Content $ConfigFile -Raw -ErrorAction Stop
398
289
  $Config = $ConfigContent | ConvertFrom-Json -ErrorAction Stop
399
- } catch {
400
- Write-ErrorMsg @"
401
- Invalid JSON in $ConfigFile
402
-
403
- Fix the JSON syntax or reinstall:
404
- irm ccs.kaitran.ca/install | iex
405
- "@
406
- exit 1
407
- }
290
+ $SettingsPath = $Config.profiles.$Profile
408
291
 
409
- # Validate config has profiles object
410
- if (-not $Config.profiles) {
411
- Write-ErrorMsg @"
412
- Config must have 'profiles' object
292
+ if (-not $SettingsPath) {
293
+ $AvailableProfiles = ($Config.profiles.PSObject.Properties.Name | ForEach-Object { " - $_" }) -join "`n"
294
+ $ErrorMessage = "Profile '$Profile' not found in $ConfigFile" + "`n`n" +
295
+ "Available profiles:" + "`n" +
296
+ $AvailableProfiles
413
297
 
414
- See .ccs.example.json for correct format
415
- Or reinstall:
416
- irm ccs.kaitran.ca/install | iex
417
- "@
418
- exit 1
419
- }
420
-
421
- # Get settings path for profile
422
- $SettingsPath = $Config.profiles.$Profile
423
-
424
- if (-not $SettingsPath) {
425
- $AvailableProfiles = ($Config.profiles.PSObject.Properties.Name | ForEach-Object { " - $_" }) -join "`n"
426
- Write-ErrorMsg @"
427
- Profile '$Profile' not found in $ConfigFile
298
+ Write-ErrorMsg $ErrorMessage
299
+ exit 1
300
+ }
301
+ } catch {
302
+ $ErrorMessage = "Invalid JSON in $ConfigFile" + "`n`n" +
303
+ "Fix the JSON syntax or reinstall:" + "`n" +
304
+ " irm ccs.kaitran.ca/install | iex"
428
305
 
429
- Available profiles:
430
- $AvailableProfiles
431
- "@
306
+ Write-ErrorMsg $ErrorMessage
432
307
  exit 1
433
308
  }
434
309
 
@@ -446,33 +321,13 @@ $SettingsPath = $SettingsPath -replace '/', '\'
446
321
 
447
322
  # Validate settings file exists
448
323
  if (-not (Test-Path $SettingsPath)) {
449
- Write-ErrorMsg @"
450
- Settings file not found: $SettingsPath
451
-
452
- Solutions:
453
- 1. Create the settings file for profile '$Profile'
454
- 2. Update the path in $ConfigFile
455
- 3. Or reinstall: irm ccs.kaitran.ca/install | iex
456
- "@
457
- exit 1
458
- }
324
+ $ErrorMessage = "Settings file not found: $SettingsPath" + "`n`n" +
325
+ "Solutions:" + "`n" +
326
+ " 1. Create the settings file for profile '$Profile'" + "`n" +
327
+ " 2. Update the path in $ConfigFile" + "`n" +
328
+ " 3. Or reinstall: irm ccs.kaitran.ca/install | iex"
459
329
 
460
- # Validate settings file is valid JSON (basic check)
461
- try {
462
- $SettingsContent = Get-Content $SettingsPath -Raw -ErrorAction Stop
463
- $Settings = $SettingsContent | ConvertFrom-Json -ErrorAction Stop
464
- } catch {
465
- Write-ErrorMsg @"
466
- Invalid JSON in $SettingsPath
467
-
468
- Details: $_
469
-
470
- Solutions:
471
- 1. Validate JSON at https://jsonlint.com
472
- 2. Or reset to template:
473
- Set-Content -Path '$SettingsPath' -Value '{`"env`":{}}`'
474
- 3. Or reinstall: irm ccs.kaitran.ca/install | iex
475
- "@
330
+ Write-ErrorMsg $ErrorMessage
476
331
  exit 1
477
332
  }
478
333
 
@@ -490,4 +345,4 @@ try {
490
345
  } catch {
491
346
  Show-ClaudeNotFoundError
492
347
  exit 1
493
- }
348
+ }