-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclaude
More file actions
executable file
·107 lines (96 loc) · 4.18 KB
/
claude
File metadata and controls
executable file
·107 lines (96 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env bash
# claude — Process wrapper for Claude Code
# Fetches remote config, sets up environment, and launches the real binary.
#
# Install: ln -sf /path/to/claude-wrapper/claude ~/bin/claude
# Update: rm ~/.cache/claude/env-remote.sh
# Debug: CLAUDE_DEBUG=1 claude
set -euo pipefail
# ── Portable realpath (macOS lacks readlink -f) ─────────────────────────────
_realpath() {
local p="$1"
while [[ -L "$p" ]]; do
local dir
dir="$(cd -P "$(dirname "$p")" && pwd)"
p="$(readlink "$p")"
[[ "$p" != /* ]] && p="$dir/$p"
done
cd -P "$(dirname "$p")" && echo "$(pwd)/$(basename "$p")"
}
# ── Find real binary (POSIX PATH iteration, replaces which -a) ──────────────
_find_real_claude() {
local self
self="$(_realpath "$0")"
local IFS=:
for dir in $PATH; do
local candidate="$dir/claude"
[[ -x "$candidate" ]] || continue
[[ "$(_realpath "$candidate")" == "$self" ]] && continue
echo "$candidate"
return
done
return 1
}
CLAUDE_BIN="$(_find_real_claude)" || {
echo "ERROR: Cannot find the real claude binary on PATH" >&2
exit 1
}
# ── Handle --clear-cache ────────────────────────────────────────────────────
if [[ "${1:-}" == "--clear-cache" ]]; then
rm -f "${XDG_CACHE_HOME:-$HOME/.cache}/claude"/*.key
rm -f "${XDG_CACHE_HOME:-$HOME/.cache}/claude/env-remote.sh"
echo "Claude env + API key cache cleared" >&2
exit 0
fi
# ── Remote config fetch + cache ─────────────────────────────────────────────
CLAUDE_ENV_REMOTE_URL="${CLAUDE_ENV_URL:-https://raw.githubusercontent.com/aproorg/claude-wrapper/main/claude-env.sh}"
_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/claude"
_CACHE_FILE="$_CACHE_DIR/env-remote.sh"
_UPDATE_TTL="${CLAUDE_ENV_UPDATE_TTL:-300}"
_needs_update() {
[[ ! -f "$_CACHE_FILE" ]] && return 0
local age
age=$(($(date +%s) - $(stat -f %m "$_CACHE_FILE" 2>/dev/null || stat -c %Y "$_CACHE_FILE" 2>/dev/null || echo 0)))
[[ $age -ge $_UPDATE_TTL ]]
}
if _needs_update; then
(umask 077; mkdir -p "$_CACHE_DIR")
tmp="$_CACHE_FILE.tmp.$$"
if (umask 077; curl -fsSL --connect-timeout 3 --max-time 10 "$CLAUDE_ENV_REMOTE_URL" -o "$tmp") 2>/dev/null; then
# Integrity check: sourced config must not contain dangerous patterns
if grep -qE '(rm\s+-rf\s+/|curl.*\|\s*(ba)?sh|eval\s)' "$tmp" 2>/dev/null; then
echo "ERROR: Remote config failed integrity check — refusing to source" >&2
rm -f "$tmp"
exit 1
fi
mv "$tmp" "$_CACHE_FILE"
else
rm -f "$tmp"
if [[ ! -f "$_CACHE_FILE" ]]; then
echo "ERROR: Cannot fetch config from $CLAUDE_ENV_REMOTE_URL (no cache)" >&2
exit 1
fi
# Stale cache fallback
if [[ "${CLAUDE_DEBUG:-0}" == "1" ]]; then
_stale_age=$(($(date +%s) - $(stat -f %m "$_CACHE_FILE" 2>/dev/null || stat -c %Y "$_CACHE_FILE" 2>/dev/null || echo 0)))
echo "Warning: Using stale cached config (${_stale_age}s old, fetch failed)" >&2
unset _stale_age
fi
fi
fi
# ── Source remote config (sets ANTHROPIC_* exports) ─────────────────────────
# shellcheck disable=SC1090
source "$_CACHE_FILE"
# ── Middleware ──────────────────────────────────────────────────────────────
_CLAUDE_MIDDLEWARE="${XDG_CONFIG_HOME:-$HOME/.config}/claude/middleware.sh"
if [[ -f "$_CLAUDE_MIDDLEWARE" ]]; then
# shellcheck disable=SC1090
if ! source "$_CLAUDE_MIDDLEWARE"; then
echo "ERROR: Middleware script failed: $_CLAUDE_MIDDLEWARE" >&2
echo "Fix the script or remove it to launch Claude without middleware." >&2
exit 1
fi
fi
unset _CLAUDE_MIDDLEWARE
# ── Launch ─────────────────────────────────────────────────────────────────
exec "$CLAUDE_BIN" "$@"