@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 +14 -0
- package/README.en.md +4 -0
- package/README.md +6 -2
- package/package.json +1 -1
- package/plugins/codex-switcher/README.en.md +6 -2
- package/plugins/codex-switcher/README.md +6 -2
- package/plugins/codex-switcher/scripts/codex-switcher +128 -19
- package/plugins/codex-switcher/scripts/test-switcher.sh +18 -1
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
|
@@ -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
|
|
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
|
-
|
|
984
|
-
|
|
985
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
997
|
-
|
|
998
|
-
|
|
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
|
-
|
|
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
|
-
"$
|
|
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" ]]
|