@wangxt0223/codex-switcher 0.4.1 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.1 - 2026-04-12
4
+
5
+ - Added `version: <semver>` output in `codex-sw check` for quick runtime version verification.
6
+ - Added smoke-test assertion to verify `check` includes the version line.
7
+
8
+ ## 0.5.0 - 2026-04-12
9
+
10
+ - Added automatic Codex CLI launch behavior for `use/switch` in interactive shells (`--launch=auto`).
11
+ - Added explicit `--launch` / `--no-launch` controls for `use/switch`.
12
+ - Added support for `use/switch -- <codex args...>` to switch profile and run Codex command in one step.
13
+ - Improved non-interactive UX with explicit auto-launch skip hint.
14
+ - Added smoke-test coverage for launch/no-launch behavior and argument conflict handling.
15
+ - Updated Chinese/English docs to describe launch semantics and new command forms.
16
+
3
17
  ## 0.4.1 - 2026-04-12
4
18
 
5
19
  - Refined README wording for a more conversational background/auth mechanism explanation.
package/README.en.md CHANGED
@@ -58,6 +58,10 @@ codex-switcher app use personal
58
58
  - `login --sync`: sync `~/.codex` into the target profile (excluding `auth.json`).
59
59
  - `use/switch --sync`: sync current CLI profile into target profile (excluding `auth.json`).
60
60
  - `--no-sync`: keep strict isolation without data copy (default).
61
+ - `use/switch` defaults to `--launch=auto`: on an interactive terminal, `codex` starts automatically after switch.
62
+ - `use/switch --launch`: launch `codex` CLI immediately after switching.
63
+ - `use/switch --no-launch`: switch CLI pointer only, without launching `codex`.
64
+ - `use/switch -- <codex args...>`: run `codex` with args right after switch (implies launch).
61
65
 
62
66
  ## Command reference
63
67
 
package/README.md CHANGED
@@ -55,6 +55,10 @@ codex-switcher app use personal
55
55
  - `login --sync`:将 `~/.codex` 同步到目标 profile(不包含 `auth.json`)。
56
56
  - `use/switch --sync`:将当前 CLI profile 同步到目标 profile(不包含 `auth.json`)。
57
57
  - `--no-sync`:不进行数据同步(默认)。
58
+ - `use/switch` 默认 `--launch=auto`:交互终端中切换后会自动启动 `codex` CLI。
59
+ - `use/switch --launch`:切换后立即启动 `codex` CLI。
60
+ - `use/switch --no-launch`:仅切换当前 CLI profile,不启动 `codex` CLI。
61
+ - `use/switch -- <codex args...>`:切换后直接执行 `codex` 参数(隐式启用 launch)。
58
62
 
59
63
  ## 命令参考
60
64
 
@@ -67,8 +71,8 @@ codex-switcher app use personal
67
71
  | Profile 管理 | `codex-switcher list` | 列出所有 profile |
68
72
  | Profile 管理 | `codex-switcher current [cli\|app]` | 查看当前 CLI / App profile |
69
73
  | Profile 管理 | `codex-switcher status` | 查看当前 profile 登录状态 |
70
- | Profile 管理 | `codex-switcher use <profile> [--sync\|--no-sync]` | 切换当前 CLI profile |
71
- | Profile 管理 | `codex-switcher switch <profile> [--sync\|--no-sync]` | `use` 的等价命令 |
74
+ | Profile 管理 | `codex-switcher use <profile> [--sync\|--no-sync] [--launch\|--no-launch] [-- <codex args...>]` | 切换当前 CLI profile,可选立即启动 `codex` |
75
+ | Profile 管理 | `codex-switcher switch <profile> [--sync\|--no-sync] [--launch\|--no-launch] [-- <codex args...>]` | `use` 的等价命令 |
72
76
  | 数据迁移 | `codex-switcher import-default <profile> [--with-auth] [--force]` | 从 `~/.codex` 导入数据到 profile |
73
77
  | CLI 登录态 | `codex-switcher login [profile] [--sync\|--no-sync]` | 登录指定或当前 CLI profile |
74
78
  | CLI 登录态 | `codex-switcher logout [profile]` | 登出指定或当前 CLI profile |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wangxt0223/codex-switcher",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "Profile-based account switcher for Codex CLI and Codex App using isolated CODEX_HOME directories.",
5
5
  "license": "MIT",
6
6
  "author": "wangxt",
@@ -18,8 +18,8 @@ codex-switcher add <profile>
18
18
  codex-switcher remove <profile> [--force]
19
19
  codex-switcher list
20
20
  codex-switcher import-default <profile> [--with-auth] [--force]
