claude-cac 1.5.2 → 1.5.4

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.
Files changed (2) hide show
  1. package/cac +56 -24
  2. 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.2"
14
+ CAC_VERSION="1.5.4"
15
15
 
16
16
  _read() { [[ -f "$1" ]] && tr -d '[:space:]' < "$1" || echo "${2:-}"; }
17
17
  _die() { printf '%b\n' "$(_red "error:") $*" >&2; exit 1; }
@@ -1044,6 +1044,9 @@ _write_env_settings() {
1044
1044
  "statusLine": {
1045
1045
  "type": "command",
1046
1046
  "command": "bash $CLAUDE_CONFIG_DIR/statusline-command.sh"
1047
+ },
1048
+ "env": {
1049
+ "DISABLE_AUTOUPDATER": "1"
1047
1050
  }
1048
1051
  }
1049
1052
  SETTINGS_EOF
@@ -1273,7 +1276,9 @@ if [[ -f "$_env_dir/persona" ]]; then
1273
1276
  fi
1274
1277
 
1275
1278
  # ── NS-level DNS interception ──
1276
- if [[ -f "$CAC_DIR/cac-dns-guard.js" ]]; then
1279
+ # Use -r (readable) not -f (exists) — root-owned files with mode 600 exist but
1280
+ # can't be read by normal user, causing bun/node to crash silently.
1281
+ if [[ -r "$CAC_DIR/cac-dns-guard.js" ]]; then
1277
1282
  case "${NODE_OPTIONS:-}" in
1278
1283
  *cac-dns-guard.js*) ;; # already injected, skip
1279
1284
  *) export NODE_OPTIONS="${NODE_OPTIONS:-} --require $CAC_DIR/cac-dns-guard.js" ;;
@@ -1284,7 +1289,7 @@ if [[ -f "$CAC_DIR/cac-dns-guard.js" ]]; then
1284
1289
  esac
1285
1290
  fi
1286
1291
  # fallback layer: HOSTALIASES (gethostbyname level)
1287
- [[ -f "$CAC_DIR/blocked_hosts" ]] && export HOSTALIASES="$CAC_DIR/blocked_hosts"
1292
+ [[ -r "$CAC_DIR/blocked_hosts" ]] && export HOSTALIASES="$CAC_DIR/blocked_hosts"
1288
1293
 
1289
1294
  # ── mTLS client certificate ──
1290
1295
  if [[ -f "$_env_dir/client_cert.pem" ]] && [[ -f "$_env_dir/client_key.pem" ]]; then
@@ -1312,7 +1317,7 @@ fi
1312
1317
  [[ -f "$_env_dir/machine_id" ]] && export CAC_MACHINE_ID=$(tr -d '[:space:]' < "$_env_dir/machine_id")
1313
1318
  export CAC_USERNAME="user-$(echo "$_name" | cut -c1-8)"
1314
1319
  export USER="$CAC_USERNAME" LOGNAME="$CAC_USERNAME"
1315
- if [[ -f "$CAC_DIR/fingerprint-hook.js" ]]; then
1320
+ if [[ -r "$CAC_DIR/fingerprint-hook.js" ]]; then
1316
1321
  case "${NODE_OPTIONS:-}" in
1317
1322
  *fingerprint-hook.js*) ;;
1318
1323
  *) export NODE_OPTIONS="--require $CAC_DIR/fingerprint-hook.js ${NODE_OPTIONS:-}" ;;
