@wangxt0223/codex-switcher 0.5.0 → 0.6.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/CHANGELOG.md +15 -0
- package/README.en.md +13 -15
- package/README.md +17 -42
- package/docs/macos-manual-checklist.md +8 -7
- package/docs/upgrade.md +1 -1
- package/package.json +4 -3
- package/plugins/codex-switcher/README.en.md +55 -82
- package/plugins/codex-switcher/README.md +53 -80
- package/plugins/codex-switcher/scripts/codex-switcher +1134 -409
- package/plugins/codex-switcher/scripts/profile-metrics.py +378 -0
- package/plugins/codex-switcher/scripts/test-switcher.sh +107 -108
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
STATE_DIR="${CODEX_SWITCHER_STATE_DIR:-$HOME/.codex-switcher}"
|
|
5
|
-
|
|
5
|
+
ENVS_DIR="${CODEX_SWITCHER_ENVS_DIR:-$HOME/.codex-envs}"
|
|
6
|
+
ACCOUNTS_DIR="${CODEX_SWITCHER_ACCOUNTS_DIR:-$STATE_DIR/env-accounts}"
|
|
7
|
+
DEFAULT_HOME="${CODEX_SWITCHER_DEFAULT_HOME:-$HOME/.codex}"
|
|
8
|
+
DEFAULT_ENV_NAME="default"
|
|
9
|
+
DEFAULT_ACCOUNT_NAME="default"
|
|
10
|
+
|
|
6
11
|
APP_LOG="${CODEX_SWITCHER_APP_LOG:-$STATE_DIR/app.log}"
|
|
7
12
|
SWITCH_LOG="${CODEX_SWITCHER_SWITCH_LOG:-$STATE_DIR/switcher.log}"
|
|
8
13
|
APP_PID_FILE="$STATE_DIR/app.pid"
|
|
@@ -14,23 +19,37 @@ SCRIPT_NAME="${CODEX_SWITCHER_INVOKED_AS:-$(basename "$0")}"
|
|
|
14
19
|
usage() {
|
|
15
20
|
cat <<'USAGE'
|
|
16
21
|
Usage:
|
|
17
|
-
codex-sw
|
|
18
|
-
codex-sw
|
|
22
|
+
codex-sw env list
|
|
23
|
+
codex-sw env create <env> [--empty|--from-default|--from-env <src>]
|
|
24
|
+
codex-sw env use <env> [--target cli|app|both]
|
|
25
|
+
codex-sw env remove <env> [--force]
|
|
26
|
+
codex-sw env current [cli|app]
|
|
27
|
+
codex-sw env path [env]
|
|
28
|
+
|
|
29
|
+
codex-sw account list [--env <env>]
|
|
30
|
+
codex-sw account add <account> [--env <env>]
|
|
31
|
+
codex-sw account remove <account> [--env <env>] [--force]
|
|
32
|
+
codex-sw account login <account> [--env <env>] [--target cli|app|both] [--sync|--no-sync]
|
|
33
|
+
codex-sw account use <account> [--env <env>] [--target cli|app|both] [--sync|--no-sync]
|
|
34
|
+
codex-sw account logout [account] [--env <env>] [--target cli|app|both]
|
|
35
|
+
codex-sw account current [cli|app]
|
|
36
|
+
|
|
19
37
|
codex-sw list
|
|
20
|
-
codex-sw import-default <profile> [--with-auth] [--force]
|
|
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
|
-
codex-sw current [cli|app]
|
|
24
38
|
codex-sw status
|
|
25
|
-
|
|
39
|
+
codex-sw current [cli|app]
|
|
26
40
|
codex-sw exec -- <codex args...>
|
|
27
|
-
codex-sw login [
|
|
28
|
-
codex-sw logout [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
codex-sw
|
|
32
|
-
codex-sw
|
|
33
|
-
codex-sw
|
|
41
|
+
codex-sw login [account] [--sync|--no-sync]
|
|
42
|
+
codex-sw logout [account]
|
|
43
|
+
|
|
44
|
+
codex-sw use <account> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
|
|
45
|
+
codex-sw switch <account> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]
|
|
46
|
+
codex-sw add <account>
|
|
47
|
+
codex-sw remove <account> [--force]
|
|
48
|
+
codex-sw import-default <env> [--with-auth] [--force]
|
|
49
|
+
|
|
50
|
+
codex-sw app open [account] [-- <app args...>]
|
|
51
|
+
codex-sw app use <account> [-- <app args...>]
|
|
52
|
+
codex-sw app logout [account]
|
|
34
53
|
codex-sw app status
|
|
35
54
|
codex-sw app stop
|
|
36
55
|
codex-sw app current
|
|
@@ -44,22 +63,11 @@ Usage:
|
|
|
44
63
|
Compatibility:
|
|
45
64
|
codex-switcher <same-commands>
|
|
46
65
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Environment overrides:
|
|
54
|
-
CODEX_SWITCHER_STATE_DIR
|
|
55
|
-
CODEX_SWITCHER_PROFILES_DIR
|
|
56
|
-
CODEX_SWITCHER_APP_BIN
|
|
57
|
-
CODEX_SWITCHER_APP_LOG
|
|
58
|
-
CODEX_SWITCHER_SWITCH_LOG
|
|
59
|
-
CODEX_SWITCHER_LOCK_WAIT_SECONDS
|
|
60
|
-
CODEX_SWITCHER_DEFAULT_HOME
|
|
61
|
-
CODEX_SWITCHER_UPGRADE_REGISTRY
|
|
62
|
-
CODEX_SWITCHER_NPM_PACKAGE
|
|
66
|
+
Notes:
|
|
67
|
+
- Built-in env "default" always maps to ~/.codex (or CODEX_SWITCHER_DEFAULT_HOME).
|
|
68
|
+
- Same-env account switch only swaps auth.json and does not sync shared data.
|
|
69
|
+
- `list` prints: EMAIL / PLAN / 5H USAGE / WEEKLY USAGE / LAST ACTIVITY (+ env/account context).
|
|
70
|
+
- Usage metrics are API-first and automatically fallback to local sessions; source is shown as (api|local).
|
|
63
71
|
USAGE
|
|
64
72
|
}
|
|
65
73
|
|
|
@@ -76,6 +84,18 @@ now_utc() {
|
|
|
76
84
|
date -u +"%Y-%m-%dT%H:%M:%SZ"
|
|
77
85
|
}
|
|
78
86
|
|
|
87
|
+
switcher_version() {
|
|
88
|
+
local script_dir package_json version
|
|
89
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
90
|
+
package_json="$(cd "$script_dir/../../.." && pwd)/package.json"
|
|
91
|
+
|
|
92
|
+
if [[ -f "$package_json" ]]; then
|
|
93
|
+
version="$(sed -nE 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' "$package_json" | head -n 1)"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
echo "${version:-unknown}"
|
|
97
|
+
}
|
|
98
|
+
|
|
79
99
|
redact() {
|
|
80
100
|
sed -E \
|
|
81
101
|
-e 's/sk-[A-Za-z0-9_-]{8,}/sk-***REDACTED***/g' \
|
|
@@ -92,8 +112,9 @@ log_event() {
|
|
|
92
112
|
}
|
|
93
113
|
|
|
94
114
|
ensure_dirs() {
|
|
95
|
-
mkdir -p "$STATE_DIR" "$
|
|
96
|
-
|
|
115
|
+
mkdir -p "$STATE_DIR" "$ENVS_DIR" "$ACCOUNTS_DIR"
|
|
116
|
+
mkdir -p "$DEFAULT_HOME"
|
|
117
|
+
chmod 700 "$STATE_DIR" "$ENVS_DIR" "$ACCOUNTS_DIR" "$DEFAULT_HOME" 2>/dev/null || true
|
|
97
118
|
}
|
|
98
119
|
|
|
99
120
|
perm_of() {
|
|
@@ -105,77 +126,120 @@ perm_of() {
|
|
|
105
126
|
fi
|
|
106
127
|
}
|
|
107
128
|
|
|
108
|
-
|
|
129
|
+
validate_name_noexit() {
|
|
109
130
|
local name="${1:-}"
|
|
110
131
|
[[ -n "$name" ]] || return 1
|
|
111
132
|
[[ "$name" =~ ^[A-Za-z0-9._-]+$ ]] || return 1
|
|
112
133
|
return 0
|
|
113
134
|
}
|
|
114
135
|
|
|
115
|
-
|
|
136
|
+
validate_env_name_noexit() {
|
|
116
137
|
local name="${1:-}"
|
|
117
|
-
|
|
138
|
+
[[ "$name" == "$DEFAULT_ENV_NAME" ]] && return 0
|
|
139
|
+
validate_name_noexit "$name"
|
|
118
140
|
}
|
|
119
141
|
|
|
120
|
-
|
|
121
|
-
local
|
|
122
|
-
|
|
123
|
-
|
|
142
|
+
validate_env_name() {
|
|
143
|
+
local name="${1:-}"
|
|
144
|
+
validate_env_name_noexit "$name" || err "invalid env '$name' (allowed: A-Z a-z 0-9 . _ -, plus reserved: default)"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
validate_account_name() {
|
|
148
|
+
local name="${1:-}"
|
|
149
|
+
validate_name_noexit "$name" || err "invalid account '$name' (allowed: A-Z a-z 0-9 . _ -)"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
env_root_path() {
|
|
153
|
+
local env="$1"
|
|
154
|
+
echo "$ENVS_DIR/$env"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
env_home_path() {
|
|
158
|
+
local env="$1"
|
|
159
|
+
if [[ "$env" == "$DEFAULT_ENV_NAME" ]]; then
|
|
160
|
+
echo "$DEFAULT_HOME"
|
|
124
161
|
else
|
|
125
|
-
echo "
|
|
162
|
+
echo "$ENVS_DIR/$env/home"
|
|
126
163
|
fi
|
|
127
164
|
}
|
|
128
165
|
|
|
129
|
-
|
|
130
|
-
local
|
|
131
|
-
|
|
166
|
+
account_dir_path() {
|
|
167
|
+
local env="$1"
|
|
168
|
+
local account="$2"
|
|
169
|
+
echo "$ACCOUNTS_DIR/$env/$account"
|
|
132
170
|
}
|
|
133
171
|
|
|
134
|
-
|
|
135
|
-
local
|
|
136
|
-
local
|
|
137
|
-
|
|
138
|
-
mkdir -p "$p"
|
|
139
|
-
chmod 700 "$p" 2>/dev/null || true
|
|
172
|
+
account_auth_path() {
|
|
173
|
+
local env="$1"
|
|
174
|
+
local account="$2"
|
|
175
|
+
echo "$(account_dir_path "$env" "$account")/auth.json"
|
|
140
176
|
}
|
|
141
177
|
|
|
142
|
-
|
|
143
|
-
local
|
|
144
|
-
|
|
145
|
-
p="$(profile_path "$name")"
|
|
146
|
-
[[ -d "$p" ]] || err "profile '$name' not found. run: $SCRIPT_NAME add $name"
|
|
178
|
+
current_env_file() {
|
|
179
|
+
local target="$1"
|
|
180
|
+
echo "$STATE_DIR/current_${target}_env"
|
|
147
181
|
}
|
|
148
182
|
|
|
149
|
-
|
|
183
|
+
current_account_file() {
|
|
150
184
|
local target="$1"
|
|
151
|
-
echo "$STATE_DIR/current_${target}"
|
|
185
|
+
echo "$STATE_DIR/current_${target}_account"
|
|
152
186
|
}
|
|
153
187
|
|
|
154
|
-
|
|
188
|
+
set_current_env() {
|
|
155
189
|
local target="$1"
|
|
156
|
-
local
|
|
190
|
+
local env="$2"
|
|
157
191
|
local file tmp
|
|
158
|
-
file="$(
|
|
192
|
+
file="$(current_env_file "$target")"
|
|
159
193
|
tmp="${file}.tmp"
|
|
160
|
-
printf '%s\n' "$
|
|
194
|
+
printf '%s\n' "$env" > "$tmp"
|
|
161
195
|
chmod 600 "$tmp" 2>/dev/null || true
|
|
162
196
|
mv "$tmp" "$file"
|
|
163
197
|
}
|
|
164
198
|
|
|
165
|
-
|
|
199
|
+
set_current_account() {
|
|
166
200
|
local target="$1"
|
|
167
|
-
local
|
|
168
|
-
file
|
|
169
|
-
|
|
201
|
+
local account="$2"
|
|
202
|
+
local file tmp
|
|
203
|
+
file="$(current_account_file "$target")"
|
|
204
|
+
tmp="${file}.tmp"
|
|
205
|
+
printf '%s\n' "$account" > "$tmp"
|
|
206
|
+
chmod 600 "$tmp" 2>/dev/null || true
|
|
207
|
+
mv "$tmp" "$file"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
read_current_env() {
|
|
211
|
+
local target="$1"
|
|
212
|
+
local file value
|
|
213
|
+
file="$(current_env_file "$target")"
|
|
214
|
+
|
|
215
|
+
if [[ ! -f "$file" ]]; then
|
|
216
|
+
echo "$DEFAULT_ENV_NAME"
|
|
217
|
+
return 1
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
value="$(head -n 1 "$file" | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
|
|
221
|
+
if ! validate_env_name_noexit "$value"; then
|
|
222
|
+
echo "$DEFAULT_ENV_NAME"
|
|
223
|
+
return 2
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
echo "$value"
|
|
227
|
+
return 0
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
read_current_account() {
|
|
231
|
+
local target="$1"
|
|
232
|
+
local file value
|
|
233
|
+
file="$(current_account_file "$target")"
|
|
170
234
|
|
|
171
235
|
if [[ ! -f "$file" ]]; then
|
|
172
|
-
echo "$
|
|
236
|
+
echo "$DEFAULT_ACCOUNT_NAME"
|
|
173
237
|
return 1
|
|
174
238
|
fi
|
|
175
239
|
|
|
176
240
|
value="$(head -n 1 "$file" | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
|
|
177
|
-
if !
|
|
178
|
-
echo "$
|
|
241
|
+
if ! validate_name_noexit "$value"; then
|
|
242
|
+
echo "$DEFAULT_ACCOUNT_NAME"
|
|
179
243
|
return 2
|
|
180
244
|
fi
|
|
181
245
|
|
|
@@ -183,32 +247,150 @@ read_current() {
|
|
|
183
247
|
return 0
|
|
184
248
|
}
|
|
185
249
|
|
|
186
|
-
|
|
187
|
-
local
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
250
|
+
ensure_env_home() {
|
|
251
|
+
local env="$1"
|
|
252
|
+
local home
|
|
253
|
+
validate_env_name "$env"
|
|
254
|
+
home="$(env_home_path "$env")"
|
|
255
|
+
mkdir -p "$home"
|
|
256
|
+
if [[ "$env" != "$DEFAULT_ENV_NAME" ]]; then
|
|
257
|
+
mkdir -p "$(env_root_path "$env")"
|
|
258
|
+
fi
|
|
259
|
+
chmod 700 "$home" 2>/dev/null || true
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
env_exists() {
|
|
263
|
+
local env="$1"
|
|
264
|
+
if [[ "$env" == "$DEFAULT_ENV_NAME" ]]; then
|
|
265
|
+
return 0
|
|
266
|
+
fi
|
|
267
|
+
[[ -d "$(env_home_path "$env")" ]]
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
require_env_exists() {
|
|
271
|
+
local env="$1"
|
|
272
|
+
validate_env_name "$env"
|
|
273
|
+
if [[ "$env" == "$DEFAULT_ENV_NAME" ]]; then
|
|
274
|
+
ensure_env_home "$env"
|
|
191
275
|
return 0
|
|
192
276
|
fi
|
|
277
|
+
[[ -d "$(env_home_path "$env")" ]] || err "env '$env' not found. run: $SCRIPT_NAME env create $env"
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
ensure_account_slot() {
|
|
281
|
+
local env="$1"
|
|
282
|
+
local account="$2"
|
|
283
|
+
validate_env_name "$env"
|
|
284
|
+
validate_account_name "$account"
|
|
285
|
+
mkdir -p "$(account_dir_path "$env" "$account")"
|
|
286
|
+
chmod 700 "$(account_dir_path "$env" "$account")" 2>/dev/null || true
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
account_has_auth() {
|
|
290
|
+
local env="$1"
|
|
291
|
+
local account="$2"
|
|
292
|
+
local auth_file home_auth
|
|
293
|
+
auth_file="$(account_auth_path "$env" "$account")"
|
|
294
|
+
if [[ -f "$auth_file" ]]; then
|
|
295
|
+
return 0
|
|
296
|
+
fi
|
|
297
|
+
if [[ "$account" == "$DEFAULT_ACCOUNT_NAME" ]]; then
|
|
298
|
+
home_auth="$(env_home_path "$env")/auth.json"
|
|
299
|
+
[[ -f "$home_auth" ]] && return 0
|
|
300
|
+
fi
|
|
193
301
|
return 1
|
|
194
302
|
}
|
|
195
303
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
304
|
+
list_env_names() {
|
|
305
|
+
echo "$DEFAULT_ENV_NAME"
|
|
306
|
+
if [[ -d "$ENVS_DIR" ]]; then
|
|
307
|
+
find "$ENVS_DIR" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort | while IFS= read -r env; do
|
|
308
|
+
validate_env_name_noexit "$env" || continue
|
|
309
|
+
[[ "$env" == "$DEFAULT_ENV_NAME" ]] && continue
|
|
310
|
+
[[ -d "$(env_home_path "$env")" ]] || continue
|
|
311
|
+
echo "$env"
|
|
312
|
+
done
|
|
201
313
|
fi
|
|
314
|
+
}
|
|
202
315
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
316
|
+
list_accounts_for_env() {
|
|
317
|
+
local env="$1"
|
|
318
|
+
local dir auth_file any
|
|
319
|
+
dir="$ACCOUNTS_DIR/$env"
|
|
320
|
+
any=0
|
|
321
|
+
|
|
322
|
+
if [[ -d "$dir" ]]; then
|
|
323
|
+
while IFS= read -r account; do
|
|
324
|
+
validate_name_noexit "$account" || continue
|
|
325
|
+
auth_file="$(account_auth_path "$env" "$account")"
|
|
326
|
+
if [[ -f "$auth_file" ]]; then
|
|
327
|
+
any=1
|
|
328
|
+
echo "$account"
|
|
329
|
+
fi
|
|
330
|
+
done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort)
|
|
206
331
|
fi
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
332
|
+
|
|
333
|
+
if [[ "$any" -eq 0 ]] && [[ "$env" == "$DEFAULT_ENV_NAME" ]] && [[ -f "$(env_home_path "$env")/auth.json" ]]; then
|
|
334
|
+
echo "$DEFAULT_ACCOUNT_NAME"
|
|
210
335
|
fi
|
|
211
|
-
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
copy_auth_file() {
|
|
339
|
+
local src="$1"
|
|
340
|
+
local dst="$2"
|
|
341
|
+
local tmp
|
|
342
|
+
tmp="${dst}.tmp"
|
|
343
|
+
cp "$src" "$tmp"
|
|
344
|
+
chmod 600 "$tmp" 2>/dev/null || true
|
|
345
|
+
mv "$tmp" "$dst"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
save_env_auth_to_account() {
|
|
349
|
+
local env="$1"
|
|
350
|
+
local account="$2"
|
|
351
|
+
local home_auth dst
|
|
352
|
+
home_auth="$(env_home_path "$env")/auth.json"
|
|
353
|
+
[[ -f "$home_auth" ]] || return 1
|
|
354
|
+
ensure_account_slot "$env" "$account"
|
|
355
|
+
dst="$(account_auth_path "$env" "$account")"
|
|
356
|
+
copy_auth_file "$home_auth" "$dst"
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
clear_env_auth() {
|
|
360
|
+
local env="$1"
|
|
361
|
+
rm -f -- "$(env_home_path "$env")/auth.json"
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
install_account_auth_to_env() {
|
|
365
|
+
local env="$1"
|
|
366
|
+
local account="$2"
|
|
367
|
+
local src dst
|
|
368
|
+
src="$(account_auth_path "$env" "$account")"
|
|
369
|
+
dst="$(env_home_path "$env")/auth.json"
|
|
370
|
+
if [[ -f "$src" ]]; then
|
|
371
|
+
copy_auth_file "$src" "$dst"
|
|
372
|
+
return 0
|
|
373
|
+
fi
|
|
374
|
+
if [[ "$account" == "$DEFAULT_ACCOUNT_NAME" ]] && [[ -f "$dst" ]]; then
|
|
375
|
+
return 0
|
|
376
|
+
fi
|
|
377
|
+
rm -f -- "$dst"
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
sync_overwrite_excluding_auth() {
|
|
381
|
+
local src="$1"
|
|
382
|
+
local dst="$2"
|
|
383
|
+
|
|
384
|
+
[[ -d "$src" ]] || err "sync source not found: $src"
|
|
385
|
+
mkdir -p "$dst"
|
|
386
|
+
|
|
387
|
+
if command -v rsync >/dev/null 2>&1; then
|
|
388
|
+
rsync -a --checksum --delete --exclude 'auth.json' "$src/" "$dst/"
|
|
389
|
+
else
|
|
390
|
+
find "$dst" -mindepth 1 -maxdepth 1 ! -name 'auth.json' -exec rm -rf -- {} + 2>/dev/null || true
|
|
391
|
+
(cd "$src" && tar cf - --exclude ./auth.json .) | (cd "$dst" && tar xpf -)
|
|
392
|
+
fi
|
|
393
|
+
chmod 700 "$dst" 2>/dev/null || true
|
|
212
394
|
}
|
|
213
395
|
|
|
214
396
|
acquire_lock() {
|
|
@@ -259,24 +441,60 @@ with_lock() {
|
|
|
259
441
|
trap - EXIT INT TERM
|
|
260
442
|
}
|
|
261
443
|
|
|
262
|
-
|
|
263
|
-
local
|
|
444
|
+
with_targets() {
|
|
445
|
+
local target="$1"
|
|
446
|
+
shift
|
|
447
|
+
local fn="$1"
|
|
264
448
|
shift
|
|
265
|
-
|
|
266
|
-
|
|
449
|
+
case "$target" in
|
|
450
|
+
cli|app)
|
|
451
|
+
"$fn" "$target" "$@"
|
|
452
|
+
;;
|
|
453
|
+
both)
|
|
454
|
+
"$fn" cli "$@"
|
|
455
|
+
"$fn" app "$@"
|
|
456
|
+
;;
|
|
457
|
+
*)
|
|
458
|
+
err "invalid target '$target' (use cli|app|both)"
|
|
459
|
+
;;
|
|
460
|
+
esac
|
|
267
461
|
}
|
|
268
462
|
|
|
269
|
-
|
|
270
|
-
local
|
|
271
|
-
local
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
463
|
+
target_home_path() {
|
|
464
|
+
local target="$1"
|
|
465
|
+
local env
|
|
466
|
+
env="$(read_current_env "$target" || true)"
|
|
467
|
+
env_home_path "$env"
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
ensure_target_auth_installed() {
|
|
471
|
+
local target="$1"
|
|
472
|
+
local env account
|
|
473
|
+
env="$(read_current_env "$target" || true)"
|
|
474
|
+
account="$(read_current_account "$target" || true)"
|
|
475
|
+
ensure_env_home "$env"
|
|
476
|
+
if account_has_auth "$env" "$account"; then
|
|
477
|
+
install_account_auth_to_env "$env" "$account"
|
|
478
|
+
else
|
|
479
|
+
clear_env_auth "$env"
|
|
276
480
|
fi
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
run_codex_for_target() {
|
|
484
|
+
local target="$1"
|
|
485
|
+
shift
|
|
486
|
+
ensure_target_auth_installed "$target"
|
|
487
|
+
CODEX_HOME="$(target_home_path "$target")" command codex "$@"
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
login_state_for_target() {
|
|
491
|
+
local target="$1"
|
|
492
|
+
local rc home
|
|
493
|
+
ensure_target_auth_installed "$target"
|
|
494
|
+
home="$(target_home_path "$target")"
|
|
277
495
|
|
|
278
496
|
rc=0
|
|
279
|
-
CODEX_HOME="$
|
|
497
|
+
CODEX_HOME="$home" command codex login status >/dev/null 2>&1 || rc=$?
|
|
280
498
|
if [[ "$rc" -eq 0 ]]; then
|
|
281
499
|
echo "logged-in"
|
|
282
500
|
else
|
|
@@ -284,6 +502,24 @@ login_state_for_profile() {
|
|
|
284
502
|
fi
|
|
285
503
|
}
|
|
286
504
|
|
|
505
|
+
resolve_app_bin() {
|
|
506
|
+
if [[ -n "${CODEX_SWITCHER_APP_BIN:-}" ]]; then
|
|
507
|
+
[[ -x "$CODEX_SWITCHER_APP_BIN" ]] || err "CODEX_SWITCHER_APP_BIN is not executable: $CODEX_SWITCHER_APP_BIN"
|
|
508
|
+
echo "$CODEX_SWITCHER_APP_BIN"
|
|
509
|
+
return
|
|
510
|
+
fi
|
|
511
|
+
|
|
512
|
+
if [[ -x "/Applications/Codex.app/Contents/MacOS/Codex" ]]; then
|
|
513
|
+
echo "/Applications/Codex.app/Contents/MacOS/Codex"
|
|
514
|
+
return
|
|
515
|
+
fi
|
|
516
|
+
if [[ -x "$HOME/Applications/Codex.app/Contents/MacOS/Codex" ]]; then
|
|
517
|
+
echo "$HOME/Applications/Codex.app/Contents/MacOS/Codex"
|
|
518
|
+
return
|
|
519
|
+
fi
|
|
520
|
+
err "Codex.app binary not found. set CODEX_SWITCHER_APP_BIN manually"
|
|
521
|
+
}
|
|
522
|
+
|
|
287
523
|
kill_tree() {
|
|
288
524
|
local pid="$1"
|
|
289
525
|
local child
|
|
@@ -330,194 +566,461 @@ app_stop_managed() {
|
|
|
330
566
|
echo "Stopped managed app process"
|
|
331
567
|
}
|
|
332
568
|
|
|
333
|
-
|
|
334
|
-
local
|
|
335
|
-
|
|
336
|
-
|
|
569
|
+
metrics_script_path() {
|
|
570
|
+
local script_dir
|
|
571
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
572
|
+
echo "$script_dir/profile-metrics.py"
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
collect_profile_metrics_tsv() {
|
|
576
|
+
local account="$1"
|
|
577
|
+
local auth_file="$2"
|
|
578
|
+
local data_path="$3"
|
|
579
|
+
local script_path
|
|
580
|
+
script_path="$(metrics_script_path)"
|
|
581
|
+
[[ -f "$script_path" ]] || return 1
|
|
582
|
+
python3 "$script_path" --account-name "$account" --auth-file "$auth_file" --data-path "$data_path" 2>/dev/null
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
cmd_env_list() {
|
|
586
|
+
local cli_env app_env env marks
|
|
587
|
+
cli_env="$(read_current_env cli || true)"
|
|
588
|
+
app_env="$(read_current_env app || true)"
|
|
589
|
+
list_env_names | sort -u | while IFS= read -r env; do
|
|
590
|
+
marks=""
|
|
591
|
+
[[ "$env" == "$cli_env" ]] && marks="${marks} [cli-current]"
|
|
592
|
+
[[ "$env" == "$app_env" ]] && marks="${marks} [app-current]"
|
|
593
|
+
echo "- $env$marks"
|
|
594
|
+
done
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
cmd_env_create() {
|
|
598
|
+
local env="$1"
|
|
599
|
+
local mode="$2"
|
|
600
|
+
local src_env="${3:-}"
|
|
601
|
+
local home src
|
|
602
|
+
|
|
603
|
+
validate_env_name "$env"
|
|
604
|
+
[[ "$env" != "$DEFAULT_ENV_NAME" ]] || err "cannot create reserved env '$DEFAULT_ENV_NAME'"
|
|
605
|
+
if env_exists "$env"; then
|
|
606
|
+
err "env '$env' already exists"
|
|
337
607
|
fi
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
608
|
+
|
|
609
|
+
home="$(env_home_path "$env")"
|
|
610
|
+
mkdir -p "$home"
|
|
611
|
+
chmod 700 "$home" 2>/dev/null || true
|
|
612
|
+
|
|
613
|
+
case "$mode" in
|
|
614
|
+
empty)
|
|
615
|
+
:
|
|
616
|
+
;;
|
|
617
|
+
from-default)
|
|
618
|
+
sync_overwrite_excluding_auth "$DEFAULT_HOME" "$home"
|
|
619
|
+
;;
|
|
620
|
+
from-env)
|
|
621
|
+
validate_env_name "$src_env"
|
|
622
|
+
require_env_exists "$src_env"
|
|
623
|
+
src="$(env_home_path "$src_env")"
|
|
624
|
+
sync_overwrite_excluding_auth "$src" "$home"
|
|
344
625
|
;;
|
|
345
626
|
*)
|
|
346
|
-
|
|
347
|
-
return 1
|
|
627
|
+
err "unknown env create mode: $mode"
|
|
348
628
|
;;
|
|
349
629
|
esac
|
|
630
|
+
|
|
631
|
+
log_event INFO "env_create env=$env mode=$mode src=$src_env"
|
|
632
|
+
echo "Created env: $env"
|
|
350
633
|
}
|
|
351
634
|
|
|
352
|
-
|
|
353
|
-
local
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
635
|
+
_cmd_env_use_target() {
|
|
636
|
+
local target="$1"
|
|
637
|
+
local env="$2"
|
|
638
|
+
local account
|
|
639
|
+
|
|
640
|
+
account="$(read_current_account "$target" || true)"
|
|
641
|
+
set_current_env "$target" "$env"
|
|
642
|
+
if account_has_auth "$env" "$account"; then
|
|
643
|
+
set_current_account "$target" "$account"
|
|
644
|
+
install_account_auth_to_env "$env" "$account"
|
|
645
|
+
else
|
|
646
|
+
set_current_account "$target" "$DEFAULT_ACCOUNT_NAME"
|
|
647
|
+
if account_has_auth "$env" "$DEFAULT_ACCOUNT_NAME"; then
|
|
648
|
+
install_account_auth_to_env "$env" "$DEFAULT_ACCOUNT_NAME"
|
|
649
|
+
else
|
|
650
|
+
clear_env_auth "$env"
|
|
651
|
+
fi
|
|
652
|
+
fi
|
|
358
653
|
}
|
|
359
654
|
|
|
360
|
-
|
|
361
|
-
local
|
|
362
|
-
local
|
|
363
|
-
local cli_cur app_cur
|
|
655
|
+
cmd_env_use() {
|
|
656
|
+
local env="$1"
|
|
657
|
+
local target="$2"
|
|
364
658
|
|
|
365
|
-
|
|
366
|
-
|
|
659
|
+
require_env_exists "$env"
|
|
660
|
+
with_targets "$target" _cmd_env_use_target "$env"
|
|
661
|
+
log_event INFO "env_use env=$env target=$target"
|
|
662
|
+
echo "Switched $target env to: $env"
|
|
663
|
+
}
|
|
367
664
|
|
|
368
|
-
|
|
369
|
-
|
|
665
|
+
cmd_env_remove() {
|
|
666
|
+
local env="$1"
|
|
667
|
+
local force="$2"
|
|
668
|
+
local cli_env app_env
|
|
370
669
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
670
|
+
validate_env_name "$env"
|
|
671
|
+
[[ "$env" != "$DEFAULT_ENV_NAME" ]] || err "cannot remove reserved env '$DEFAULT_ENV_NAME'"
|
|
672
|
+
env_exists "$env" || err "env '$env' not found"
|
|
673
|
+
|
|
674
|
+
cli_env="$(read_current_env cli || true)"
|
|
675
|
+
app_env="$(read_current_env app || true)"
|
|
377
676
|
|
|
378
|
-
if [[ "$force" != "true" ]]; then
|
|
379
|
-
|
|
677
|
+
if [[ "$env" == "$cli_env" && "$force" != "true" ]]; then
|
|
678
|
+
err "env '$env' is current CLI env; use --force to remove"
|
|
679
|
+
fi
|
|
680
|
+
if [[ "$env" == "$app_env" && "$force" != "true" ]]; then
|
|
681
|
+
err "env '$env' is current App env; use --force to remove"
|
|
380
682
|
fi
|
|
381
683
|
|
|
382
|
-
if [[ "$
|
|
684
|
+
if [[ "$env" == "$app_env" ]]; then
|
|
383
685
|
app_stop_managed >/dev/null
|
|
384
|
-
|
|
686
|
+
set_current_env app "$DEFAULT_ENV_NAME"
|
|
687
|
+
set_current_account app "$DEFAULT_ACCOUNT_NAME"
|
|
688
|
+
ensure_target_auth_installed app
|
|
385
689
|
fi
|
|
386
|
-
if [[ "$
|
|
387
|
-
|
|
690
|
+
if [[ "$env" == "$cli_env" ]]; then
|
|
691
|
+
set_current_env cli "$DEFAULT_ENV_NAME"
|
|
692
|
+
set_current_account cli "$DEFAULT_ACCOUNT_NAME"
|
|
693
|
+
ensure_target_auth_installed cli
|
|
388
694
|
fi
|
|
389
695
|
|
|
390
|
-
rm -rf -- "$(
|
|
391
|
-
log_event INFO "
|
|
392
|
-
echo "Removed
|
|
696
|
+
rm -rf -- "$(env_root_path "$env")" "$ACCOUNTS_DIR/$env"
|
|
697
|
+
log_event INFO "env_remove env=$env force=$force"
|
|
698
|
+
echo "Removed env: $env"
|
|
393
699
|
}
|
|
394
700
|
|
|
395
|
-
|
|
396
|
-
local
|
|
397
|
-
|
|
398
|
-
|
|
701
|
+
cmd_env_current() {
|
|
702
|
+
local target="${1:-all}"
|
|
703
|
+
case "$target" in
|
|
704
|
+
cli)
|
|
705
|
+
read_current_env cli || true
|
|
706
|
+
;;
|
|
707
|
+
app)
|
|
708
|
+
read_current_env app || true
|
|
709
|
+
;;
|
|
710
|
+
all)
|
|
711
|
+
echo "cli: $(read_current_env cli || true)"
|
|
712
|
+
echo "app: $(read_current_env app || true)"
|
|
713
|
+
;;
|
|
714
|
+
*)
|
|
715
|
+
err "invalid target '$target' (use cli|app)"
|
|
716
|
+
;;
|
|
717
|
+
esac
|
|
718
|
+
}
|
|
399
719
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
720
|
+
cmd_env_path() {
|
|
721
|
+
local env="${1:-$(read_current_env cli || true)}"
|
|
722
|
+
validate_env_name "$env"
|
|
723
|
+
require_env_exists "$env"
|
|
724
|
+
echo "export CODEX_HOME='$(env_home_path "$env")'"
|
|
725
|
+
}
|
|
404
726
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
727
|
+
cmd_account_add() {
|
|
728
|
+
local account="$1"
|
|
729
|
+
local env="$2"
|
|
730
|
+
validate_account_name "$account"
|
|
731
|
+
require_env_exists "$env"
|
|
732
|
+
ensure_account_slot "$env" "$account"
|
|
733
|
+
log_event INFO "account_add env=$env account=$account"
|
|
734
|
+
echo "Added account slot: $env/$account"
|
|
412
735
|
}
|
|
413
736
|
|
|
414
|
-
|
|
415
|
-
local
|
|
416
|
-
local
|
|
737
|
+
cmd_account_remove() {
|
|
738
|
+
local account="$1"
|
|
739
|
+
local env="$2"
|
|
417
740
|
local force="$3"
|
|
418
|
-
local
|
|
741
|
+
local cli_env app_env cli_account app_account
|
|
419
742
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
[[ -d "$src" ]] || err "default codex home not found: $src"
|
|
423
|
-
ensure_profile "$profile"
|
|
424
|
-
dst="$(profile_path "$profile")"
|
|
743
|
+
validate_account_name "$account"
|
|
744
|
+
validate_env_name "$env"
|
|
425
745
|
|
|
426
|
-
if [[ "$
|
|
427
|
-
|
|
428
|
-
else
|
|
429
|
-
if find "$dst" -mindepth 1 -maxdepth 1 | grep -q .; then
|
|
430
|
-
err "profile '$profile' is not empty. use --force to overwrite"
|
|
431
|
-
fi
|
|
746
|
+
if [[ ! -d "$(account_dir_path "$env" "$account")" ]] && ! account_has_auth "$env" "$account"; then
|
|
747
|
+
err "account '$account' not found in env '$env'"
|
|
432
748
|
fi
|
|
433
749
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
(cd "$src" && tar cf - --exclude ./auth.json .) | (cd "$dst" && tar xpf -)
|
|
445
|
-
fi
|
|
750
|
+
cli_env="$(read_current_env cli || true)"
|
|
751
|
+
app_env="$(read_current_env app || true)"
|
|
752
|
+
cli_account="$(read_current_account cli || true)"
|
|
753
|
+
app_account="$(read_current_account app || true)"
|
|
754
|
+
|
|
755
|
+
if [[ "$env" == "$cli_env" && "$account" == "$cli_account" && "$force" != "true" ]]; then
|
|
756
|
+
err "account '$account' is current CLI account in env '$env'; use --force to remove"
|
|
757
|
+
fi
|
|
758
|
+
if [[ "$env" == "$app_env" && "$account" == "$app_account" && "$force" != "true" ]]; then
|
|
759
|
+
err "account '$account' is current App account in env '$env'; use --force to remove"
|
|
446
760
|
fi
|
|
447
761
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
762
|
+
rm -rf -- "$(account_dir_path "$env" "$account")"
|
|
763
|
+
if [[ "$account" == "$DEFAULT_ACCOUNT_NAME" ]]; then
|
|
764
|
+
rm -f -- "$(env_home_path "$env")/auth.json"
|
|
765
|
+
fi
|
|
766
|
+
|
|
767
|
+
if [[ "$env" == "$cli_env" && "$account" == "$cli_account" ]]; then
|
|
768
|
+
set_current_account cli "$DEFAULT_ACCOUNT_NAME"
|
|
769
|
+
ensure_target_auth_installed cli
|
|
770
|
+
fi
|
|
771
|
+
if [[ "$env" == "$app_env" && "$account" == "$app_account" ]]; then
|
|
772
|
+
set_current_account app "$DEFAULT_ACCOUNT_NAME"
|
|
773
|
+
ensure_target_auth_installed app
|
|
453
774
|
fi
|
|
775
|
+
|
|
776
|
+
log_event INFO "account_remove env=$env account=$account force=$force"
|
|
777
|
+
echo "Removed account slot: $env/$account"
|
|
454
778
|
}
|
|
455
779
|
|
|
456
|
-
|
|
457
|
-
local
|
|
458
|
-
local
|
|
780
|
+
cmd_account_list() {
|
|
781
|
+
local env="$1"
|
|
782
|
+
local cli_env app_env cli_account app_account found account marks
|
|
783
|
+
require_env_exists "$env"
|
|
459
784
|
|
|
460
|
-
|
|
461
|
-
|
|
785
|
+
cli_env="$(read_current_env cli || true)"
|
|
786
|
+
app_env="$(read_current_env app || true)"
|
|
787
|
+
cli_account="$(read_current_account cli || true)"
|
|
788
|
+
app_account="$(read_current_account app || true)"
|
|
789
|
+
found=0
|
|
462
790
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
791
|
+
while IFS= read -r account; do
|
|
792
|
+
found=1
|
|
793
|
+
marks=""
|
|
794
|
+
[[ "$env" == "$cli_env" && "$account" == "$cli_account" ]] && marks="${marks} [cli-current]"
|
|
795
|
+
[[ "$env" == "$app_env" && "$account" == "$app_account" ]] && marks="${marks} [app-current]"
|
|
796
|
+
echo "- $account$marks"
|
|
797
|
+
done < <(list_accounts_for_env "$env")
|
|
798
|
+
|
|
799
|
+
if [[ "$found" -eq 0 ]]; then
|
|
800
|
+
echo "No accounts in env '$env'. Use: $SCRIPT_NAME account login <account> --env $env"
|
|
468
801
|
fi
|
|
469
|
-
chmod 700 "$dst" 2>/dev/null || true
|
|
470
802
|
}
|
|
471
803
|
|
|
472
|
-
|
|
473
|
-
local
|
|
474
|
-
local
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
log_event INFO "sync_default profile=$profile src=$src"
|
|
481
|
-
echo "Synced default data to profile: $profile (auth.json excluded)"
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
sync_profile_to_profile() {
|
|
485
|
-
local from_profile="$1"
|
|
486
|
-
local to_profile="$2"
|
|
487
|
-
local src dst
|
|
804
|
+
_cmd_account_set_target() {
|
|
805
|
+
local target="$1"
|
|
806
|
+
local env="$2"
|
|
807
|
+
local account="$3"
|
|
808
|
+
set_current_env "$target" "$env"
|
|
809
|
+
set_current_account "$target" "$account"
|
|
810
|
+
install_account_auth_to_env "$env" "$account"
|
|
811
|
+
}
|
|
488
812
|
|
|
489
|
-
|
|
490
|
-
|
|
813
|
+
cmd_account_login() {
|
|
814
|
+
local account="$1"
|
|
815
|
+
local env="$2"
|
|
816
|
+
local target="$3"
|
|
817
|
+
local sync_mode="$4"
|
|
818
|
+
local home
|
|
819
|
+
|
|
820
|
+
validate_account_name "$account"
|
|
821
|
+
require_env_exists "$env"
|
|
822
|
+
ensure_env_home "$env"
|
|
823
|
+
home="$(env_home_path "$env")"
|
|
824
|
+
|
|
825
|
+
if [[ "$sync_mode" == "true" && "$env" != "$DEFAULT_ENV_NAME" ]]; then
|
|
826
|
+
sync_overwrite_excluding_auth "$DEFAULT_HOME" "$home"
|
|
491
827
|
fi
|
|
492
828
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
log_event INFO "
|
|
499
|
-
echo "
|
|
829
|
+
CODEX_HOME="$home" command codex login
|
|
830
|
+
save_env_auth_to_account "$env" "$account" || err "login did not produce auth.json in $home"
|
|
831
|
+
|
|
832
|
+
with_targets "$target" _cmd_account_set_target "$env" "$account"
|
|
833
|
+
|
|
834
|
+
log_event INFO "account_login env=$env account=$account target=$target sync=$sync_mode"
|
|
835
|
+
echo "Logged in account: $env/$account"
|
|
500
836
|
}
|
|
501
837
|
|
|
502
|
-
|
|
503
|
-
local
|
|
504
|
-
local
|
|
505
|
-
local
|
|
506
|
-
|
|
838
|
+
cmd_account_use() {
|
|
839
|
+
local account="$1"
|
|
840
|
+
local env="$2"
|
|
841
|
+
local target="$3"
|
|
842
|
+
local sync_mode="$4"
|
|
843
|
+
|
|
844
|
+
validate_account_name "$account"
|
|
845
|
+
require_env_exists "$env"
|
|
846
|
+
account_has_auth "$env" "$account" || err "account '$account' in env '$env' has no auth.json. run: $SCRIPT_NAME account login $account --env $env"
|
|
507
847
|
|
|
508
848
|
if [[ "$sync_mode" == "true" ]]; then
|
|
509
|
-
|
|
510
|
-
validate_profile_name "$from_profile"
|
|
511
|
-
sync_profile_to_profile "$from_profile" "$profile"
|
|
849
|
+
warn "same-env account switch only replaces auth.json; --sync is ignored"
|
|
512
850
|
fi
|
|
513
851
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
852
|
+
with_targets "$target" _cmd_account_set_target "$env" "$account"
|
|
853
|
+
log_event INFO "account_use env=$env account=$account target=$target"
|
|
854
|
+
echo "Switched $target account to: $env/$account"
|
|
517
855
|
}
|
|
518
856
|
|
|
519
|
-
|
|
520
|
-
|
|
857
|
+
cmd_account_logout() {
|
|
858
|
+
local account="$1"
|
|
859
|
+
local env="$2"
|
|
860
|
+
local target="$3"
|
|
861
|
+
local cli_env app_env cli_account app_account
|
|
862
|
+
|
|
863
|
+
validate_env_name "$env"
|
|
864
|
+
if [[ -z "$account" ]]; then
|
|
865
|
+
if [[ "$target" == "both" ]]; then
|
|
866
|
+
account="$(read_current_account cli || true)"
|
|
867
|
+
else
|
|
868
|
+
account="$(read_current_account "$target" || true)"
|
|
869
|
+
fi
|
|
870
|
+
fi
|
|
871
|
+
validate_account_name "$account"
|
|
872
|
+
require_env_exists "$env"
|
|
873
|
+
|
|
874
|
+
rm -f -- "$(account_auth_path "$env" "$account")"
|
|
875
|
+
|
|
876
|
+
cli_env="$(read_current_env cli || true)"
|
|
877
|
+
app_env="$(read_current_env app || true)"
|
|
878
|
+
cli_account="$(read_current_account cli || true)"
|
|
879
|
+
app_account="$(read_current_account app || true)"
|
|
880
|
+
|
|
881
|
+
if [[ "$env" == "$cli_env" && "$account" == "$cli_account" ]]; then
|
|
882
|
+
set_current_account cli "$DEFAULT_ACCOUNT_NAME"
|
|
883
|
+
ensure_target_auth_installed cli
|
|
884
|
+
fi
|
|
885
|
+
if [[ "$env" == "$app_env" && "$account" == "$app_account" ]]; then
|
|
886
|
+
set_current_account app "$DEFAULT_ACCOUNT_NAME"
|
|
887
|
+
ensure_target_auth_installed app
|
|
888
|
+
fi
|
|
889
|
+
|
|
890
|
+
if [[ "$account" == "$DEFAULT_ACCOUNT_NAME" ]]; then
|
|
891
|
+
rm -f -- "$(env_home_path "$env")/auth.json"
|
|
892
|
+
fi
|
|
893
|
+
|
|
894
|
+
log_event INFO "account_logout env=$env account=$account target=$target"
|
|
895
|
+
echo "Logged out account: $env/$account"
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
cmd_account_current() {
|
|
899
|
+
local target="${1:-all}"
|
|
900
|
+
case "$target" in
|
|
901
|
+
cli)
|
|
902
|
+
echo "$(read_current_env cli || true)/$(read_current_account cli || true)"
|
|
903
|
+
;;
|
|
904
|
+
app)
|
|
905
|
+
echo "$(read_current_env app || true)/$(read_current_account app || true)"
|
|
906
|
+
;;
|
|
907
|
+
all)
|
|
908
|
+
echo "cli: $(read_current_env cli || true)/$(read_current_account cli || true)"
|
|
909
|
+
echo "app: $(read_current_env app || true)/$(read_current_account app || true)"
|
|
910
|
+
;;
|
|
911
|
+
*)
|
|
912
|
+
err "invalid target '$target' (use cli|app)"
|
|
913
|
+
;;
|
|
914
|
+
esac
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
cmd_list() {
|
|
918
|
+
local cli_env app_env cli_account app_account
|
|
919
|
+
local env account marks auth_file home metrics
|
|
920
|
+
local email plan usage_5h usage_weekly last_activity source
|
|
921
|
+
|
|
922
|
+
cli_env="$(read_current_env cli || true)"
|
|
923
|
+
app_env="$(read_current_env app || true)"
|
|
924
|
+
cli_account="$(read_current_account cli || true)"
|
|
925
|
+
app_account="$(read_current_account app || true)"
|
|
926
|
+
|
|
927
|
+
printf '%-12s %-30s %-44s %-10s %-16s %-18s %s\n' "ENV" "ACCOUNT" "EMAIL" "PLAN" "5H USAGE" "WEEKLY USAGE" "LAST ACTIVITY"
|
|
928
|
+
while IFS= read -r env; do
|
|
929
|
+
home="$(env_home_path "$env")"
|
|
930
|
+
ensure_env_home "$env"
|
|
931
|
+
local found=0
|
|
932
|
+
while IFS= read -r account; do
|
|
933
|
+
found=1
|
|
934
|
+
marks=""
|
|
935
|
+
[[ "$env" == "$cli_env" && "$account" == "$cli_account" ]] && marks="${marks} [cli-current]"
|
|
936
|
+
[[ "$env" == "$app_env" && "$account" == "$app_account" ]] && marks="${marks} [app-current]"
|
|
937
|
+
auth_file="$(account_auth_path "$env" "$account")"
|
|
938
|
+
[[ -f "$auth_file" ]] || auth_file="$home/auth.json"
|
|
939
|
+
|
|
940
|
+
metrics="$(collect_profile_metrics_tsv "$account" "$auth_file" "$home" || true)"
|
|
941
|
+
if [[ -n "$metrics" ]]; then
|
|
942
|
+
IFS=$'\t' read -r email plan usage_5h usage_weekly last_activity source <<< "$metrics"
|
|
943
|
+
fi
|
|
944
|
+
email="${email:-($account)-}"
|
|
945
|
+
plan="${plan:-unknown}"
|
|
946
|
+
usage_5h="${usage_5h:--}"
|
|
947
|
+
usage_weekly="${usage_weekly:--}"
|
|
948
|
+
last_activity="${last_activity:--}"
|
|
949
|
+
source="${source:-local}"
|
|
950
|
+
[[ "$source" == "api" || "$source" == "local" ]] || source="local"
|
|
951
|
+
last_activity="${last_activity} (${source})"
|
|
952
|
+
|
|
953
|
+
printf '%-12s %-30s %-44s %-10s %-16s %-18s %s\n' "$env" "$account$marks" "$email" "$plan" "$usage_5h" "$usage_weekly" "$last_activity"
|
|
954
|
+
done < <(list_accounts_for_env "$env")
|
|
955
|
+
|
|
956
|
+
if [[ "$found" -eq 0 ]]; then
|
|
957
|
+
metrics="$(collect_profile_metrics_tsv "-" "$home/auth.json" "$home" || true)"
|
|
958
|
+
if [[ -n "$metrics" ]]; then
|
|
959
|
+
IFS=$'\t' read -r email plan usage_5h usage_weekly last_activity source <<< "$metrics"
|
|
960
|
+
fi
|
|
961
|
+
email="${email:--}"
|
|
962
|
+
plan="${plan:-unknown}"
|
|
963
|
+
usage_5h="${usage_5h:--}"
|
|
964
|
+
usage_weekly="${usage_weekly:--}"
|
|
965
|
+
last_activity="${last_activity:--}"
|
|
966
|
+
source="${source:-local}"
|
|
967
|
+
[[ "$source" == "api" || "$source" == "local" ]] || source="local"
|
|
968
|
+
last_activity="${last_activity} (${source})"
|
|
969
|
+
printf '%-12s %-30s %-44s %-10s %-16s %-18s %s\n' "$env" "-" "$email" "$plan" "$usage_5h" "$usage_weekly" "$last_activity"
|
|
970
|
+
fi
|
|
971
|
+
done < <(list_env_names | sort -u)
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
cmd_add() {
|
|
975
|
+
local account="$1"
|
|
976
|
+
local env
|
|
977
|
+
env="$(read_current_env cli || true)"
|
|
978
|
+
cmd_account_add "$account" "$env"
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
cmd_remove() {
|
|
982
|
+
local account="$1"
|
|
983
|
+
local force="$2"
|
|
984
|
+
local env
|
|
985
|
+
env="$(read_current_env cli || true)"
|
|
986
|
+
cmd_account_remove "$account" "$env" "$force"
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
cmd_import_default() {
|
|
990
|
+
local env="$1"
|
|
991
|
+
local with_auth="$2"
|
|
992
|
+
local force="$3"
|
|
993
|
+
|
|
994
|
+
validate_env_name "$env"
|
|
995
|
+
[[ "$env" != "$DEFAULT_ENV_NAME" ]] || err "cannot import into reserved env '$DEFAULT_ENV_NAME'"
|
|
996
|
+
|
|
997
|
+
if env_exists "$env"; then
|
|
998
|
+
if [[ "$force" != "true" ]]; then
|
|
999
|
+
err "env '$env' already exists. use --force to overwrite"
|
|
1000
|
+
fi
|
|
1001
|
+
rm -rf -- "$(env_root_path "$env")" "$ACCOUNTS_DIR/$env"
|
|
1002
|
+
fi
|
|
1003
|
+
|
|
1004
|
+
cmd_env_create "$env" "from-default" ""
|
|
1005
|
+
if [[ "$with_auth" == "true" && -f "$DEFAULT_HOME/auth.json" ]]; then
|
|
1006
|
+
ensure_account_slot "$env" "$DEFAULT_ACCOUNT_NAME"
|
|
1007
|
+
copy_auth_file "$DEFAULT_HOME/auth.json" "$(account_auth_path "$env" "$DEFAULT_ACCOUNT_NAME")"
|
|
1008
|
+
fi
|
|
1009
|
+
|
|
1010
|
+
log_event INFO "import_default_as_env env=$env with_auth=$with_auth force=$force"
|
|
1011
|
+
echo "Imported default data to env: $env"
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
cmd_use_compat() {
|
|
1015
|
+
local account="$1"
|
|
1016
|
+
local sync_mode="${2:-false}"
|
|
1017
|
+
local env
|
|
1018
|
+
env="$(read_current_env cli || true)"
|
|
1019
|
+
cmd_account_use "$account" "$env" "cli" "$sync_mode"
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
cmd_switch_compat() {
|
|
1023
|
+
cmd_use_compat "$1" "${2:-false}"
|
|
521
1024
|
}
|
|
522
1025
|
|
|
523
1026
|
should_launch_codex() {
|
|
@@ -540,17 +1043,17 @@ should_launch_codex() {
|
|
|
540
1043
|
|
|
541
1044
|
cmd_use_and_maybe_launch() {
|
|
542
1045
|
local mode_cmd="$1"
|
|
543
|
-
local
|
|
1046
|
+
local account="$2"
|
|
544
1047
|
local sync_mode="${3:-false}"
|
|
545
1048
|
local launch_mode="${4:-auto}"
|
|
546
1049
|
shift 4 || true
|
|
547
1050
|
|
|
548
|
-
with_lock "$mode_cmd" "$
|
|
1051
|
+
with_lock "$mode_cmd" "$account" "$sync_mode"
|
|
549
1052
|
|
|
550
|
-
echo "Switched CLI
|
|
1053
|
+
echo "Switched CLI account to: $(read_current_env cli || true)/$(read_current_account cli || true)"
|
|
551
1054
|
if should_launch_codex "$launch_mode"; then
|
|
552
|
-
echo "Launching codex with
|
|
553
|
-
|
|
1055
|
+
echo "Launching codex with env/account: $(read_current_env cli || true)/$(read_current_account cli || true)"
|
|
1056
|
+
run_codex_for_target cli "$@"
|
|
554
1057
|
return
|
|
555
1058
|
fi
|
|
556
1059
|
|
|
@@ -558,21 +1061,21 @@ cmd_use_and_maybe_launch() {
|
|
|
558
1061
|
echo "Auto launch skipped (non-interactive shell). Use --launch to force start."
|
|
559
1062
|
fi
|
|
560
1063
|
echo "Run in current shell if needed:"
|
|
561
|
-
echo " export CODEX_HOME='$(
|
|
1064
|
+
echo " export CODEX_HOME='$(target_home_path cli)'"
|
|
562
1065
|
}
|
|
563
1066
|
|
|
564
1067
|
cmd_current() {
|
|
565
1068
|
local target="${1:-all}"
|
|
566
1069
|
case "$target" in
|
|
567
1070
|
cli)
|
|
568
|
-
|
|
1071
|
+
echo "$(read_current_env cli || true)/$(read_current_account cli || true)"
|
|
569
1072
|
;;
|
|
570
1073
|
app)
|
|
571
|
-
|
|
1074
|
+
echo "$(read_current_env app || true)/$(read_current_account app || true)"
|
|
572
1075
|
;;
|
|
573
1076
|
all)
|
|
574
|
-
echo "cli: $(
|
|
575
|
-
echo "app: $(
|
|
1077
|
+
echo "cli: $(read_current_env cli || true)/$(read_current_account cli || true)"
|
|
1078
|
+
echo "app: $(read_current_env app || true)/$(read_current_account app || true)"
|
|
576
1079
|
;;
|
|
577
1080
|
*)
|
|
578
1081
|
err "invalid target '$target' (use cli|app)"
|
|
@@ -581,31 +1084,31 @@ cmd_current() {
|
|
|
581
1084
|
}
|
|
582
1085
|
|
|
583
1086
|
cmd_status() {
|
|
584
|
-
local
|
|
585
|
-
local cli_ptr_state app_ptr_state
|
|
586
|
-
local cli_state app_state
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
1087
|
+
local cli_env app_env cli_account app_account
|
|
1088
|
+
local cli_ptr_state app_ptr_state cli_acc_state app_acc_state
|
|
1089
|
+
local cli_state app_state exit_code
|
|
1090
|
+
|
|
1091
|
+
cli_env="$(read_current_env cli)" || cli_ptr_state=$?
|
|
1092
|
+
app_env="$(read_current_env app)" || app_ptr_state=$?
|
|
1093
|
+
cli_account="$(read_current_account cli)" || cli_acc_state=$?
|
|
1094
|
+
app_account="$(read_current_account app)" || app_acc_state=$?
|
|
591
1095
|
cli_ptr_state="${cli_ptr_state:-0}"
|
|
592
1096
|
app_ptr_state="${app_ptr_state:-0}"
|
|
1097
|
+
cli_acc_state="${cli_acc_state:-0}"
|
|
1098
|
+
app_acc_state="${app_acc_state:-0}"
|
|
593
1099
|
|
|
594
|
-
cli_state="$(
|
|
595
|
-
app_state="$(
|
|
1100
|
+
cli_state="$(login_state_for_target cli)"
|
|
1101
|
+
app_state="$(login_state_for_target app)"
|
|
596
1102
|
|
|
597
|
-
echo "cli_current: $
|
|
598
|
-
echo "app_current: $
|
|
599
|
-
echo "cli($
|
|
600
|
-
echo "app($
|
|
1103
|
+
echo "cli_current: $cli_env/$cli_account"
|
|
1104
|
+
echo "app_current: $app_env/$app_account"
|
|
1105
|
+
echo "cli($cli_env/$cli_account): $cli_state"
|
|
1106
|
+
echo "app($app_env/$app_account): $app_state"
|
|
601
1107
|
|
|
602
1108
|
exit_code=0
|
|
603
|
-
if [[ "$cli_ptr_state" -eq 2 || "$app_ptr_state" -eq 2 ]]; then
|
|
1109
|
+
if [[ "$cli_ptr_state" -eq 2 || "$app_ptr_state" -eq 2 || "$cli_acc_state" -eq 2 || "$app_acc_state" -eq 2 ]]; then
|
|
604
1110
|
echo "hint: pointer file corrupted, run: $SCRIPT_NAME recover" >&2
|
|
605
1111
|
exit_code=2
|
|
606
|
-
elif [[ "$cli_state" == "missing-profile" || "$app_state" == "missing-profile" ]]; then
|
|
607
|
-
echo "hint: missing profile directory, run: $SCRIPT_NAME recover" >&2
|
|
608
|
-
exit_code=2
|
|
609
1112
|
elif [[ "$cli_state" != "logged-in" || "$app_state" != "logged-in" ]]; then
|
|
610
1113
|
exit_code=1
|
|
611
1114
|
fi
|
|
@@ -619,85 +1122,76 @@ cmd_exec() {
|
|
|
619
1122
|
shift
|
|
620
1123
|
fi
|
|
621
1124
|
[[ "$#" -gt 0 ]] || err "missing codex args after --"
|
|
622
|
-
|
|
623
|
-
local profile
|
|
624
|
-
profile="$(read_current cli || true)"
|
|
625
|
-
ensure_profile "$profile"
|
|
626
|
-
CODEX_HOME="$(profile_path "$profile")" command codex "$@"
|
|
1125
|
+
run_codex_for_target cli "$@"
|
|
627
1126
|
}
|
|
628
1127
|
|
|
629
1128
|
cmd_login() {
|
|
630
|
-
local
|
|
1129
|
+
local account="${1:-$(read_current_account cli || true)}"
|
|
631
1130
|
local sync_mode="${2:-false}"
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
sync_default_to_profile "$profile"
|
|
636
|
-
fi
|
|
637
|
-
log_event INFO "cli_login profile=$profile sync=$sync_mode"
|
|
638
|
-
run_codex_for_profile "$profile" login
|
|
1131
|
+
local env
|
|
1132
|
+
env="$(read_current_env cli || true)"
|
|
1133
|
+
cmd_account_login "$account" "$env" "cli" "$sync_mode"
|
|
639
1134
|
}
|
|
640
1135
|
|
|
641
1136
|
cmd_logout() {
|
|
642
|
-
local
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
run_codex_for_profile "$profile" logout
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
cmd_env() {
|
|
650
|
-
local profile="${1:-$(read_current cli || true)}"
|
|
651
|
-
validate_profile_name "$profile"
|
|
652
|
-
ensure_profile "$profile"
|
|
653
|
-
echo "export CODEX_HOME='$(profile_path "$profile")'"
|
|
1137
|
+
local account="${1:-}"
|
|
1138
|
+
local env
|
|
1139
|
+
env="$(read_current_env cli || true)"
|
|
1140
|
+
cmd_account_logout "$account" "$env" "cli"
|
|
654
1141
|
}
|
|
655
1142
|
|
|
656
1143
|
cmd_app_open() {
|
|
657
|
-
local
|
|
658
|
-
shift
|
|
659
|
-
local app_bin pid login_state
|
|
1144
|
+
local account="${1:-}"
|
|
1145
|
+
shift || true
|
|
1146
|
+
local env app_bin pid login_state use_account
|
|
1147
|
+
|
|
1148
|
+
env="$(read_current_env app || true)"
|
|
1149
|
+
use_account="${account:-$(read_current_account app || true)}"
|
|
1150
|
+
validate_account_name "$use_account"
|
|
1151
|
+
require_env_exists "$env"
|
|
1152
|
+
account_has_auth "$env" "$use_account" || err "account '$use_account' not logged in under env '$env'. run: $SCRIPT_NAME account login $use_account --env $env --target app"
|
|
1153
|
+
|
|
1154
|
+
set_current_env app "$env"
|
|
1155
|
+
set_current_account app "$use_account"
|
|
1156
|
+
ensure_target_auth_installed app
|
|
660
1157
|
|
|
661
|
-
|
|
662
|
-
require_profile_exists "$profile"
|
|
663
|
-
login_state="$(login_state_for_profile "$profile")"
|
|
1158
|
+
login_state="$(login_state_for_target app)"
|
|
664
1159
|
if [[ "$login_state" != "logged-in" ]]; then
|
|
665
|
-
err "
|
|
1160
|
+
err "account '$use_account' in env '$env' is not logged in"
|
|
666
1161
|
fi
|
|
667
1162
|
app_bin="$(resolve_app_bin)"
|
|
668
1163
|
|
|
669
1164
|
app_stop_managed >/dev/null
|
|
670
1165
|
|
|
671
1166
|
mkdir -p "$(dirname "$APP_LOG")"
|
|
672
|
-
nohup env CODEX_HOME="$(
|
|
1167
|
+
nohup env CODEX_HOME="$(target_home_path app)" CODEX_SWITCHER_MANAGED=1 CODEX_SWITCHER_ENV="$env" CODEX_SWITCHER_ACCOUNT="$use_account" "$app_bin" "$@" >>"$APP_LOG" 2>&1 &
|
|
673
1168
|
pid="$!"
|
|
674
1169
|
printf '%s\n' "$pid" > "$APP_PID_FILE"
|
|
675
1170
|
chmod 600 "$APP_PID_FILE" 2>/dev/null || true
|
|
676
1171
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
echo "Opened Codex App with profile: $profile"
|
|
1172
|
+
log_event INFO "app_open env=$env account=$use_account pid=$pid args=$*"
|
|
1173
|
+
echo "Opened Codex App with: $env/$use_account"
|
|
680
1174
|
echo "App log: $APP_LOG"
|
|
681
1175
|
}
|
|
682
1176
|
|
|
683
1177
|
cmd_app_use() {
|
|
684
|
-
local
|
|
685
|
-
shift
|
|
686
|
-
cmd_app_open "$
|
|
1178
|
+
local account="$1"
|
|
1179
|
+
shift || true
|
|
1180
|
+
cmd_app_open "$account" "$@"
|
|
687
1181
|
}
|
|
688
1182
|
|
|
689
1183
|
cmd_app_logout() {
|
|
690
|
-
local
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
run_codex_for_profile "$profile" logout
|
|
1184
|
+
local account="${1:-}"
|
|
1185
|
+
local env
|
|
1186
|
+
env="$(read_current_env app || true)"
|
|
1187
|
+
cmd_account_logout "$account" "$env" "app"
|
|
695
1188
|
}
|
|
696
1189
|
|
|
697
1190
|
cmd_app_status() {
|
|
698
|
-
local
|
|
699
|
-
|
|
700
|
-
|
|
1191
|
+
local env account
|
|
1192
|
+
env="$(read_current_env app || true)"
|
|
1193
|
+
account="$(read_current_account app || true)"
|
|
1194
|
+
echo "app_current: $env/$account"
|
|
701
1195
|
if app_is_running; then
|
|
702
1196
|
echo "app_process: running(pid=$(cat "$APP_PID_FILE"))"
|
|
703
1197
|
return 0
|
|
@@ -801,44 +1295,34 @@ cmd_upgrade() {
|
|
|
801
1295
|
|
|
802
1296
|
cmd_recover() {
|
|
803
1297
|
local dry_run="${1:-false}"
|
|
804
|
-
local
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
ensure_profile "$cli_profile"
|
|
1298
|
+
local target env account
|
|
1299
|
+
|
|
1300
|
+
for target in cli app; do
|
|
1301
|
+
env="$(read_current_env "$target" || true)"
|
|
1302
|
+
account="$(read_current_account "$target" || true)"
|
|
1303
|
+
validate_env_name_noexit "$env" || env="$DEFAULT_ENV_NAME"
|
|
1304
|
+
if [[ "$env" != "$DEFAULT_ENV_NAME" ]] && [[ ! -d "$(env_home_path "$env")" ]]; then
|
|
1305
|
+
env="$DEFAULT_ENV_NAME"
|
|
1306
|
+
fi
|
|
1307
|
+
validate_name_noexit "$account" || account="$DEFAULT_ACCOUNT_NAME"
|
|
1308
|
+
if ! account_has_auth "$env" "$account"; then
|
|
1309
|
+
account="$DEFAULT_ACCOUNT_NAME"
|
|
817
1310
|
fi
|
|
818
|
-
cli_ptr_state=3
|
|
819
|
-
fi
|
|
820
1311
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
app_profile="$first"
|
|
826
|
-
else
|
|
827
|
-
app_profile="$(default_profile_for app)"
|
|
828
|
-
ensure_profile "$app_profile"
|
|
1312
|
+
if [[ "$dry_run" != "true" ]]; then
|
|
1313
|
+
set_current_env "$target" "$env"
|
|
1314
|
+
set_current_account "$target" "$account"
|
|
1315
|
+
ensure_target_auth_installed "$target"
|
|
829
1316
|
fi
|
|
830
|
-
|
|
831
|
-
|
|
1317
|
+
|
|
1318
|
+
echo "recover($target): $env/$account"
|
|
1319
|
+
done
|
|
832
1320
|
|
|
833
1321
|
if [[ "$dry_run" == "true" ]]; then
|
|
834
|
-
echo "recover(dry-run): cli=$cli_profile app=$app_profile"
|
|
835
1322
|
return 0
|
|
836
1323
|
fi
|
|
837
1324
|
|
|
838
|
-
|
|
839
|
-
set_current app "$app_profile"
|
|
840
|
-
log_event INFO "recover cli=$cli_profile app=$app_profile"
|
|
841
|
-
echo "Recovered pointers: cli=$cli_profile app=$app_profile"
|
|
1325
|
+
log_event INFO "recover cli=$(read_current_env cli || true)/$(read_current_account cli || true) app=$(read_current_env app || true)/$(read_current_account app || true)"
|
|
842
1326
|
}
|
|
843
1327
|
|
|
844
1328
|
scan_logs_for_secrets() {
|
|
@@ -857,39 +1341,53 @@ scan_logs_for_secrets() {
|
|
|
857
1341
|
cmd_check() {
|
|
858
1342
|
command -v codex >/dev/null 2>&1 || err "codex command not found in PATH"
|
|
859
1343
|
resolve_app_bin >/dev/null
|
|
860
|
-
|
|
861
1344
|
ensure_dirs
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1345
|
+
|
|
1346
|
+
local pstate=0
|
|
1347
|
+
read_current_env cli >/dev/null || pstate=$?
|
|
1348
|
+
if [[ "$pstate" -eq 2 ]]; then
|
|
1349
|
+
err "current_cli_env pointer corrupted; run: $SCRIPT_NAME recover"
|
|
866
1350
|
fi
|
|
867
1351
|
pstate=0
|
|
868
|
-
|
|
1352
|
+
read_current_env app >/dev/null || pstate=$?
|
|
869
1353
|
if [[ "$pstate" -eq 2 ]]; then
|
|
870
|
-
err "
|
|
1354
|
+
err "current_app_env pointer corrupted; run: $SCRIPT_NAME recover"
|
|
1355
|
+
fi
|
|
1356
|
+
pstate=0
|
|
1357
|
+
read_current_account cli >/dev/null || pstate=$?
|
|
1358
|
+
if [[ "$pstate" -eq 2 ]]; then
|
|
1359
|
+
err "current_cli_account pointer corrupted; run: $SCRIPT_NAME recover"
|
|
1360
|
+
fi
|
|
1361
|
+
pstate=0
|
|
1362
|
+
read_current_account app >/dev/null || pstate=$?
|
|
1363
|
+
if [[ "$pstate" -eq 2 ]]; then
|
|
1364
|
+
err "current_app_account pointer corrupted; run: $SCRIPT_NAME recover"
|
|
871
1365
|
fi
|
|
872
1366
|
|
|
873
1367
|
if ! scan_logs_for_secrets; then
|
|
874
1368
|
err "log redaction check failed"
|
|
875
1369
|
fi
|
|
876
1370
|
|
|
1371
|
+
echo "version: $(switcher_version)"
|
|
877
1372
|
echo "check: ok"
|
|
878
1373
|
}
|
|
879
1374
|
|
|
880
1375
|
cmd_doctor() {
|
|
881
1376
|
local fix="${1:-false}"
|
|
882
1377
|
local issues=0
|
|
883
|
-
local state_perm
|
|
1378
|
+
local state_perm envs_perm accounts_perm
|
|
884
1379
|
|
|
885
1380
|
ensure_dirs
|
|
886
1381
|
state_perm="$(perm_of "$STATE_DIR")"
|
|
887
|
-
|
|
1382
|
+
envs_perm="$(perm_of "$ENVS_DIR")"
|
|
1383
|
+
accounts_perm="$(perm_of "$ACCOUNTS_DIR")"
|
|
888
1384
|
|
|
889
1385
|
echo "state_dir: $STATE_DIR (perm=$state_perm)"
|
|
890
|
-
echo "
|
|
891
|
-
echo "
|
|
892
|
-
echo "
|
|
1386
|
+
echo "envs_dir: $ENVS_DIR (perm=$envs_perm)"
|
|
1387
|
+
echo "accounts_dir: $ACCOUNTS_DIR (perm=$accounts_perm)"
|
|
1388
|
+
echo "default_home: $DEFAULT_HOME (perm=$(perm_of "$DEFAULT_HOME"))"
|
|
1389
|
+
echo "cli_current: $(read_current_env cli || true)/$(read_current_account cli || true)"
|
|
1390
|
+
echo "app_current: $(read_current_env app || true)/$(read_current_account app || true)"
|
|
893
1391
|
|
|
894
1392
|
if ! command -v codex >/dev/null 2>&1; then
|
|
895
1393
|
echo "- codex in PATH: missing"
|
|
@@ -905,20 +1403,9 @@ cmd_doctor() {
|
|
|
905
1403
|
issues=1
|
|
906
1404
|
fi
|
|
907
1405
|
|
|
908
|
-
if [[ "$state_perm" != "700" ]]; then
|
|
909
|
-
echo "- state dir permission not 700"
|
|
910
|
-
issues=1
|
|
911
|
-
if [[ "$fix" == "true" ]]; then
|
|
912
|
-
chmod 700 "$STATE_DIR" || true
|
|
913
|
-
fi
|
|
914
|
-
fi
|
|
915
|
-
|
|
916
|
-
if [[ "$profiles_perm" != "700" ]]; then
|
|
917
|
-
echo "- profiles dir permission not 700"
|
|
1406
|
+
if [[ "$state_perm" != "700" || "$envs_perm" != "700" || "$accounts_perm" != "700" ]]; then
|
|
918
1407
|
issues=1
|
|
919
|
-
|
|
920
|
-
chmod 700 "$PROFILES_DIR" || true
|
|
921
|
-
fi
|
|
1408
|
+
echo "- directory permissions are not strict 700"
|
|
922
1409
|
fi
|
|
923
1410
|
|
|
924
1411
|
if ! scan_logs_for_secrets; then
|
|
@@ -927,23 +1414,9 @@ cmd_doctor() {
|
|
|
927
1414
|
echo "- redaction check: ok"
|
|
928
1415
|
fi
|
|
929
1416
|
|
|
930
|
-
local pstate=0
|
|
931
|
-
read_current cli >/dev/null || pstate=$?
|
|
932
|
-
if [[ "$pstate" -eq 2 ]]; then
|
|
933
|
-
echo "- current_cli pointer corrupted"
|
|
934
|
-
issues=1
|
|
935
|
-
fi
|
|
936
|
-
pstate=0
|
|
937
|
-
read_current app >/dev/null || pstate=$?
|
|
938
|
-
if [[ "$pstate" -eq 2 ]]; then
|
|
939
|
-
echo "- current_app pointer corrupted"
|
|
940
|
-
issues=1
|
|
941
|
-
fi
|
|
942
|
-
|
|
943
1417
|
if [[ "$fix" == "true" ]]; then
|
|
1418
|
+
chmod 700 "$STATE_DIR" "$ENVS_DIR" "$ACCOUNTS_DIR" "$DEFAULT_HOME" 2>/dev/null || true
|
|
944
1419
|
with_lock cmd_recover false
|
|
945
|
-
chmod 700 "$STATE_DIR" "$PROFILES_DIR" 2>/dev/null || true
|
|
946
|
-
find "$PROFILES_DIR" -mindepth 1 -maxdepth 1 -type d -exec chmod 700 {} \; 2>/dev/null || true
|
|
947
1420
|
issues=0
|
|
948
1421
|
if ! scan_logs_for_secrets; then
|
|
949
1422
|
issues=1
|
|
@@ -974,12 +1447,265 @@ main() {
|
|
|
974
1447
|
shift || true
|
|
975
1448
|
|
|
976
1449
|
case "$cmd" in
|
|
1450
|
+
env)
|
|
1451
|
+
local sub="${1:-}"
|
|
1452
|
+
if [[ -z "$sub" ]]; then
|
|
1453
|
+
usage
|
|
1454
|
+
exit 1
|
|
1455
|
+
fi
|
|
1456
|
+
shift || true
|
|
1457
|
+
case "$sub" in
|
|
1458
|
+
list)
|
|
1459
|
+
[[ "$#" -eq 0 ]] || err "usage: $SCRIPT_NAME env list"
|
|
1460
|
+
cmd_env_list
|
|
1461
|
+
;;
|
|
1462
|
+
create)
|
|
1463
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME env create <env> [--empty|--from-default|--from-env <src>]"
|
|
1464
|
+
local env="$1"
|
|
1465
|
+
shift
|
|
1466
|
+
local mode="from-default"
|
|
1467
|
+
local src_env=""
|
|
1468
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1469
|
+
case "$1" in
|
|
1470
|
+
--empty)
|
|
1471
|
+
mode="empty"
|
|
1472
|
+
;;
|
|
1473
|
+
--from-default)
|
|
1474
|
+
mode="from-default"
|
|
1475
|
+
;;
|
|
1476
|
+
--from-env)
|
|
1477
|
+
shift
|
|
1478
|
+
[[ "$#" -gt 0 ]] || err "missing source env after --from-env"
|
|
1479
|
+
mode="from-env"
|
|
1480
|
+
src_env="$1"
|
|
1481
|
+
;;
|
|
1482
|
+
*)
|
|
1483
|
+
err "unknown option: $1"
|
|
1484
|
+
;;
|
|
1485
|
+
esac
|
|
1486
|
+
shift
|
|
1487
|
+
done
|
|
1488
|
+
with_lock cmd_env_create "$env" "$mode" "$src_env"
|
|
1489
|
+
;;
|
|
1490
|
+
use)
|
|
1491
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME env use <env> [--target cli|app|both]"
|
|
1492
|
+
local env="$1"
|
|
1493
|
+
shift
|
|
1494
|
+
local target="cli"
|
|
1495
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1496
|
+
case "$1" in
|
|
1497
|
+
--target)
|
|
1498
|
+
shift
|
|
1499
|
+
[[ "$#" -gt 0 ]] || err "missing value after --target"
|
|
1500
|
+
target="$1"
|
|
1501
|
+
;;
|
|
1502
|
+
*)
|
|
1503
|
+
err "unknown option: $1"
|
|
1504
|
+
;;
|
|
1505
|
+
esac
|
|
1506
|
+
shift
|
|
1507
|
+
done
|
|
1508
|
+
with_lock cmd_env_use "$env" "$target"
|
|
1509
|
+
;;
|
|
1510
|
+
remove)
|
|
1511
|
+
[[ "$#" -ge 1 && "$#" -le 2 ]] || err "usage: $SCRIPT_NAME env remove <env> [--force]"
|
|
1512
|
+
local env="$1"
|
|
1513
|
+
local force="false"
|
|
1514
|
+
if [[ "${2:-}" == "--force" ]]; then
|
|
1515
|
+
force="true"
|
|
1516
|
+
elif [[ -n "${2:-}" ]]; then
|
|
1517
|
+
err "unknown option: ${2:-}"
|
|
1518
|
+
fi
|
|
1519
|
+
with_lock cmd_env_remove "$env" "$force"
|
|
1520
|
+
;;
|
|
1521
|
+
current)
|
|
1522
|
+
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME env current [cli|app]"
|
|
1523
|
+
cmd_env_current "${1:-all}"
|
|
1524
|
+
;;
|
|
1525
|
+
path)
|
|
1526
|
+
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME env path [env]"
|
|
1527
|
+
cmd_env_path "${1:-}"
|
|
1528
|
+
;;
|
|
1529
|
+
*)
|
|
1530
|
+
err "unknown env subcommand: $sub"
|
|
1531
|
+
;;
|
|
1532
|
+
esac
|
|
1533
|
+
;;
|
|
1534
|
+
account)
|
|
1535
|
+
local sub="${1:-}"
|
|
1536
|
+
[[ -n "$sub" ]] || err "usage: $SCRIPT_NAME account <list|add|remove|login|use|logout|current> ..."
|
|
1537
|
+
shift || true
|
|
1538
|
+
case "$sub" in
|
|
1539
|
+
list)
|
|
1540
|
+
local env="$(read_current_env cli || true)"
|
|
1541
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1542
|
+
case "$1" in
|
|
1543
|
+
--env)
|
|
1544
|
+
shift
|
|
1545
|
+
[[ "$#" -gt 0 ]] || err "missing env after --env"
|
|
1546
|
+
env="$1"
|
|
1547
|
+
;;
|
|
1548
|
+
*)
|
|
1549
|
+
err "unknown option: $1"
|
|
1550
|
+
;;
|
|
1551
|
+
esac
|
|
1552
|
+
shift
|
|
1553
|
+
done
|
|
1554
|
+
cmd_account_list "$env"
|
|
1555
|
+
;;
|
|
1556
|
+
add)
|
|
1557
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME account add <account> [--env <env>]"
|
|
1558
|
+
local account="$1"
|
|
1559
|
+
shift
|
|
1560
|
+
local env="$(read_current_env cli || true)"
|
|
1561
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1562
|
+
case "$1" in
|
|
1563
|
+
--env)
|
|
1564
|
+
shift
|
|
1565
|
+
[[ "$#" -gt 0 ]] || err "missing env after --env"
|
|
1566
|
+
env="$1"
|
|
1567
|
+
;;
|
|
1568
|
+
*)
|
|
1569
|
+
err "unknown option: $1"
|
|
1570
|
+
;;
|
|
1571
|
+
esac
|
|
1572
|
+
shift
|
|
1573
|
+
done
|
|
1574
|
+
with_lock cmd_account_add "$account" "$env"
|
|
1575
|
+
;;
|
|
1576
|
+
remove)
|
|
1577
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME account remove <account> [--env <env>] [--force]"
|
|
1578
|
+
local account="$1"
|
|
1579
|
+
shift
|
|
1580
|
+
local env="$(read_current_env cli || true)"
|
|
1581
|
+
local force="false"
|
|
1582
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1583
|
+
case "$1" in
|
|
1584
|
+
--env)
|
|
1585
|
+
shift
|
|
1586
|
+
[[ "$#" -gt 0 ]] || err "missing env after --env"
|
|
1587
|
+
env="$1"
|
|
1588
|
+
;;
|
|
1589
|
+
--force)
|
|
1590
|
+
force="true"
|
|
1591
|
+
;;
|
|
1592
|
+
*)
|
|
1593
|
+
err "unknown option: $1"
|
|
1594
|
+
;;
|
|
1595
|
+
esac
|
|
1596
|
+
shift
|
|
1597
|
+
done
|
|
1598
|
+
with_lock cmd_account_remove "$account" "$env" "$force"
|
|
1599
|
+
;;
|
|
1600
|
+
login)
|
|
1601
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME account login <account> [--env <env>] [--target cli|app|both] [--sync|--no-sync]"
|
|
1602
|
+
local account="$1"
|
|
1603
|
+
shift
|
|
1604
|
+
local env="$(read_current_env cli || true)"
|
|
1605
|
+
local target="cli"
|
|
1606
|
+
local sync_mode="false"
|
|
1607
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1608
|
+
case "$1" in
|
|
1609
|
+
--env)
|
|
1610
|
+
shift
|
|
1611
|
+
[[ "$#" -gt 0 ]] || err "missing env after --env"
|
|
1612
|
+
env="$1"
|
|
1613
|
+
;;
|
|
1614
|
+
--target)
|
|
1615
|
+
shift
|
|
1616
|
+
[[ "$#" -gt 0 ]] || err "missing target after --target"
|
|
1617
|
+
target="$1"
|
|
1618
|
+
;;
|
|
1619
|
+
--sync)
|
|
1620
|
+
sync_mode="true"
|
|
1621
|
+
;;
|
|
1622
|
+
--no-sync)
|
|
1623
|
+
sync_mode="false"
|
|
1624
|
+
;;
|
|
1625
|
+
*)
|
|
1626
|
+
err "unknown option: $1"
|
|
1627
|
+
;;
|
|
1628
|
+
esac
|
|
1629
|
+
shift
|
|
1630
|
+
done
|
|
1631
|
+
with_lock cmd_account_login "$account" "$env" "$target" "$sync_mode"
|
|
1632
|
+
;;
|
|
1633
|
+
use)
|
|
1634
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME account use <account> [--env <env>] [--target cli|app|both] [--sync|--no-sync]"
|
|
1635
|
+
local account="$1"
|
|
1636
|
+
shift
|
|
1637
|
+
local env="$(read_current_env cli || true)"
|
|
1638
|
+
local target="cli"
|
|
1639
|
+
local sync_mode="false"
|
|
1640
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1641
|
+
case "$1" in
|
|
1642
|
+
--env)
|
|
1643
|
+
shift
|
|
1644
|
+
[[ "$#" -gt 0 ]] || err "missing env after --env"
|
|
1645
|
+
env="$1"
|
|
1646
|
+
;;
|
|
1647
|
+
--target)
|
|
1648
|
+
shift
|
|
1649
|
+
[[ "$#" -gt 0 ]] || err "missing target after --target"
|
|
1650
|
+
target="$1"
|
|
1651
|
+
;;
|
|
1652
|
+
--sync)
|
|
1653
|
+
sync_mode="true"
|
|
1654
|
+
;;
|
|
1655
|
+
--no-sync)
|
|
1656
|
+
sync_mode="false"
|
|
1657
|
+
;;
|
|
1658
|
+
*)
|
|
1659
|
+
err "unknown option: $1"
|
|
1660
|
+
;;
|
|
1661
|
+
esac
|
|
1662
|
+
shift
|
|
1663
|
+
done
|
|
1664
|
+
with_lock cmd_account_use "$account" "$env" "$target" "$sync_mode"
|
|
1665
|
+
;;
|
|
1666
|
+
logout)
|
|
1667
|
+
local account=""
|
|
1668
|
+
local env="$(read_current_env cli || true)"
|
|
1669
|
+
local target="cli"
|
|
1670
|
+
if [[ "$#" -gt 0 && "${1:-}" != --* ]]; then
|
|
1671
|
+
account="$1"
|
|
1672
|
+
shift
|
|
1673
|
+
fi
|
|
1674
|
+
while [[ "$#" -gt 0 ]]; do
|
|
1675
|
+
case "$1" in
|
|
1676
|
+
--env)
|
|
1677
|
+
shift
|
|
1678
|
+
[[ "$#" -gt 0 ]] || err "missing env after --env"
|
|
1679
|
+
env="$1"
|
|
1680
|
+
;;
|
|
1681
|
+
--target)
|
|
1682
|
+
shift
|
|
1683
|
+
[[ "$#" -gt 0 ]] || err "missing target after --target"
|
|
1684
|
+
target="$1"
|
|
1685
|
+
;;
|
|
1686
|
+
*)
|
|
1687
|
+
err "unknown option: $1"
|
|
1688
|
+
;;
|
|
1689
|
+
esac
|
|
1690
|
+
shift
|
|
1691
|
+
done
|
|
1692
|
+
with_lock cmd_account_logout "$account" "$env" "$target"
|
|
1693
|
+
;;
|
|
1694
|
+
current)
|
|
1695
|
+
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME account current [cli|app]"
|
|
1696
|
+
cmd_account_current "${1:-all}"
|
|
1697
|
+
;;
|
|
1698
|
+
*)
|
|
1699
|
+
err "unknown account subcommand: $sub"
|
|
1700
|
+
;;
|
|
1701
|
+
esac
|
|
1702
|
+
;;
|
|
977
1703
|
add)
|
|
978
|
-
[[ "$#" -eq 1 ]] || err "usage: $SCRIPT_NAME add <
|
|
1704
|
+
[[ "$#" -eq 1 ]] || err "usage: $SCRIPT_NAME add <account>"
|
|
979
1705
|
with_lock cmd_add "$1"
|
|
980
1706
|
;;
|
|
981
1707
|
remove)
|
|
982
|
-
[[ "$#" -ge 1 && "$#" -le 2 ]] || err "usage: $SCRIPT_NAME remove <
|
|
1708
|
+
[[ "$#" -ge 1 && "$#" -le 2 ]] || err "usage: $SCRIPT_NAME remove <account> [--force]"
|
|
983
1709
|
local force="false"
|
|
984
1710
|
if [[ "${2:-}" == "--force" ]]; then
|
|
985
1711
|
force="true"
|
|
@@ -993,8 +1719,8 @@ main() {
|
|
|
993
1719
|
cmd_list
|
|
994
1720
|
;;
|
|
995
1721
|
import-default)
|
|
996
|
-
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME import-default <
|
|
997
|
-
local
|
|
1722
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME import-default <env> [--with-auth] [--force]"
|
|
1723
|
+
local env="$1"
|
|
998
1724
|
local with_auth="false"
|
|
999
1725
|
local force="false"
|
|
1000
1726
|
shift
|
|
@@ -1012,11 +1738,11 @@ main() {
|
|
|
1012
1738
|
esac
|
|
1013
1739
|
shift
|
|
1014
1740
|
done
|
|
1015
|
-
with_lock cmd_import_default "$
|
|
1741
|
+
with_lock cmd_import_default "$env" "$with_auth" "$force"
|
|
1016
1742
|
;;
|
|
1017
1743
|
use)
|
|
1018
|
-
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME use <
|
|
1019
|
-
local
|
|
1744
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME use <account> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]"
|
|
1745
|
+
local account="$1"
|
|
1020
1746
|
shift
|
|
1021
1747
|
local sync="false"
|
|
1022
1748
|
local launch="auto"
|
|
@@ -1051,14 +1777,14 @@ main() {
|
|
|
1051
1777
|
launch="true"
|
|
1052
1778
|
fi
|
|
1053
1779
|
if [[ "${#codex_args[@]}" -gt 0 ]]; then
|
|
1054
|
-
cmd_use_and_maybe_launch
|
|
1780
|
+
cmd_use_and_maybe_launch cmd_use_compat "$account" "$sync" "$launch" "${codex_args[@]}"
|
|
1055
1781
|
else
|
|
1056
|
-
cmd_use_and_maybe_launch
|
|
1782
|
+
cmd_use_and_maybe_launch cmd_use_compat "$account" "$sync" "$launch"
|
|
1057
1783
|
fi
|
|
1058
1784
|
;;
|
|
1059
1785
|
switch)
|
|
1060
|
-
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME switch <
|
|
1061
|
-
local
|
|
1786
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME switch <account> [--sync|--no-sync] [--launch|--no-launch] [-- <codex args...>]"
|
|
1787
|
+
local account="$1"
|
|
1062
1788
|
shift
|
|
1063
1789
|
local sync="false"
|
|
1064
1790
|
local launch="auto"
|
|
@@ -1093,9 +1819,9 @@ main() {
|
|
|
1093
1819
|
launch="true"
|
|
1094
1820
|
fi
|
|
1095
1821
|
if [[ "${#codex_args[@]}" -gt 0 ]]; then
|
|
1096
|
-
cmd_use_and_maybe_launch
|
|
1822
|
+
cmd_use_and_maybe_launch cmd_switch_compat "$account" "$sync" "$launch" "${codex_args[@]}"
|
|
1097
1823
|
else
|
|
1098
|
-
cmd_use_and_maybe_launch
|
|
1824
|
+
cmd_use_and_maybe_launch cmd_switch_compat "$account" "$sync" "$launch"
|
|
1099
1825
|
fi
|
|
1100
1826
|
;;
|
|
1101
1827
|
current)
|
|
@@ -1110,8 +1836,8 @@ main() {
|
|
|
1110
1836
|
cmd_exec "$@"
|
|
1111
1837
|
;;
|
|
1112
1838
|
login)
|
|
1113
|
-
[[ "$#" -le 2 ]] || err "usage: $SCRIPT_NAME login [
|
|
1114
|
-
local
|
|
1839
|
+
[[ "$#" -le 2 ]] || err "usage: $SCRIPT_NAME login [account] [--sync|--no-sync]"
|
|
1840
|
+
local account=""
|
|
1115
1841
|
local sync="false"
|
|
1116
1842
|
local arg
|
|
1117
1843
|
for arg in "$@"; do
|
|
@@ -1123,44 +1849,43 @@ main() {
|
|
|
1123
1849
|
sync="false"
|
|
1124
1850
|
;;
|
|
1125
1851
|
*)
|
|
1126
|
-
if [[ -z "$
|
|
1127
|
-
|
|
1852
|
+
if [[ -z "$account" ]]; then
|
|
1853
|
+
account="$arg"
|
|
1128
1854
|
else
|
|
1129
1855
|
err "unknown option: $arg"
|
|
1130
1856
|
fi
|
|
1131
1857
|
;;
|
|
1132
1858
|
esac
|
|
1133
1859
|
done
|
|
1134
|
-
with_lock cmd_login "${
|
|
1860
|
+
with_lock cmd_login "${account:-}" "$sync"
|
|
1135
1861
|
;;
|
|
1136
1862
|
logout)
|
|
1137
|
-
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME logout [
|
|
1863
|
+
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME logout [account]"
|
|
1138
1864
|
with_lock cmd_logout "${1:-}"
|
|
1139
1865
|
;;
|
|
1140
|
-
env)
|
|
1141
|
-
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME env [profile]"
|
|
1142
|
-
cmd_env "${1:-}"
|
|
1143
|
-
;;
|
|
1144
1866
|
app)
|
|
1145
1867
|
local sub="${1:-}"
|
|
1146
1868
|
[[ -n "$sub" ]] || err "usage: $SCRIPT_NAME app <open|use|logout|status|stop|current> ..."
|
|
1147
1869
|
shift || true
|
|
1148
1870
|
case "$sub" in
|
|
1149
1871
|
open)
|
|
1150
|
-
local
|
|
1151
|
-
if [[ "$#" -gt 0 ]]; then
|
|
1872
|
+
local account=""
|
|
1873
|
+
if [[ "$#" -gt 0 && "${1:-}" != "--" ]]; then
|
|
1874
|
+
account="$1"
|
|
1875
|
+
shift
|
|
1876
|
+
fi
|
|
1152
1877
|
if [[ "${1:-}" == "--" ]]; then shift; fi
|
|
1153
|
-
with_lock cmd_app_open "$
|
|
1878
|
+
with_lock cmd_app_open "$account" "$@"
|
|
1154
1879
|
;;
|
|
1155
1880
|
use)
|
|
1156
|
-
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME app use <
|
|
1157
|
-
local
|
|
1881
|
+
[[ "$#" -ge 1 ]] || err "usage: $SCRIPT_NAME app use <account> [-- <app args...>]"
|
|
1882
|
+
local account="$1"
|
|
1158
1883
|
shift
|
|
1159
1884
|
if [[ "${1:-}" == "--" ]]; then shift; fi
|
|
1160
|
-
with_lock cmd_app_use "$
|
|
1885
|
+
with_lock cmd_app_use "$account" "$@"
|
|
1161
1886
|
;;
|
|
1162
1887
|
logout)
|
|
1163
|
-
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME app logout [
|
|
1888
|
+
[[ "$#" -le 1 ]] || err "usage: $SCRIPT_NAME app logout [account]"
|
|
1164
1889
|
with_lock cmd_app_logout "${1:-}"
|
|
1165
1890
|
;;
|
|
1166
1891
|
status)
|
|
@@ -1173,7 +1898,7 @@ main() {
|
|
|
1173
1898
|
;;
|
|
1174
1899
|
current)
|
|
1175
1900
|
[[ "$#" -eq 0 ]] || err "usage: $SCRIPT_NAME app current"
|
|
1176
|
-
|
|
1901
|
+
echo "$(read_current_env app || true)/$(read_current_account app || true)"
|
|
1177
1902
|
;;
|
|
1178
1903
|
*)
|
|
1179
1904
|
err "unknown app subcommand: $sub"
|