claude-cac 1.5.5 → 1.5.6
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/cac +100 -16
- package/package.json +1 -1
package/cac
CHANGED
|
@@ -11,7 +11,7 @@ VERSIONS_DIR="$CAC_DIR/versions"
|
|
|
11
11
|
# ── utils: colors, read/write, UUID, proxy parsing ───────────────────────
|
|
12
12
|
|
|
13
13
|
# shellcheck disable=SC2034 # used in build-concatenated cac script
|
|
14
|
-
CAC_VERSION="1.5.
|
|
14
|
+
CAC_VERSION="1.5.6"
|
|
15
15
|
|
|
16
16
|
_read() { [[ -f "$1" ]] && tr -d '[:space:]' < "$1" || echo "${2:-}"; }
|
|
17
17
|
_die() { printf '%b\n' "$(_red "error:") $*" >&2; exit 1; }
|
|
@@ -58,6 +58,19 @@ _gen_uuid() {
|
|
|
58
58
|
_new_uuid() { _gen_uuid | tr '[:lower:]' '[:upper:]'; }
|
|
59
59
|
_new_user_id() { python3 -c "import os; print(os.urandom(32).hex())" || _die "python3 required"; }
|
|
60
60
|
_new_machine_id() { _gen_uuid | tr -d '-' | tr '[:upper:]' '[:lower:]'; }
|
|
61
|
+
_new_hostname_suffix() { _gen_uuid | tr -d '-' | tr '[:lower:]' '[:upper:]' | cut -c1-5; }
|
|
62
|
+
_detect_hostname_platform() {
|
|
63
|
+
local os; os=$(_detect_os)
|
|
64
|
+
if [[ "$os" == "linux" ]]; then
|
|
65
|
+
if [[ -n "${WSL_DISTRO_NAME:-}" ]] || [[ -n "${WSL_INTEROP:-}" ]] || \
|
|
66
|
+
grep -qi microsoft /proc/sys/kernel/osrelease 2>/dev/null || \
|
|
67
|
+
uname -r 2>/dev/null | grep -qi microsoft; then
|
|
68
|
+
echo "windows"
|
|
69
|
+
return
|
|
70
|
+
fi
|
|
71
|
+
fi
|
|
72
|
+
echo "$os"
|
|
73
|
+
}
|
|
61
74
|
_new_hostname() {
|
|
62
75
|
local -a _first_names=(
|
|
63
76
|
"James" "John" "Robert" "Michael" "William" "David" "Richard" "Joseph"
|
|
@@ -68,10 +81,25 @@ _new_hostname() {
|
|
|
68
81
|
"Liam" "Noah" "Oliver" "Elijah" "Lucas" "Mason" "Ethan" "Aiden"
|
|
69
82
|
"Alex" "Ryan" "Tyler" "Jordan" "Taylor" "Morgan" "Casey" "Riley"
|
|
70
83
|
)
|
|
71
|
-
local -a _models=("MacBook-Pro" "MacBook-Air" "MacBook-Pro" "MacBook-Pro")
|
|
72
84
|
local _name="${_first_names[$((RANDOM % ${#_first_names[@]}))]}"
|
|
73
|
-
local
|
|
74
|
-
|
|
85
|
+
local _platform; _platform=$(_detect_hostname_platform)
|
|
86
|
+
case "$_platform" in
|
|
87
|
+
macos)
|
|
88
|
+
local -a _models=("MacBook-Pro" "MacBook-Air" "MacBook-Pro" "MacBook-Pro")
|
|
89
|
+
local _model="${_models[$((RANDOM % ${#_models[@]}))]}"
|
|
90
|
+
echo "${_name}s-${_model}.local"
|
|
91
|
+
;;
|
|
92
|
+
windows)
|
|
93
|
+
local -a _prefixes=("DESKTOP" "LAPTOP")
|
|
94
|
+
local _prefix="${_prefixes[$((RANDOM % ${#_prefixes[@]}))]}"
|
|
95
|
+
echo "${_prefix}-$(_new_hostname_suffix)"
|
|
96
|
+
;;
|
|
97
|
+
*)
|
|
98
|
+
local -a _devices=("desktop" "laptop" "workstation" "thinkpad")
|
|
99
|
+
local _device="${_devices[$((RANDOM % ${#_devices[@]}))]}"
|
|
100
|
+
echo "$(printf '%s' "$_name" | tr '[:upper:]' '[:lower:]')-${_device}"
|
|
101
|
+
;;
|
|
102
|
+
esac
|
|
75
103
|
}
|
|
76
104
|
_new_mac() { printf '02:%02x:%02x:%02x:%02x:%02x' $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)); }
|
|
77
105
|
_new_git_remote() { echo "https://github.com/user-$(_gen_uuid | cut -d- -f1)/project-$(_gen_uuid | cut -d- -f2).git"; }
|
|
@@ -126,6 +154,19 @@ _parse_proxy() {
|
|
|
126
154
|
fi
|
|
127
155
|
}
|
|
128
156
|
|
|
157
|
+
# curl-based health probes should use remote DNS for SOCKS5.
|
|
158
|
+
# Otherwise local DNS pollution can resolve probe domains to sinkhole/test
|
|
159
|
+
# addresses, causing false negatives even when the proxy itself is healthy.
|
|
160
|
+
_curl_proxy_url() {
|
|
161
|
+
local normalized
|
|
162
|
+
normalized=$(_parse_proxy "$1")
|
|
163
|
+
if [[ "$normalized" =~ ^socks5:// ]]; then
|
|
164
|
+
echo "socks5h://${normalized#socks5://}"
|
|
165
|
+
else
|
|
166
|
+
echo "$normalized"
|
|
167
|
+
fi
|
|
168
|
+
}
|
|
169
|
+
|
|
129
170
|
# socks5://user:pass@host:port → host:port
|
|
130
171
|
_proxy_host_port() {
|
|
131
172
|
local normalized
|
|
@@ -284,10 +325,20 @@ _envs_using_version() {
|
|
|
284
325
|
}
|
|
285
326
|
|
|
286
327
|
# Elapsed time helper: call _timer_start, then _timer_elapsed
|
|
287
|
-
|
|
328
|
+
_time_now() {
|
|
329
|
+
local now
|
|
330
|
+
now=$(date +%s%N 2>/dev/null || true)
|
|
331
|
+
if [[ "$now" =~ ^[0-9]{11,}$ ]]; then
|
|
332
|
+
echo "$now"
|
|
333
|
+
else
|
|
334
|
+
date +%s
|
|
335
|
+
fi
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
_timer_start() { _TIMER_START=$(_time_now); }
|
|
288
339
|
_timer_elapsed() {
|
|
289
|
-
local now; now=$(
|
|
290
|
-
if [[ $
|
|
340
|
+
local now; now=$(_time_now)
|
|
341
|
+
if [[ "$now" =~ ^[0-9]{11,}$ && "${_TIMER_START:-}" =~ ^[0-9]{11,}$ ]]; then
|
|
291
342
|
# nanoseconds available
|
|
292
343
|
local ms=$(( (now - _TIMER_START) / 1000000 ))
|
|
293
344
|
if [[ $ms -ge 1000 ]]; then
|
|
@@ -319,19 +370,31 @@ _detect_rc_file() {
|
|
|
319
370
|
local shell_name
|
|
320
371
|
shell_name=$(basename "${SHELL:-/bin/bash}")
|
|
321
372
|
case "$shell_name" in
|
|
373
|
+
fish)
|
|
374
|
+
echo "$HOME/.config/fish/config.fish"
|
|
375
|
+
return
|
|
376
|
+
;;
|
|
322
377
|
zsh)
|
|
323
|
-
|
|
378
|
+
echo "$HOME/.zshrc"
|
|
379
|
+
return
|
|
324
380
|
;;
|
|
325
381
|
bash)
|
|
326
382
|
[[ -f "$HOME/.bashrc" ]] && { echo "$HOME/.bashrc"; return; }
|
|
327
383
|
[[ -f "$HOME/.bash_profile" ]] && { echo "$HOME/.bash_profile"; return; }
|
|
384
|
+
echo "$HOME/.bashrc"
|
|
385
|
+
return
|
|
328
386
|
;;
|
|
329
387
|
esac
|
|
330
388
|
# Fallback: try common rc files
|
|
331
389
|
[[ -f "$HOME/.bashrc" ]] && { echo "$HOME/.bashrc"; return; }
|
|
332
390
|
[[ -f "$HOME/.zshrc" ]] && { echo "$HOME/.zshrc"; return; }
|
|
333
391
|
[[ -f "$HOME/.bash_profile" ]] && { echo "$HOME/.bash_profile"; return; }
|
|
334
|
-
echo ""
|
|
392
|
+
[[ -f "$HOME/.config/fish/config.fish" ]] && { echo "$HOME/.config/fish/config.fish"; return; }
|
|
393
|
+
echo "$HOME/.bashrc"
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
_is_fish_rc() {
|
|
397
|
+
[[ "$1" == */.config/fish/config.fish ]]
|
|
335
398
|
}
|
|
336
399
|
|
|
337
400
|
_install_method() {
|
|
@@ -360,16 +423,36 @@ _write_path_to_rc() {
|
|
|
360
423
|
return 0
|
|
361
424
|
fi
|
|
362
425
|
|
|
426
|
+
mkdir -p "$(dirname "$rc_file")"
|
|
427
|
+
[[ -f "$rc_file" ]] || touch "$rc_file"
|
|
428
|
+
|
|
363
429
|
if grep -q '# >>> cac >>>' "$rc_file" 2>/dev/null; then
|
|
364
430
|
echo " ✓ PATH already exists in $rc_file, skipping"
|
|
365
431
|
return 0
|
|
366
432
|
fi
|
|
367
433
|
|
|
368
434
|
# Compat: remove old format if present
|
|
369
|
-
if grep -q '\.cac/bin' "$rc_file" 2>/dev/null; then
|
|
435
|
+
if ! _is_fish_rc "$rc_file" && grep -q '\.cac/bin' "$rc_file" 2>/dev/null; then
|
|
370
436
|
_remove_path_from_rc "$rc_file"
|
|
371
437
|
fi
|
|
372
438
|
|
|
439
|
+
if _is_fish_rc "$rc_file"; then
|
|
440
|
+
cat >> "$rc_file" << 'CACEOF'
|
|
441
|
+
|
|
442
|
+
# >>> cac — Claude Code Cloak >>>
|
|
443
|
+
fish_add_path --move --path "$HOME/.cac/bin" >/dev/null 2>&1
|
|
444
|
+
function cac
|
|
445
|
+
command cac $argv
|
|
446
|
+
set -l _rc $status
|
|
447
|
+
fish_add_path --move --path "$HOME/.cac/bin" >/dev/null 2>&1
|
|
448
|
+
return $_rc
|
|
449
|
+
end
|
|
450
|
+
# <<< cac — Claude Code Cloak <<<
|
|
451
|
+
CACEOF
|
|
452
|
+
echo " ✓ PATH written to $rc_file"
|
|
453
|
+
return 0
|
|
454
|
+
fi
|
|
455
|
+
|
|
373
456
|
cat >> "$rc_file" << 'CACEOF'
|
|
374
457
|
|
|
375
458
|
# >>> cac — Claude Code Cloak >>>
|
|
@@ -1734,7 +1817,7 @@ _env_cmd_create() {
|
|
|
1734
1817
|
esac
|
|
1735
1818
|
done
|
|
1736
1819
|
|
|
1737
|
-
[[ -n "$name" ]] || _die "usage: cac env create <name> [-p <proxy>] [-c <version>] [--telemetry <mode>] [--persona <preset>]"
|
|
1820
|
+
[[ -n "$name" ]] || _die "usage: cac env create <name> [-p <proxy>] [-c <version>] [--clone [source]] [--no-link] [--telemetry <mode>] [--persona <preset>]"
|
|
1738
1821
|
[[ "$name" =~ ^[a-zA-Z0-9_-]+$ ]] || _die "invalid name '$name' (use alphanumeric, dash, underscore)"
|
|
1739
1822
|
|
|
1740
1823
|
local env_dir="$ENVS_DIR/$name"
|
|
@@ -1767,7 +1850,7 @@ _env_cmd_create() {
|
|
|
1767
1850
|
if [[ -n "$proxy_url" ]]; then
|
|
1768
1851
|
printf " $(_dim "Detecting timezone ...") "
|
|
1769
1852
|
local ip_info
|
|
1770
|
-
ip_info=$(curl -s --proxy "$proxy_url" --connect-timeout 8 "http://ip-api.com/json/?fields=timezone,countryCode" 2>/dev/null || true)
|
|
1853
|
+
ip_info=$(curl -s --proxy "$(_curl_proxy_url "$proxy_url")" --connect-timeout 8 "http://ip-api.com/json/?fields=timezone,countryCode" 2>/dev/null || true)
|
|
1771
1854
|
if [[ -n "$ip_info" ]]; then
|
|
1772
1855
|
local detected_tz country_code
|
|
1773
1856
|
read -r detected_tz country_code < <(echo "$ip_info" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('timezone',''), d.get('countryCode',''))" 2>/dev/null || echo "")
|
|
@@ -2132,8 +2215,9 @@ cmd_env() {
|
|
|
2132
2215
|
echo
|
|
2133
2216
|
echo " $(_bold "cac env") — environment management"
|
|
2134
2217
|
echo
|
|
2135
|
-
echo " $(_green "create") <name> [-p proxy] [-c ver] [--telemetry mode] [--persona preset]"
|
|
2218
|
+
echo " $(_green "create") <name> [-p proxy] [-c ver] [--clone [source]] [--no-link] [--telemetry mode] [--persona preset]"
|
|
2136
2219
|
echo " Create isolated environment (auto-activates)"
|
|
2220
|
+
echo " --clone inherits commands/hooks/skills/plugins; --no-link copies instead of symlink"
|
|
2137
2221
|
echo " $(_green "set") [name] <key> <value> Modify environment"
|
|
2138
2222
|
echo " proxy, version, telemetry, or persona"
|
|
2139
2223
|
echo " $(_green "ls") List all environments"
|
|
@@ -2579,7 +2663,7 @@ cmd_check() {
|
|
|
2579
2663
|
for _ip_url in $_urls; do
|
|
2580
2664
|
_dots="${_dots}."
|
|
2581
2665
|
printf "\r · exit IP $(_dim "detecting${_dots}")"
|
|
2582
|
-
proxy_ip=$(curl --proxy "$proxy" --connect-timeout 3 --max-time 6 "$_ip_url" 2>/dev/null || true)
|
|
2666
|
+
proxy_ip=$(curl --proxy "$(_curl_proxy_url "$proxy")" --connect-timeout 3 --max-time 6 "$_ip_url" 2>/dev/null || true)
|
|
2583
2667
|
[[ "$proxy_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && break
|
|
2584
2668
|
proxy_ip=""
|
|
2585
2669
|
done
|
|
@@ -2590,7 +2674,7 @@ cmd_check() {
|
|
|
2590
2674
|
local env_tz; env_tz=$(_read "$env_dir/tz" "")
|
|
2591
2675
|
if [[ -n "$env_tz" ]] && [[ -n "$proxy_ip" ]]; then
|
|
2592
2676
|
local ip_tz
|
|
2593
|
-
ip_tz=$(curl -s --proxy "$proxy" --connect-timeout 5 "http://ip-api.com/json/$proxy_ip?fields=timezone" 2>/dev/null | \
|
|
2677
|
+
ip_tz=$(curl -s --proxy "$(_curl_proxy_url "$proxy")" --connect-timeout 5 "http://ip-api.com/json/$proxy_ip?fields=timezone" 2>/dev/null | \
|
|
2594
2678
|
python3 -c "import sys,json; print(json.load(sys.stdin).get('timezone',''))" 2>/dev/null || true)
|
|
2595
2679
|
if [[ -n "$ip_tz" ]] && [[ "$ip_tz" != "$env_tz" ]]; then
|
|
2596
2680
|
echo " $(_yellow "⚠") TZ mismatch: env=$env_tz, IP=$ip_tz"
|
|
@@ -3533,7 +3617,7 @@ cmd_help() {
|
|
|
3533
3617
|
echo
|
|
3534
3618
|
|
|
3535
3619
|
echo " $(_bold "Environment")"
|
|
3536
|
-
echo " $(_green "cac env create") <name> [-p proxy] [-c ver]"
|
|
3620
|
+
echo " $(_green "cac env create") <name> [-p proxy] [-c ver] [--clone [source]] [--no-link]"
|
|
3537
3621
|
echo " $(_green "cac env set") [name] <key> <value> Modify environment"
|
|
3538
3622
|
echo " $(_green "cac env ls") List all environments"
|
|
3539
3623
|
echo " $(_green "cac env rm") <name> Remove an environment"
|