21
- codex-switcher use <profile> [--sync|--no-sync]
22
- codex-switcher switch <profile> [--sync|--no-sync]
21
+ codex-switcher use <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
22
+ codex-switcher switch <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
23
23
  codex-switcher current [cli|app]
24
24
  codex-switcher status
25
25
 
@@ -75,6 +75,10 @@ codex-switcher import-default work --with-auth
75
75
  - `login --sync`: overwrite sync from default `~/.codex` to target profile, excluding `auth.json`.
76
76
  - `use/switch --sync`: overwrite sync from current CLI profile to target profile, excluding `auth.json`.
77
77
  - `--no-sync`: explicit no-sync mode (default behavior).
78
+ - `use/switch` defaults to `--launch=auto`: in interactive terminals, `codex` starts right after switching.
79
+ - `use/switch --launch`: launch `codex` CLI immediately after switching profile.
80
+ - `use/switch --no-launch`: switch pointer only without launching `codex`.
81
+ - `use/switch -- <codex args...>`: run `codex` with provided args after switch (implies launch).
78
82
 
79
83
  Examples:
80
84
 
@@ -18,8 +18,8 @@ codex-switcher add <profile>
18
18
  codex-switcher remove <profile> [--force]
19
19
  codex-switcher list
20
20
  codex-switcher import-default <profile> [--with-auth] [--force]
21
- codex-switcher use <profile> [--sync|--no-sync]
22
- codex-switcher switch <profile> [--sync|--no-sync]
21
+ codex-switcher use <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
22
+ codex-switcher switch <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
23
23
  codex-switcher current [cli|app]
24
24
  codex-switcher status
25
25
 
@@ -75,6 +75,10 @@ codex-switcher import-default work --with-auth
75
75
  - `login --sync`:从默认 `~/.codex` 覆盖同步到目标 profile,排除 `auth.json`。
76
76
  - `use/switch --sync`:从当前 CLI profile 覆盖同步到目标 profile,排除 `auth.json`。
77
77
  - `--no-sync`:显式关闭同步(默认行为)。
78
+ - `use/switch` 默认 `--launch=auto`:交互终端中切换后自动启动 `codex` CLI。
79
+ - `use/switch --launch`:切换后立即以目标 profile 启动 `codex` CLI。
80
+ - `use/switch --no-launch`:切换后只更新 profile 指针,不启动 `codex` CLI。
81
+ - `use/switch -- <codex args...>`:切换后执行指定 `codex` 参数(等价于隐式 `--launch`)。
78
82
 
79
83
  示例:
80
84
 
@@ -18,8 +18,8 @@ Usage:
18
18
  codex-sw remove <profile> [--force]
19
19
  codex-sw list
20
20
  codex-sw import-default <profile> [--with-auth] [--force]
21
- codex-sw use <profile> [--sync|--no-sync]
22
- codex-sw switch <profile> [--sync|--no-sync]
21
+ codex-sw use <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
22
+ codex-sw switch <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
23
23
  codex-sw current [cli|app]
24
24
  codex-sw status
25
25
 
@@ -76,6 +76,18 @@ now_utc() {
76
76
  date -u +"%Y-%m-%dT%H:%M:%SZ"
77
77
  }
78
78
 
