@glidea/codex-switch 0.1.1 → 0.2.0

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,244 @@ 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
+ 'list:list profiles'
225
+ 'current:show current profile'
226
+ 'completion:print shell completion script'
227
+ )
228
+
229
+ if (( CURRENT == 2 )); then
230
+ _alternative 'commands:command:->cmds' 'profiles:profile:_codex_switch_profiles'
231
+ return
232
+ fi
233
+
234
+ case "$words[2]" in
235
+ add|edit)
236
+ if (( CURRENT == 3 )); then
237
+ _codex_switch_profiles
238
+ fi
239
+ ;;
240
+ completion)
241
+ _values 'shell' zsh bash fish powershell
242
+ ;;
243
+ *)
244
+ if (( CURRENT == 2 )); then
245
+ _describe 'command' commands
246
+ fi
247
+ ;;
248
+ esac
249
+ }
250
+
251
+ _codex_switch "$@"
252
+ `
253
+ }
254
+
255
+ function bashCompletionScript() {
256
+ return `_codex_switch_profiles() {
257
+ codex-switch list 2>/dev/null
258
+ }
259
+
260
+ _codex_switch() {
261
+ local cur prev
262
+ COMPREPLY=()
263
+ cur="\${COMP_WORDS[COMP_CWORD]}"
264
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
265
+ local commands="add edit list current completion"
266
+
267
+ if [[ \${COMP_CWORD} -eq 1 ]]; then
268
+ local profiles
269
+ profiles="$(_codex_switch_profiles)"
270
+ COMPREPLY=( $(compgen -W "\${commands} \${profiles}" -- "\${cur}") )
271
+ return 0
272
+ fi
273
+
274
+ if [[ "\${prev}" == "completion" ]]; then
275
+ COMPREPLY=( $(compgen -W "zsh bash fish powershell" -- "\${cur}") )
276
+ return 0
277
+ fi
278
+
279
+ if [[ "\${COMP_WORDS[1]}" == "add" || "\${COMP_WORDS[1]}" == "edit" ]]; then
280
+ local profiles
281
+ profiles="$(_codex_switch_profiles)"
282
+ COMPREPLY=( $(compgen -W "\${profiles}" -- "\${cur}") )
283
+ return 0
284
+ fi
285
+ }
286
+
287
+ complete -F _codex_switch codex-switch
288
+ `
289
+ }
290
+
291
+ function fishCompletionScript() {
292
+ return `function __codex_switch_profiles
293
+ codex-switch list 2>/dev/null
294
+ end
295
+
296
+ complete -c codex-switch -f
297
+ complete -c codex-switch -n '__fish_use_subcommand' -a 'add edit list current completion (__codex_switch_profiles)'
298
+ complete -c codex-switch -n '__fish_seen_subcommand_from add edit' -a '(__codex_switch_profiles)'
299
+ complete -c codex-switch -n '__fish_seen_subcommand_from completion' -a 'zsh bash fish powershell'
300
+ `
301
+ }
302
+
303
+ function powershellCompletionScript() {
304
+ return `Register-ArgumentCompleter -Native -CommandName codex-switch -ScriptBlock {
305
+ param($wordToComplete, $commandAst, $cursorPosition)
306
+ $words = $commandAst.CommandElements | ForEach-Object { $_.Extent.Text }
307
+ $commands = @('add', 'edit', 'list', 'current', 'completion')
308
+ $profiles = @(codex-switch list 2>$null)
309
+ $candidates = @()
310
+
311
+ if ($words.Count -le 2) {
312
+ $candidates = $commands + $profiles
313
+ } elseif ($words[1] -eq 'completion') {
314
+ $candidates = @('zsh', 'bash', 'fish', 'powershell')
315
+ } elseif ($words[1] -eq 'add' -or $words[1] -eq 'edit') {
316
+ $candidates = $profiles
317
+ }
318
+
319
+ $candidates |
320
+ Where-Object { $_ -like "$wordToComplete*" } |
321
+ ForEach-Object {
322
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
323
+ }
324
+ }
325
+ `
326
+ }
327
+
328
+ function completionScript(shellName) {
329
+ if (shellName === "zsh") {
330
+ return zshCompletionScript()
331
+ }
332
+ if (shellName === "bash") {
333
+ return bashCompletionScript()
334
+ }
335
+ if (shellName === "fish") {
336
+ return fishCompletionScript()
337
+ }
338
+ if (shellName === "powershell") {
339
+ return powershellCompletionScript()
340
+ }
341
+ fail(`unsupported shell: ${shellName}`)
342
+ }
343
+
344
+ function printCompletion(shellName) {
345
+ console.log(completionScript(shellName))
346
+ }
347
+
348
+ function detectShellName() {
349
+ if (process.platform === "win32") {
350
+ return "powershell"
351
+ }
352
+ const shellPath = process.env.SHELL || ""
353
+ if (shellPath.endsWith("/zsh")) {
354
+ return "zsh"
355
+ }
356
+ if (shellPath.endsWith("/bash")) {
357
+ return "bash"
358
+ }
359
+ if (shellPath.endsWith("/fish")) {
360
+ return "fish"
361
+ }
362
+ fail("cannot detect shell, use: codex-switch completion install <shell>")
363
+ }
364
+
365
+ function appendIfMissing(filePath, marker, block) {
366
+ const content = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : ""
367
+ if (content.includes(marker)) {
368
+ return
369
+ }
370
+ const next = content.endsWith("\n") || content.length === 0 ? content : `${content}\n`
371
+ fs.writeFileSync(filePath, `${next}${block}\n`)
372
+ }
373
+
374
+ function installCompletion(shellName) {
375
+ const resolvedShell = shellName || detectShellName()
376
+ const homeDir = os.homedir()
377
+
378
+ if (resolvedShell === "zsh") {
379
+ const zfuncDir = path.join(homeDir, ".zfunc")
380
+ const completionPath = path.join(zfuncDir, "_codex-switch")
381
+ fs.mkdirSync(zfuncDir, { recursive: true })
382
+ fs.writeFileSync(completionPath, completionScript("zsh"))
383
+ const zshrcPath = path.join(homeDir, ".zshrc")
384
+ appendIfMissing(
385
+ zshrcPath,
386
+ "# codex-switch completion",
387
+ "# codex-switch completion\nfpath=(~/.zfunc $fpath)\nautoload -Uz compinit && compinit"
388
+ )
389
+ console.log(`installed zsh completion: ${completionPath}`)
390
+ return
391
+ }
392
+
393
+ if (resolvedShell === "bash") {
394
+ const dirPath = path.join(homeDir, ".local", "share", "bash-completion", "completions")
395
+ const completionPath = path.join(dirPath, "codex-switch")
396
+ fs.mkdirSync(dirPath, { recursive: true })
397
+ fs.writeFileSync(completionPath, completionScript("bash"))
398
+ console.log(`installed bash completion: ${completionPath}`)
399
+ return
400
+ }
401
+
402
+ if (resolvedShell === "fish") {
403
+ const dirPath = path.join(homeDir, ".config", "fish", "completions")
404
+ const completionPath = path.join(dirPath, "codex-switch.fish")
405
+ fs.mkdirSync(dirPath, { recursive: true })
406
+ fs.writeFileSync(completionPath, completionScript("fish"))
407
+ console.log(`installed fish completion: ${completionPath}`)
408
+ return
409
+ }
410
+
411
+ if (resolvedShell === "powershell") {
412
+ const codexHomeDir = path.join(homeDir, ".codex")
413
+ const completionPath = path.join(codexHomeDir, "codex-switch-completion.ps1")
414
+ fs.mkdirSync(codexHomeDir, { recursive: true })
415
+ fs.writeFileSync(completionPath, completionScript("powershell"))
416
+
417
+ const profileDirPath = path.join(homeDir, "Documents", "PowerShell")
418
+ const profilePath = path.join(profileDirPath, "Microsoft.PowerShell_profile.ps1")
419
+ fs.mkdirSync(profileDirPath, { recursive: true })
420
+ appendIfMissing(
421
+ profilePath,
422
+ "# codex-switch completion",
423
+ `# codex-switch completion\n. '${completionPath.replace(/'/g, "''")}'`
424
+ )
425
+ console.log(`installed powershell completion: ${profilePath}`)
426
+ return
427
+ }
428
+
429
+ fail(`unsupported shell: ${resolvedShell}`)
430
+ }
431
+
179
432
  function run() {
180
- if (args.length === 0) {
181
- usage()
182
- process.exit(1)
433
+ if (args.length === 0 || args[0] === "help" || args[0] === "-h" || args[0] === "--help") {
434
+ help()
435
+ process.exit(0)
183
436
  }
184
437
 
185
438
  const command = args[0]
@@ -194,6 +447,21 @@ function run() {
194
447
  return
195
448
  }
196
449
 
450
+ if (command === "completion") {
451
+ if (args.length === 1) {
452
+ installCompletion("")
453
+ return
454
+ }
455
+
456
+ const shellName = args[1]
457
+ if (!shellName || args.length !== 2) {
458
+ usage()
459
+ process.exit(1)
460
+ }
461
+ printCompletion(shellName)
462
+ return
463
+ }
464
+
197
465
  if (command === "add") {
198
466
  const profileName = args[1]
199
467
  if (!profileName) {
@@ -214,6 +482,16 @@ function run() {
214
482
  return
215
483
  }
216
484
 
485
+ if (command === "rm") {
486
+ const profileName = args[1]
487
+ if (!profileName || args.length !== 2) {
488
+ usage()
489
+ process.exit(1)
490
+ }
491
+ deleteProfile(profileName)
492
+ return
493
+ }
494
+
217
495
  const profileName = command
218
496
  let useCopy = false
219
497
  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.0",
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
+ }