@glidea/codex-switch 0.1.1 → 0.2.1

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/README.en.md CHANGED
@@ -52,14 +52,22 @@ Restart is required to load the new profile
52
52
  ## Common Commands
53
53
 
54
54
  ```bash
55
+ codex-switch <profile>
55
56
  codex-switch add <profile>
57
+ codex-switch current
58
+ codex-switch list
59
+ codex-switch edit <profile>
60
+ codex-switch rm <profile>
61
+ codex-switch completion
62
+ ```
63
+
64
+ Advanced commands
65
+
66
+ ```bash
56
67
  codex-switch add <profile> --from-current
57
68
  codex-switch add <profile> --config <path> --auth <path>
58
- codex-switch edit <profile>
59
- codex-switch <profile>
60
69
  codex-switch <profile> --copy
61
- codex-switch list
62
- codex-switch current
70
+ codex-switch completion <zsh|bash|fish|powershell>
63
71
  ```
64
72
 
65
73
  ## File Layout
package/README.md CHANGED
@@ -55,14 +55,22 @@ codex-switch glidea
55
55
  ## 常用命令
56
56
 
57
57
  ```bash
58
+ codex-switch <profile>
58
59
  codex-switch add <profile>
60
+ codex-switch current
61
+ codex-switch list
62
+ codex-switch edit <profile>
63
+ codex-switch rm <profile>
64
+ codex-switch completion
65
+ ```
66
+
67
+ 高级命令
68
+
69
+ ```bash
59
70
  codex-switch add <profile> --from-current
60
71
  codex-switch add <profile> --config <path> --auth <path>
61
- codex-switch edit <profile>
62
- codex-switch <profile>
63
72
  codex-switch <profile> --copy
64
- codex-switch list
65
- codex-switch current
73
+ codex-switch completion <zsh|bash|fish|powershell>
66
74
  ```
67
75
 
68
76
  ## 文件结构
@@ -15,7 +15,26 @@ function fail(message) {
15
15
  }
16
16
 
17
17
  function usage() {
18
- console.log("usage: codex-switch <profile>|add <profile>|edit <profile>|list|current [--copy]")
18
+ console.log(
19
+ "usage: codex-switch <profile>|add <profile>|edit <profile>|rm <profile>|list|current|completion [zsh|bash|fish|powershell] [--copy]"
20
+ )
21
+ }
22
+
23
+ function help() {
24
+ usage()
25
+ console.log("")
26
+ console.log("commands:")
27
+ console.log(" codex-switch <profile>")
28
+ console.log(" codex-switch <profile> --copy")
29
+ console.log(" codex-switch add <profile>")
30
+ console.log(" codex-switch add <profile> --from-current")
31
+ console.log(" codex-switch add <profile> --config <path> --auth <path>")
32
+ console.log(" codex-switch edit <profile>")
33
+ console.log(" codex-switch rm <profile>")
34
+ console.log(" codex-switch list")
35
+ console.log(" codex-switch current")
36
+ console.log(" codex-switch completion")
37
+ console.log(" codex-switch completion <zsh|bash|fish|powershell>")
19
38
  }
20
39
 