@@ -1581,11 +1586,45 @@ _ensure_initialized() {
1581
1586
  if [[ -z "$_self_dir" ]] || [[ ! -f "$_self_dir/relay.js" ]]; then
1582
1587
  _self_dir="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
1583
1588
  fi
1584
- [[ -f "$_self_dir/fingerprint-hook.js" ]] && cp "$_self_dir/fingerprint-hook.js" "$CAC_DIR/fingerprint-hook.js"
1585
- [[ -f "$_self_dir/relay.js" ]] && cp "$_self_dir/relay.js" "$CAC_DIR/relay.js"
1589
+ # Warn if running as root — files written here become root-owned and break
1590
+ # normal-user invocations (wrapper has set -e and will silently exit).
1591
+ if [[ $EUID -eq 0 ]]; then
1592
+ echo "[cac] warning: running as root may corrupt ~/.cac/ file ownership" >&2
1593
+ echo "[cac] hint: run as your normal user instead" >&2
1594
+ fi
1595
+ # rm -f first: user owns ~/.cac/ dir so can delete root-owned files even if can't overwrite them
1596
+ if [[ -f "$_self_dir/fingerprint-hook.js" ]]; then
1597
+ rm -f "$CAC_DIR/fingerprint-hook.js" 2>/dev/null || true
1598
+ cp "$_self_dir/fingerprint-hook.js" "$CAC_DIR/fingerprint-hook.js" 2>/dev/null || true
1599
+ fi
1600
+ if [[ -f "$_self_dir/relay.js" ]]; then
1601
+ rm -f "$CAC_DIR/relay.js" 2>/dev/null || true
1602
+ cp "$_self_dir/relay.js" "$CAC_DIR/relay.js" 2>/dev/null || true
1603
+ fi
1604
+ rm -f "$CAC_DIR/cac-dns-guard.js" 2>/dev/null || true
1586
1605
  _write_dns_guard_js 2>/dev/null || true
1606
+ rm -f "$CAC_DIR/blocked_hosts" 2>/dev/null || true
1587
1607
  _write_blocked_hosts 2>/dev/null || true
1588
1608
 
1609
+ # Patch all existing envs: ensure DISABLE_AUTOUPDATER=1 in settings.json
1610
+ local _sf
1611
+ for _sf in "$ENVS_DIR"/*/.claude/settings.json; do
1612
+ [[ -f "$_sf" ]] || continue
1613
+ grep -q '"DISABLE_AUTOUPDATER"' "$_sf" 2>/dev/null && continue
1614
+ python3 - "$_sf" << 'PYEOF' 2>/dev/null || true
1615
+ import json, sys
1616
+ path = sys.argv[1]
1617
+ with open(path) as f:
1618
+ d = json.load(f)
1619
+ if d.get('env', {}).get('DISABLE_AUTOUPDATER') == '1':
1620
+ sys.exit(0)
1621
+ d.setdefault('env', {})['DISABLE_AUTOUPDATER'] = '1'
1622
+ with open(path, 'w') as f:
1623
+ json.dump(d, f, indent=2)
1624
+ f.write('\n')
1625
+ PYEOF
1626
+ done
1627
+
1589
1628
  # PATH (idempotent — always ensure it's in rc file)
1590
1629
  local rc_file; rc_file=$(_detect_rc_file)
1591
1630
  _write_path_to_rc "$rc_file" >/dev/null 2>&1 || true
@@ -1730,7 +1769,7 @@ _env_cmd_create() {
1730
1769
  mkdir -p "$env_dir"
1731
1770
  [[ -n "$proxy_url" ]] && echo "$proxy_url" > "$env_dir/proxy"
1732
1771
  echo "$(_new_uuid)" > "$env_dir/uuid"
1733
- echo "$(_new_user_id)" > "$env_dir/user_id"
1772
+ touch "$env_dir/user_id"
1734
1773
  echo "$(_new_machine_id)" > "$env_dir/machine_id"
1735
1774
  echo "$(_new_hostname)" > "$env_dir/hostname"
1736
1775
  echo "$(_new_mac)" > "$env_dir/mac_address"
@@ -1823,7 +1862,6 @@ MERGE_EOF
1823
1862
  if [[ -d "$env_dir/.claude" ]]; then
1824
1863
  export CLAUDE_CONFIG_DIR="$env_dir/.claude"
1825
1864
  fi
1826
- _update_claude_json_user_id "$(_read "$env_dir/user_id")" 2>/dev/null || true
1827
1865
 
1828
1866
  local elapsed; elapsed=$(_timer_elapsed)
1829
1867
  echo
@@ -1919,7 +1957,6 @@ _env_cmd_activate() {
1919
1957
  export CLAUDE_CONFIG_DIR="$ENVS_DIR/$name/.claude"
1920
1958
  fi
1921
1959
 
1922
- _update_claude_json_user_id "$(_read "$ENVS_DIR/$name/user_id")"
1923
1960
 
1924
1961
  # Relay lifecycle
1925
1962
  _relay_stop 2>/dev/null || true
@@ -2429,23 +2466,18 @@ cmd_check() {
2429
2466
  else
2430
2467
  _id_issues+=("repo hash not spoofed")
2431
2468
  fi
2432
- # user_id consistency
2469
+ # user_id tracking: sync from .claude.json after login (real userID wins)
2433
2470
  local _uid_ok=true
2434
- local _env_uid; _env_uid=$(_read "$env_dir/user_id" "")
2435
- if [[ -n "$_env_uid" ]]; then
2436
- local _config_dir="${CLAUDE_CONFIG_DIR:-$ENVS_DIR/$current/.claude}"
2437
- local _cj="$_config_dir/.claude.json"
2438
- [[ -f "$_cj" ]] || _cj="$HOME/.claude.json"
2439
- if [[ -f "$_cj" ]]; then
2440
- local _actual_uid
2441
- _actual_uid=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('userID',''))" "$_cj" 2>/dev/null || true)
2471
+ local _config_dir="${CLAUDE_CONFIG_DIR:-$ENVS_DIR/$current/.claude}"
2472
+ local _cj="$_config_dir/.claude.json"
2473
+ [[ -f "$_cj" ]] || _cj="$HOME/.claude.json"
2474
+ if [[ -f "$_cj" ]]; then
2475
+ local _actual_uid
2476
+ _actual_uid=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('userID',''))" "$_cj" 2>/dev/null || true)
2477
+ if [[ -n "$_actual_uid" ]]; then
2442
2478
  (( _id_total++ )) || true
2443
- if [[ -n "$_actual_uid" ]] && [[ "$_actual_uid" != "$_env_uid" ]]; then
2444
- _uid_ok=false
2445
- _id_issues+=("user_id mismatch")
2446
- else
2447
- (( _id_ok++ )) || true
2448
- fi
2479
+ echo "$_actual_uid" > "$env_dir/user_id" 2>/dev/null || true
2480
+ (( _id_ok++ )) || true
2449
2481
  fi
2450
2482
  fi
2451
2483
  # billing header
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-cac",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Isolate, protect, and manage your Claude Code — versions, environments, identity, and proxy.",
5
5
  "bin": {
6
6
  "cac": "cac"