mirror of
https://github.com/ION606/config-backup.git
synced 2026-07-14 01:38:07 +00:00
106 lines
3.2 KiB
Bash
Executable File
106 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
log_dir="${HOME}/.claude/logs"
|
|
mkdir -p "$log_dir"
|
|
|
|
timestamp="$(date +%Y%m%d-%H%M%S)"
|
|
session_file="${log_dir}/session-${timestamp}.log"
|
|
cwd="$(pwd)"
|
|
|
|
echo "session: ${session_file}"
|
|
|
|
if [[ -z "${CLAUDE_CODE_OAUTH_TOKEN:-}" ]]; then
|
|
CLAUDE_CODE_OAUTH_TOKEN="$(pass show claude/oauth-token | tr -d '\n')" || {
|
|
echo "error: could not retrieve token from pass" >&2
|
|
exit 1
|
|
}
|
|
fi
|
|
|
|
if [[ -n "${ANTHROPIC_API_KEY:-}" ]]; then
|
|
echo "error: ANTHROPIC_API_KEY would override oauth, billing API instead of plan" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# build minimal claude.json with subscription binding only
|
|
auth_blob="$(
|
|
python3 <<PY
|
|
import json
|
|
d = json.load(open("${HOME}/.claude.json"))
|
|
out = {
|
|
"hasCompletedOnboarding": True,
|
|
"theme": "dark",
|
|
"bypassPermissionsModeAccepted": True,
|
|
"userID": d.get("userID", ""),
|
|
"oauthAccount": d.get("oauthAccount", {}),
|
|
"mcpServers": d.get("mcpServers", {}),
|
|
"projects": {
|
|
"/workspace": {
|
|
"hasTrustDialogAccepted": True,
|
|
"hasTrustDialogHooksAccepted": True,
|
|
"hasCompletedProjectOnboarding": True,
|
|
"mcpServers": d.get("projects", {}).get("${cwd}", {}).get("mcpServers", {}),
|
|
},
|
|
},
|
|
}
|
|
print(json.dumps(out))
|
|
PY
|
|
)"
|
|
|
|
if [[ -z "$(echo "$auth_blob" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("userID",""))')" ]]; then
|
|
echo "error: no userID found in host ~/.claude.json -- log in on host first" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export CLAUDE_CODE_OAUTH_TOKEN
|
|
export AUTH_BLOB="$auth_blob"
|
|
|
|
# sync CLAUDE.md into .claude/ so it's visible at /workspace/.claude/CLAUDE.md inside container
|
|
mkdir -p "${cwd}/.claude"
|
|
if [[ -f "${cwd}/CLAUDE.md" ]]; then
|
|
cp "${cwd}/CLAUDE.md" "${cwd}/.claude/CLAUDE.md"
|
|
fi
|
|
|
|
docker pull containers.ion606.dev/ion606/claude-docker:latest 1> /dev/null
|
|
|
|
# resolve symlinks under cwd, mount host targets at container-side resolved paths
|
|
# absolute link: container path == host target
|
|
# relative link: container path = normalize(/workspace + relpath(link,cwd)/.. + raw)
|
|
symlink_max_depth="${CLAUDE_SYMLINK_MAXDEPTH:-3}"
|
|
symlink_mounts=()
|
|
seen_pairs=()
|
|
while IFS= read -r -d '' link; do
|
|
host_target="$(readlink -f -- "$link" 2>/dev/null)" || continue
|
|
[[ -z "$host_target" || ! -e "$host_target" ]] && continue
|
|
|
|
# skip if target inside cwd (already covered by /workspace mount)
|
|
[[ "$host_target" == "$cwd"/* || "$host_target" == "$cwd" ]] && continue
|
|
|
|
raw="$(readlink -- "$link")"
|
|
if [[ "$raw" = /* ]]; then
|
|
container_path="$host_target"
|
|
else
|
|
rel="${link#$cwd/}"
|
|
container_path="$(realpath -m "/workspace/$(dirname "$rel")/$raw")"
|
|
fi
|
|
|
|
pair="${host_target}:${container_path}"
|
|
for p in "${seen_pairs[@]:-}"; do [[ "$p" == "$pair" ]] && continue 2; done
|
|
|
|
seen_pairs+=("$pair")
|
|
symlink_mounts+=(-v "$pair")
|
|
done < <(find "$cwd" -maxdepth "$symlink_max_depth" -type l -print0 2>/dev/null)
|
|
|
|
|
|
docker run --rm -it \
|
|
-v "${cwd}:/workspace" \
|
|
-v "${HOME}/.claude/plugins:/home/claude/.claude/plugins:ro" \
|
|
-v "${HOME}/.claude/settings.json:/home/claude/.claude/settings.json:ro" \
|
|
"${symlink_mounts[@]}" \
|
|
-e CLAUDE_CODE_OAUTH_TOKEN \
|
|
-e AUTH_BLOB \
|
|
--cap-drop ALL \
|
|
--gpus all \
|
|
containers.ion606.dev/ion606/claude-docker:latest "$@" \
|
|
2>&1 | tee "$session_file"
|