21
40
  function profilePaths(profileName) {
@@ -176,10 +195,245 @@ function editProfile(profileName) {
176
195
  console.log(`switched to ${profileName}`)
177
196
  }
178
197
 
198
+ function deleteProfile(profileName) {
199
+ const paths = ensureProfileExists(profileName)
200
+ const currentProfile = getCurrentProfileName()
201
+ if (currentProfile === profileName) {
202
+ fail(
203
+ `profile is current: ${profileName}\nswitch to another profile first\nexample: codex-switch <other-profile> && codex-switch delete ${profileName}`
204
+ )
205
+ }
206
+ fs.rmSync(paths.dirPath, { recursive: true, force: true })
207
+ console.log(`deleted ${profileName}`)
208
+ }
209
+
210
+ function zshCompletionScript() {
211
+ return `#compdef codex-switch
212
+
213
+ _codex_switch_profiles() {
214
+ local -a profiles
215
+ profiles=("\${(@f)\$(codex-switch list 2>/dev/null)}")
216
+ _describe 'profile' profiles
217
+ }
218
+
219
+ _codex_switch() {
220
+ local -a commands
221
+ commands=(
222
+ 'add:add profile'
223
+ 'edit:edit profile'
224
+ 'rm:remove profile'
225
+ 'list:list profiles'
226
+ 'current:show current profile'
227
+ 'completion:print shell completion script'
228
+ )
229
+
230
+ if (( CURRENT == 2 )); then
231
+ _alternative 'commands:command:->cmds' 'profiles:profile:_codex_switch_profiles'
232
+ return
233
+ fi
234
+
235
+ case "$words[2]" in
236
+ add|edit|rm)
237
+ if (( CURRENT == 3 )); then
238
+ _codex_switch_profiles
239
+ fi
240
+ ;;
241
+ completion)
242
+ _values 'shell' zsh bash fish powershell
243
+ ;;
244
+ *)
245
+ if (( CURRENT == 2 )); then
246
+ _describe 'command' commands
247
+ fi
248
+ ;;
249
+ esac
250
+ }
251
+
252
+ _codex_switch "$@"
253
+ `
254
+ }
255
+
256
+ function bashCompletionScript() {
257
+ return `_codex_switch_profiles() {
258
+ codex-switch list 2>/dev/null
259
+ }
260
+
261
+ _codex_switch() {
262
+ local cur prev
263
+ COMPREPLY=()
264
+ cur="\${COMP_WORDS[COMP_CWORD]}"
265
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
266
+ local commands="add edit rm list current completion"
267
+
268
+ if [[ \${COMP_CWORD} -eq 1 ]]; then
269
+ local profiles
270
+ profiles="$(_codex_switch_profiles)"
271
+ COMPREPLY=( $(compgen -W "\${commands} \${profiles}" -- "\${cur}") )
272
+ return 0
273
+ fi
274
+
275
+ if [[ "\${prev}" == "completion" ]]; then
276
+ COMPREPLY=( $(compgen -W "zsh bash fish powershell" -- "\${cur}") )
277
+ return 0
278
+ fi
279
+
280
+ if [[ "\${COMP_WORDS[1]}" == "add" || "\${COMP_WORDS[1]}" == "edit" || "\${COMP_WORDS[1]}" == "rm" ]]; then
281
+ local profiles
282
+ profiles="$(_codex_switch_profiles)"
283
+ COMPREPLY=( $(compgen -W "\${profiles}" -- "\${cur}") )
284
+ return 0
285
+ fi
286
+ }
287
+
288
+ complete -F _codex_switch codex-switch
289
+ `
290
+ }
291
+
292
+ function fishCompletionScript() {
293
+ return `function __codex_switch_profiles
294
+ codex-switch list 2>/dev/null
295
+ end
296
+
297
+ complete -c codex-switch -f
298
+ complete -c codex-switch -n '__fish_use_subcommand' -a 'add edit rm list current completion (__codex_switch_profiles)'
299
+ complete -c codex-switch -n '__fish_seen_subcommand_from add edit rm' -a '(__codex_switch_profiles)'
300
+ complete -c codex-switch -n '__fish_seen_subcommand_from completion' -a 'zsh bash fish powershell'
301
+ `
302
+ }
303
+
304
+ function powershellCompletionScript() {
305
+ return `Register-ArgumentCompleter -Native -CommandName codex-switch -ScriptBlock {
306
+ param($wordToComplete, $commandAst, $cursorPosition)
307
+ $words = $commandAst.CommandElements | ForEach-Object { $_.Extent.Text }
308
+ $commands = @('add', 'edit', 'rm', 'list', 'current', 'completion')
309
+ $profiles = @(codex-switch list 2>$null)
310
+ $candidates = @()
311
+
312
+ if ($words.Count -le 2) {
313
+ $candidates = $commands + $profiles
314
+ } elseif ($words[1] -eq 'completion') {
315
+ $candidates = @('zsh', 'bash', 'fish', 'powershell')
316
+ } elseif ($words[1] -eq 'add' -or $words[1] -eq 'edit' -or $words[1] -eq 'rm') {
317
+ $candidates = $profiles
318
+ }
319
+
320
+ $candidates |
321
+ Where-Object { $_ -like "$wordToComplete*" } |
322
+ ForEach-Object {
323
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
324
+ }
325
+ }
326
+ `
327
+ }
328
+
329
+ function completionScript(shellName) {
330
+ if (shellName === "zsh") {
331
+ return zshCompletionScript()
332
+ }
333
+ if (shellName === "bash") {
334
+ return bashCompletionScript()
335
+ }
336
+ if (shellName === "fish") {
337
+ return fishCompletionScript()
338
+ }
339
+ if (shellName === "powershell") {
340
+ return powershellCompletionScript()
341
+ }
342
+ fail(`unsupported shell: ${shellName}`)
343
+ }
344
+
345
+ function printCompletion(shellName) {
346
+ console.log(completionScript(shellName))
347
+ }
348
+
349
+ function detectShellName() {
350
+ if (process.platform === "win32") {
351
+ return "powershell"
352
+ }
353
+ const shellPath = process.env.SHELL || ""
354
+ if (shellPath.endsWith("/zsh")) {
355
+ return "zsh"
356
+ }
357
+ if (shellPath.endsWith("/bash")) {
358
+ return "bash"
359
+ }
360
+ if (shellPath.endsWith("/fish")) {
361
+ return "fish"
362
+ }
363
+ fail("cannot detect shell, use: codex-switch completion install <shell>")
364
+ }
365
+
366
+ function appendIfMissing(filePath, marker, block) {
367
+ const content = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : ""
368
+ if (content.includes(marker)) {
369
+ return
370
+ }
371
+ const next = content.endsWith("\n") || content.length === 0 ? content : `${content}\n`
372
+ fs.writeFileSync(filePath, `${next}${block}\n`)
373
+ }
374
+
375
+ function installCompletion(shellName) {
376
+ const resolvedShell = shellName || detectShellName()
377
+ const homeDir = os.homedir()
378
+
379
+ if (resolvedShell === "zsh") {
380
+ const zfuncDir = path.join(homeDir, ".zfunc")
381
+ const completionPath = path.join(zfuncDir, "_codex-switch")
382
+ fs.mkdirSync(zfuncDir, { recursive: true })
383
+ fs.writeFileSync(completionPath, completionScript("zsh"))
384
+ const zshrcPath = path.join(homeDir, ".zshrc")
385
+ appendIfMissing(
386
+ zshrcPath,
387
+ "# codex-switch completion",
388
+ "# codex-switch completion\nfpath=(~/.zfunc $fpath)\nautoload -Uz compinit && compinit"
389
+ )
390
+ console.log(`installed zsh completion: ${completionPath}`)
391
+ return
392
+ }
393
+
394
+ if (resolvedShell === "bash") {
395
+ const dirPath = path.join(homeDir, ".local", "share", "bash-completion", "completions")
396
+ const completionPath = path.join(dirPath, "codex-switch")
397
+ fs.mkdirSync(dirPath, { recursive: true })
398
+ fs.writeFileSync(completionPath, completionScript("bash"))
399
+ console.log(`installed bash completion: ${completionPath}`)
400
+ return
401
+ }
402
+
403
+ if (resolvedShell === "fish") {
404
+ const dirPath = path.join(homeDir, ".config", "fish", "completions")
405
+ const completionPath = path.join(dirPath, "codex-switch.fish")
406
+ fs.mkdirSync(dirPath, { recursive: true })
407
+ fs.writeFileSync(completionPath, completionScript("fish"))
408
+ console.log(`installed fish completion: ${completionPath}`)
409
+ return
410
+ }
411
+
412
+ if (resolvedShell === "powershell") {
413
+ const codexHomeDir = path.join(homeDir, ".codex")
414
+ const completionPath = path.join(codexHomeDir, "codex-switch-completion.ps1")
415
+ fs.mkdirSync(codexHomeDir, { recursive: true })
416
+ fs.writeFileSync(completionPath, completionScript("powershell"))
417
+
418
+ const profileDirPath = path.join(homeDir, "Documents", "PowerShell")
419
+ const profilePath = path.join(profileDirPath, "Microsoft.PowerShell_profile.ps1")
420
+ fs.mkdirSync(profileDirPath, { recursive: true })
421
+ appendIfMissing(
422
+ profilePath,
423
+ "# codex-switch completion",
424
+ `# codex-switch completion\n. '${completionPath.replace(/'/g, "''")}'`
425
+ )
426
+ console.log(`installed powershell completion: ${profilePath}`)
427
+ return
428
+ }
429
+
430
+ fail(`unsupported shell: ${resolvedShell}`)
431
+ }
432
+
179
433
  function run() {
180
- if (args.length === 0) {
181
- usage()
182
- process.exit(1)
434
+ if (args.length === 0 || args[0] === "help" || args[0] === "-h" || args[0] === "--help") {
435
+ help()
436
+ process.exit(0)
183
437
  }
184
438
 
185
439
  const command = args[0]
@@ -194,6 +448,21 @@ function run() {
194
448
  return
195
449
  }
196
450
 
451
+ if (command === "completion") {
452
+ if (args.length === 1) {
453
+ installCompletion("")
454
+ return
455
+ }
456
+
457
+ const shellName = args[1]
458
+ if (!shellName || args.length !== 2) {
459
+ usage()
460
+ process.exit(1)
461
+ }
462
+ printCompletion(shellName)
463
+ return
464
+ }
465
+
197
466
  if (command === "add") {
198
467
  const profileName = args[1]
199
468
  if (!profileName) {
@@ -214,6 +483,16 @@ function run() {
214
483
  return
215
484
  }
216
485
 
486
+ if (command === "rm") {
487
+ const profileName = args[1]
488
+ if (!profileName || args.length !== 2) {
489
+ usage()
490
+ process.exit(1)
491
+ }
492
+ deleteProfile(profileName)
493
+ return
494
+ }
495
+
217
496
  const profileName = command
218
497
  let useCopy = false
219
498
  if (args.length > 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glidea/codex-switch",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Switch Codex profiles quickly",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,4 +19,4 @@
19
19
  "engines": {
20
20
  "node": ">=20"
21
21
  }
22
- }
22
+ }