79
+ switcher_version() {
80
+ local script_dir package_json version
81
+ script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
82
+ package_json="$(cd "$script_dir/../../.." && pwd)/package.json"
83
+
84
+ if [[ -f "$package_json" ]]; then
85
+ version="$(sed -nE 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' "$package_json" | head -n 1)"
86
+ fi
87
+
88
+ echo "${version:-unknown}"
89
+ }
90
+
79
91
  redact() {
80
92
  sed -E \
81
93
  -e 's/sk-[A-Za-z0-9_-]{8,}/sk-***REDACTED***/g' \
@@ -514,15 +526,53 @@ cmd_use() {
514
526
  ensure_profile "$profile"
515
527
  set_current cli "$profile"
516
528
  log_event INFO "cli_use profile=$profile sync=$sync_mode"
517
- echo "Switched CLI profile to: $profile"
518
- echo "Run in current shell if needed:"
519
- echo " export CODEX_HOME='$(profile_path "$profile")'"
520
529
  }
521
530
 
522
531
  cmd_switch() {
523
532
  cmd_use "$1" "${2:-false}"
524
533
  }
525
534
 
535
+ should_launch_codex() {
536
+ local mode="$1"
537
+ case "$mode" in
538
+ true)
539
+ return 0
540
+ ;;
541
+ false)
542
+ return 1
543
+ ;;
544
+ auto)
545
+ [[ -t 0 && -t 1 ]]
546
+ ;;
547
+ *)
548
+ return 1
549
+ ;;
550
+ esac
551
+ }
552
+
553
+ cmd_use_and_maybe_launch() {
554
+ local mode_cmd="$1"
555
+ local profile="$2"
556
+ local sync_mode="${3:-false}"
557
+ local launch_mode="${4:-auto}"
558
+ shift 4 || true
559
+
560
+ with_lock "$mode_cmd" "$profile" "$sync_mode"
561
+
562
+ echo "Switched CLI profile to: $profile"
563
+ if should_launch_codex "$launch_mode"; then
564
+ echo "Launching codex with profile: $profile"
565
+ CODEX_HOME="$(profile_path "$profile")" command codex "$@"
566
+ return
567
+ fi
568
+
569
+ if [[ "$launch_mode" == "auto" ]]; then
570
+ echo "Auto launch skipped (non-interactive shell). Use --launch to force start."
571
+ fi
572
+ echo "Run in current shell if needed:"
573
+ echo " export CODEX_HOME='$(profile_path "$profile")'"
574
+ }
575
+
526
576
  cmd_current() {
527
577
  local target="${1:-all}"
528
578
  case "$target" in
@@ -836,6 +886,7 @@ cmd_check() {
836
886
  err "log redaction check failed"
837
887
  fi
838
888
 
889
+ echo "version: $(switcher_version)"
839
890
  echo "check: ok"
840
891
  }
841
892
 
@@ -977,30 +1028,88 @@ main() {
977
1028
  with_lock cmd_import_default "$profile" "$with_auth" "$force"
978
1029
  ;;
979
1030
  use)
980
- [[ "$#" -ge 1 && "$#" -le 2 ]] || err "usage: $SCRIPT_NAME use <profile> [--sync|--no-sync]"
1031
+ [[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME use <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]"
981
1032
  local profile="$1"
1033
+ shift
982
1034
  local sync="false"
983
- if [[ "${2:-}" == "--sync" ]]; then
984
- sync="true"
985
- elif [[ "${2:-}" == "--no-sync" || -z "${2:-}" ]]; then
986
- :
1035
+ local launch="auto"
1036
+ local codex_args=()
1037
+ while [[ "$#" -gt 0 ]]; do
1038
+ case "$1" in
1039
+ --sync)
1040
+ sync="true"
1041
+ ;;
1042
+ --no-sync)
1043
+ sync="false"
1044
+ ;;
1045
+ --launch)
1046
+ launch="true"
1047
+ ;;
1048
+ --no-launch)
1049
+ launch="false"
1050
+ ;;
1051
+ --)
1052
+ shift
1053
+ codex_args=("$@")
1054
+ break
1055
+ ;;
1056
+ *)
1057
+ err "unknown option: $1"
1058
+ ;;
1059
+ esac
1060
+ shift
1061
+ done
1062
+ if [[ "${#codex_args[@]}" -gt 0 ]]; then
1063
+ [[ "$launch" != "false" ]] || err "cannot pass codex args with --no-launch"
1064
+ launch="true"
1065
+ fi
1066
+ if [[ "${#codex_args[@]}" -gt 0 ]]; then
1067
+ cmd_use_and_maybe_launch cmd_use "$profile" "$sync" "$launch" "${codex_args[@]}"
987
1068
  else
988
- err "unknown option: ${2:-}"
1069
+ cmd_use_and_maybe_launch cmd_use "$profile" "$sync" "$launch"
989
1070
  fi
990
- with_lock cmd_use "$profile" "$sync"
991
1071
  ;;
992
1072
  switch)
993
- [[ "$#" -ge 1 && "$#" -le 2 ]] || err "usage: $SCRIPT_NAME switch <profile> [--sync|--no-sync]"
1073
+ [[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME switch <profile> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]"
994
1074
  local profile="$1"
1075
+ shift
995
1076
  local sync="false"
996
- if [[ "${2:-}" == "--sync" ]]; then
997
- sync="true"
998
- elif [[ "${2:-}" == "--no-sync" || -z "${2:-}" ]]; then
999
- :
1077
+ local launch="auto"
1078
+ local codex_args=()
1079
+ while [[ "$#" -gt 0 ]]; do
1080
+ case "$1" in
1081
+ --sync)
1082
+ sync="true"
1083
+ ;;
1084
+ --no-sync)
1085
+ sync="false"
1086
+ ;;
1087
+ --launch)
1088
+ launch="true"
1089
+ ;;
1090
+ --no-launch)
1091
+ launch="false"
1092
+ ;;
1093
+ --)
1094
+ shift
1095
+ codex_args=("$@")
1096
+ break
1097
+ ;;
1098
+ *)
1099
+ err "unknown option: $1"
1100
+ ;;
1101
+ esac
1102
+ shift
1103
+ done
1104
+ if [[ "${#codex_args[@]}" -gt 0 ]]; then
1105
+ [[ "$launch" != "false" ]] || err "cannot pass codex args with --no-launch"
1106
+ launch="true"
1107
+ fi
1108
+ if [[ "${#codex_args[@]}" -gt 0 ]]; then
1109
+ cmd_use_and_maybe_launch cmd_switch "$profile" "$sync" "$launch" "${codex_args[@]}"
1000
1110
  else
1001
- err "unknown option: ${2:-}"
1111
+ cmd_use_and_maybe_launch cmd_switch "$profile" "$sync" "$launch"
1002
1112
  fi
1003
- with_lock cmd_switch "$profile" "$sync"
1004
1113
  ;;
1005
1114
  current)
1006
1115
  [[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME current [cli|app]"
@@ -21,6 +21,7 @@ trap cleanup EXIT INT TERM
21
21
  cat > "$BIN/codex" <<'FAKE'
22
22
  #!/usr/bin/env bash
23
23
  set -euo pipefail
24
+ echo "${CODEX_HOME:-}|$*" >> "${CODEX_SWITCHER_TEST_CODEX_LOG:?}"
24
25
  if [[ "${1:-}" == "login" && "${2:-}" == "status" ]]; then
25
26
  if [[ -f "${CODEX_HOME}/auth.json" ]]; then
26
27
  echo "Logged in"
@@ -64,6 +65,8 @@ export CODEX_SWITCHER_APP_BIN="$BIN/fake-codex-app"
64
65
  export CODEX_SWITCHER_LOCK_WAIT_SECONDS=2
65
66
  export CODEX_SWITCHER_DEFAULT_HOME="$TMPBASE/default-home"
66
67
  export CODEX_SWITCHER_TEST_NPM_LOG="$TMPBASE/npm-args.log"
68
+ export CODEX_SWITCHER_TEST_CODEX_LOG="$TMPBASE/codex-args.log"
69
+ : > "$CODEX_SWITCHER_TEST_CODEX_LOG"
67
70
 
68
71
  mkdir -p "$CODEX_SWITCHER_DEFAULT_HOME/memories"
69
72
  echo '{"auth_mode":"chatgpt"}' > "$CODEX_SWITCHER_DEFAULT_HOME/auth.json"
@@ -71,6 +74,7 @@ echo '{"projects":["demo"]}' > "$CODEX_SWITCHER_DEFAULT_HOME/state_5.sqlite"
71
74
  echo '{"memo":"persist"}' > "$CODEX_SWITCHER_DEFAULT_HOME/memories/demo.json"
72
75
 
73
76
  check_out="$("$SW" check)"
77
+ echo "$check_out" | grep -Eq '^version: [0-9]+\.[0-9]+\.[0-9]+$'
74
78
  echo "$check_out" | grep -q "check: ok"
75
79
  init_out="$("$SW" init --dry-run)"
76
80
  echo "$init_out" | grep -q "\[dry-run\]"
@@ -79,9 +83,22 @@ grep -q "i -g @wangxt0223/codex-switcher@latest --registry https://registry.npmj
79
83
 
80
84
  "$SW" add work
81
85
  "$SW" add personal
82
- "$SW" use personal
86
+ codex_calls_before="$(wc -l < "$CODEX_SWITCHER_TEST_CODEX_LOG" 2>/dev/null || echo 0)"
87
+ "$SW" use personal --no-launch
88
+ codex_calls_after="$(wc -l < "$CODEX_SWITCHER_TEST_CODEX_LOG" 2>/dev/null || echo 0)"
89
+ [[ "$codex_calls_before" -eq "$codex_calls_after" ]]
83
90
  [[ "$("$SW" current cli)" == "personal" ]]
84
91
 
92
+ "$SW" use personal -- --version
93
+ grep -Fq "$PROFILES/personal|--version" "$CODEX_SWITCHER_TEST_CODEX_LOG"
94
+
95
+ set +e
96
+ "$SW" use personal --no-launch -- --version >/tmp/codex_sw_use_no_launch_conflict 2>&1
97
+ use_no_launch_conflict_rc=$?
98
+ set -e
99
+ [[ "$use_no_launch_conflict_rc" -ne 0 ]]
100
+ grep -q "cannot pass codex args with --no-launch" /tmp/codex_sw_use_no_launch_conflict
101
+
85
102
  "$SW" login personal
86
103
  "$SW" login sync-login --sync
87
104
  [[ -f "$PROFILES/sync-login/state_5.sqlite" ]]