Merge pull request #1868 from vitorpamplona/claude/fix-missing-plugin-adHgr

Fix proxy bypass and improve code formatting
This commit is contained in:
Vitor Pamplona
2026-03-16 23:51:49 -04:00
committed by GitHub
13 changed files with 210 additions and 88 deletions
+169 -63
View File
@@ -1,12 +1,59 @@
#!/bin/bash
# Session start hook: Configure proxy auth, SSL trust, and Android SDK for Claude Code on the web
set -euo pipefail
# Only run in remote (web) environments
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
exit 0
fi
# --- Fix no_proxy: remove *.google.com and *.googleapis.com so traffic routes through proxy ---
# The default no_proxy in Claude Code web includes *.google.com and *.googleapis.com,
# which causes JVM/curl to bypass the proxy for Google Maven (dl.google.com).
# These domains MUST go through the proxy for authenticated egress to work.
fix_no_proxy() {
local var="$1"
local val="${!var:-}"
if [ -n "$val" ]; then
# Remove *.google.com, *.googleapis.com entries from the comma-separated list
local fixed
fixed=$(echo "$val" | tr ',' '\n' | grep -v -E '^\*\.google\.com$|^\*\.googleapis\.com$' | tr '\n' ',' | sed 's/,$//')
export "$var=$fixed"
fi
}
fix_no_proxy no_proxy
fix_no_proxy NO_PROXY
# --- Fix JAVA_TOOL_OPTIONS: remove nonProxyHosts that bypass Google domains ---
# JAVA_TOOL_OPTIONS may contain -Dhttp.nonProxyHosts=...|*.google.com|*.googleapis.com
# which prevents the JVM from routing Google Maven traffic through the proxy.
if [ -n "${JAVA_TOOL_OPTIONS:-}" ]; then
# Remove the nonProxyHosts entries for google.com and googleapis.com from the JVM options
# Strategy: rewrite the -Dhttp.nonProxyHosts value to exclude google patterns
JAVA_TOOL_OPTIONS=$(echo "$JAVA_TOOL_OPTIONS" | sed -E '
s/-Dhttp\.nonProxyHosts=[^ ]*/\n&\n/g
' | while IFS= read -r line; do
if [[ "$line" == -Dhttp.nonProxyHosts=* ]]; then
# Extract the value, remove google patterns, reconstruct
val="${line#-Dhttp.nonProxyHosts=}"
fixed=$(echo "$val" | tr '|' '\n' | grep -v -E '^\*\.google\.com$|^\*\.googleapis\.com$' | tr '\n' '|' | sed 's/|$//')
echo "-Dhttp.nonProxyHosts=$fixed"
else
echo "$line"
fi
done | tr '\n' ' ' | sed 's/ */ /g; s/^ //; s/ $//')
export JAVA_TOOL_OPTIONS
fi
# Export fixed env vars for the session
if [ -n "${CLAUDE_ENV_FILE:-}" ]; then
echo "export no_proxy='${no_proxy:-}'" >> "$CLAUDE_ENV_FILE"
echo "export NO_PROXY='${NO_PROXY:-}'" >> "$CLAUDE_ENV_FILE"
echo "export JAVA_TOOL_OPTIONS='$JAVA_TOOL_OPTIONS'" >> "$CLAUDE_ENV_FILE"
fi
echo "Fixed proxy bypass settings (no_proxy, JAVA_TOOL_OPTIONS)" >&2
# --- Proxy credentials: configure Maven/Gradle if authenticated proxy is set ---
proxy="${https_proxy:-${HTTPS_PROXY:-}}"
if [ -n "$proxy" ] && echo "$proxy" | grep -q '@'; then
@@ -99,68 +146,11 @@ if [ -n "$ANTHROPIC_CA_PEM" ]; then
rm -f "$TMPCA"
fi
# --- Project setup: local.properties and env vars (before SDK download so these always run) ---
ANDROID_SDK_DIR="/root/android-sdk"
SDK_REPO_BASE="https://dl.google.com/android/repository"
# Install Android SDK packages by downloading directly with curl
# (sdkmanager cannot reach the SDK repository through the proxy)
install_sdk_package() {
local zip_url="$1"
local dest_dir="$2"
local inner_dir="$3" # top-level dir inside the zip
if [ -d "$dest_dir" ]; then
return 0
fi
echo "Downloading $zip_url..."
local TMP_ZIP
TMP_ZIP=$(mktemp /tmp/sdk-pkg.XXXXXX.zip)
curl -fsSL "$zip_url" -o "$TMP_ZIP"
local TMP_DIR
TMP_DIR=$(mktemp -d)
unzip -q "$TMP_ZIP" -d "$TMP_DIR"
rm -f "$TMP_ZIP"
mkdir -p "$(dirname "$dest_dir")"
mv "$TMP_DIR/$inner_dir" "$dest_dir"
rm -rf "$TMP_DIR"
echo "Installed to $dest_dir"
}
# Install Android platform 36
install_sdk_package \
"$SDK_REPO_BASE/platform-36_r02.zip" \
"$ANDROID_SDK_DIR/platforms/android-36" \
"android-36"
# Install build-tools 36.0.0 (zip uses "android-16" as inner dir name)
install_sdk_package \
"$SDK_REPO_BASE/build-tools_r36_linux.zip" \
"$ANDROID_SDK_DIR/build-tools/36.0.0" \
"android-16"
# Install platform-tools
install_sdk_package \
"$SDK_REPO_BASE/platform-tools_r37.0.0-linux.zip" \
"$ANDROID_SDK_DIR/platform-tools" \
"platform-tools"
# Accept SDK licenses (create license files manually)
echo "Writing SDK license files..."
mkdir -p "$ANDROID_SDK_DIR/licenses"
# android-sdk-license
echo -e "\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_SDK_DIR/licenses/android-sdk-license"
echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" >> "$ANDROID_SDK_DIR/licenses/android-sdk-license"
# android-sdk-preview-license
echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_SDK_DIR/licenses/android-sdk-preview-license"
echo -e "\n504667f4c0de7af1a06de9f4b1727b84351f2910" >> "$ANDROID_SDK_DIR/licenses/android-sdk-preview-license"
# intel-android-extra-license
echo -e "\nd975f751698a77b662f1254ddbeed3901e976f5a" > "$ANDROID_SDK_DIR/licenses/intel-android-extra-license"
REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null || echo "${CLAUDE_PROJECT_DIR:-/home/user/amethyst}")"
# Create local.properties if missing
REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null || echo "${CLAUDE_PROJECT_DIR:-/home/user/Amber}")"
LOCAL_PROPS="$REPO_ROOT/local.properties"
if [ ! -f "$LOCAL_PROPS" ]; then
echo "sdk.dir=$ANDROID_SDK_DIR" > "$LOCAL_PROPS"
@@ -174,7 +164,123 @@ if [ -n "${CLAUDE_ENV_FILE:-}" ]; then
echo "export PATH=\$PATH:$ANDROID_SDK_DIR/platform-tools" >> "$CLAUDE_ENV_FILE"
fi
cd "$CLAUDE_PROJECT_DIR"
./gradlew --version > /dev/null 2>&1
# --- Install standalone ktlint (fallback for spotlessApply when Gradle can't resolve AGP) ---
# The egress proxy may block dl.google.com (Google Maven), preventing Gradle from resolving
# the Android Gradle Plugin. Since spotlessApply depends on Gradle's plugin resolution,
# we install ktlint standalone as a reliable alternative.
KTLINT_VERSION="1.5.0"
KTLINT_BIN="/usr/local/bin/ktlint"
if [ ! -x "$KTLINT_BIN" ]; then
echo "Installing ktlint $KTLINT_VERSION..." >&2
if curl -fsSL "https://github.com/pinterest/ktlint/releases/download/${KTLINT_VERSION}/ktlint" -o "$KTLINT_BIN" 2>/dev/null; then
chmod +x "$KTLINT_BIN"
echo "Installed ktlint $KTLINT_VERSION to $KTLINT_BIN" >&2
else
echo "WARNING: Failed to install ktlint (GitHub may be unreachable)" >&2
fi
fi
echo "Android SDK setup complete."
# Create a spotless-apply wrapper that mimics the Gradle spotless configuration
cat > /usr/local/bin/spotless-apply << 'SPOTLESS_SCRIPT'
#!/bin/bash
# Standalone spotless-apply: runs ktlint with the same settings as the Gradle spotless plugin.
# Use this when ./gradlew spotlessApply fails due to proxy/network issues.
set -euo pipefail
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$REPO_ROOT"
if ! command -v ktlint &>/dev/null; then
echo "ERROR: ktlint not found. Install it first." >&2
exit 1
fi
echo "Running ktlint format on Kotlin sources..."
# Find all Kotlin source files matching the spotless target pattern (src/**/*.kt)
# Exclude build directories
ktlint --format "**/*.kt" 2>&1 | grep -v "^$" || true
echo "Done. Files formatted with ktlint."
SPOTLESS_SCRIPT
chmod +x /usr/local/bin/spotless-apply
# --- Android SDK download (non-fatal: warns if dl.google.com is blocked) ---
SDK_REPO_BASE="https://dl.google.com/android/repository"
install_sdk_package() {
local zip_url="$1"
local dest_dir="$2"
local inner_dir="$3" # top-level dir inside the zip
if [ -d "$dest_dir" ]; then
return 0
fi
echo "Downloading $zip_url..." >&2
local TMP_ZIP
TMP_ZIP=$(mktemp /tmp/sdk-pkg.XXXXXX.zip)
if ! curl -fsSL "$zip_url" -o "$TMP_ZIP" 2>/dev/null; then
rm -f "$TMP_ZIP"
echo "WARNING: Failed to download $zip_url (dl.google.com may be blocked by proxy)" >&2
echo " -> Add dl.google.com to the egress proxy allowlist to fix this" >&2
return 1
fi
local TMP_DIR
TMP_DIR=$(mktemp -d)
unzip -q "$TMP_ZIP" -d "$TMP_DIR"
rm -f "$TMP_ZIP"
mkdir -p "$(dirname "$dest_dir")"
mv "$TMP_DIR/$inner_dir" "$dest_dir"
rm -rf "$TMP_DIR"
echo "Installed to $dest_dir" >&2
}
sdk_ok=true
# Install Android platform 36
if ! install_sdk_package \
"$SDK_REPO_BASE/platform-36_r02.zip" \
"$ANDROID_SDK_DIR/platforms/android-36" \
"android-36"; then
sdk_ok=false
fi
# Install build-tools 36.0.0 (zip uses "android-16" as inner dir name)
if ! install_sdk_package \
"$SDK_REPO_BASE/build-tools_r36_linux.zip" \
"$ANDROID_SDK_DIR/build-tools/36.0.0" \
"android-16"; then
sdk_ok=false
fi
# Install platform-tools
if ! install_sdk_package \
"$SDK_REPO_BASE/platform-tools_r37.0.0-linux.zip" \
"$ANDROID_SDK_DIR/platform-tools" \
"platform-tools"; then
sdk_ok=false
fi
if [ "$sdk_ok" = true ]; then
# Accept SDK licenses (create license files manually)
echo "Writing SDK license files..." >&2
mkdir -p "$ANDROID_SDK_DIR/licenses"
echo -e "\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_SDK_DIR/licenses/android-sdk-license"
echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" >> "$ANDROID_SDK_DIR/licenses/android-sdk-license"
echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_SDK_DIR/licenses/android-sdk-preview-license"
echo -e "\n504667f4c0de7af1a06de9f4b1727b84351f2910" >> "$ANDROID_SDK_DIR/licenses/android-sdk-preview-license"
echo -e "\nd975f751698a77b662f1254ddbeed3901e976f5a" > "$ANDROID_SDK_DIR/licenses/intel-android-extra-license"
echo "Android SDK setup complete." >&2
else
echo "WARNING: Android SDK download failed. dl.google.com is likely blocked by the egress proxy." >&2
echo " -> Gradle builds requiring AGP will fail until dl.google.com is added to the proxy allowlist." >&2
echo " -> Use 'spotless-apply' (standalone ktlint) instead of './gradlew spotlessApply'." >&2
fi
# Warm up Gradle wrapper (non-fatal)
cd "$REPO_ROOT"
./gradlew --version > /dev/null 2>&1 || true
echo "Session start hook complete." >&2
+1 -1
View File
@@ -16,7 +16,7 @@
"hooks": [
{
"type": "command",
"command": "./gradlew spotlessApply",
"command": "./gradlew spotlessApply 2>/dev/null || spotless-apply",
"timeout": 120
}
]
@@ -119,11 +119,12 @@ object ShareHelper {
bytesRead >= 12 && matchesMagicNumbers(header, 4, MOV_FTYP) -> detectMp4OrMov(header)
// MP4/MOV alternative: moov, mdat, or free at offset 4
bytesRead >= 8 && (
matchesMagicNumbers(header, 4, MOV_MOOV) ||
matchesMagicNumbers(header, 4, MOV_MDAT) ||
matchesMagicNumbers(header, 4, MOV_FREE)
) -> "mp4"
bytesRead >= 8 &&
(
matchesMagicNumbers(header, 4, MOV_MOOV) ||
matchesMagicNumbers(header, 4, MOV_MDAT) ||
matchesMagicNumbers(header, 4, MOV_FREE)
) -> "mp4"
else -> defaultExtension
}
@@ -297,8 +297,10 @@ fun ChessLobbyContent(
val userPubkey = accountViewModel.account.userProfile().pubkeyHex
val hasContent =
activeGames.isNotEmpty() || spectatingGames.isNotEmpty() ||
publicGames.isNotEmpty() || challenges.isNotEmpty()
activeGames.isNotEmpty() ||
spectatingGames.isNotEmpty() ||
publicGames.isNotEmpty() ||
challenges.isNotEmpty()
if (!hasContent) {
// Empty state - use LazyColumn so pull-to-refresh works
@@ -83,7 +83,8 @@ class HashtagFeedFilter(
event is PrivateDmEvent ||
event is PollNoteEvent ||
event is AudioHeaderEvent
) && event.isTaggedHash(hashTag)
) &&
event.isTaggedHash(hashTag)
fun acceptableViaScope(
event: Event?,
@@ -1047,7 +1047,8 @@ open class ShortNotePostViewModel :
(
!wantsPoll ||
(
pollOptions.isNotEmpty() && pollOptions.all { it.value.label.isNotEmpty() } &&
pollOptions.isNotEmpty() &&
pollOptions.all { it.value.label.isNotEmpty() } &&
closedAt > TimeUtils.oneMinuteFromNow()
)
) &&
@@ -77,12 +77,13 @@ class UserProfileGalleryFeedFilter(
val noteEvent = it.event
return (
(
it.event?.pubKey == user.pubkeyHex && (
noteEvent is PictureEvent ||
noteEvent is RegularVideoEvent ||
(noteEvent is ReplaceableVideoEvent && it is AddressableNote) ||
(noteEvent is ProfileGalleryEntryEvent && noteEvent.hasUrl() && noteEvent.hasFromEvent())
)
it.event?.pubKey == user.pubkeyHex &&
(
noteEvent is PictureEvent ||
noteEvent is RegularVideoEvent ||
(noteEvent is ReplaceableVideoEvent && it is AddressableNote) ||
(noteEvent is ProfileGalleryEntryEvent && noteEvent.hasUrl() && noteEvent.hasFromEvent())
)
) // && noteEvent.isOneOf(SUPPORTED_VIDEO_FEED_MIME_TYPES_SET))
) &&
params.match(noteEvent, it.relays) &&
@@ -345,8 +345,11 @@ private fun ChessLobby(
listState: LazyListState = rememberLazyListState(),
) {
val hasContent =
activeGames.isNotEmpty() || spectatingGames.isNotEmpty() ||
publicGames.isNotEmpty() || challenges.isNotEmpty() || completedGames.isNotEmpty()
activeGames.isNotEmpty() ||
spectatingGames.isNotEmpty() ||
publicGames.isNotEmpty() ||
challenges.isNotEmpty() ||
completedGames.isNotEmpty()
if (!hasContent) {
// Empty state
@@ -678,7 +678,8 @@ class QueryBuilder(
val search: String? = null,
) {
fun isSimpleSearch() =
search != null && search.isNotEmpty() &&
search != null &&
search.isNotEmpty() &&
(nonDTagsIn == null || nonDTagsIn.isEmpty()) &&
(nonDTagsAll == null || nonDTagsAll.isEmpty())
@@ -301,7 +301,8 @@ class NamecoinNameResolver(
pubkey = rootMatch.content
}
firstEntry != null && firstEntry.value is JsonPrimitive &&
firstEntry != null &&
firstEntry.value is JsonPrimitive &&
isValidPubkey((firstEntry.value as JsonPrimitive).content) -> {
resolvedLocalPart = firstEntry.key
pubkey = (firstEntry.value as JsonPrimitive).content
@@ -217,9 +217,12 @@ object ChessStateReconstructor {
return fen1 == fen2 // Fallback to exact match
}
return parts1[0] == parts2[0] && // Board position
parts1[1] == parts2[1] && // Active color
parts1[2] == parts2[2] && // Castling rights
return parts1[0] == parts2[0] &&
// Board position
parts1[1] == parts2[1] &&
// Active color
parts1[2] == parts2[2] &&
// Castling rights
parts1[3] == parts2[3] // En passant
}
@@ -212,7 +212,8 @@ actual class ChessEngine {
board.getPiece(toSquare) != Piece.NONE ||
(
pt == com.github.bhlangonijr.chesslib.PieceType.PAWN &&
epTarget != Square.NONE && toSquare == epTarget
epTarget != Square.NONE &&
toSquare == epTarget
)
if (pt != com.github.bhlangonijr.chesslib.PieceType.PAWN) {
@@ -261,7 +261,8 @@ class NamecoinNameResolverTest {
pubkey = rootMatch.content
}
firstEntry != null && firstEntry.value is kotlinx.serialization.json.JsonPrimitive &&
firstEntry != null &&
firstEntry.value is kotlinx.serialization.json.JsonPrimitive &&
(firstEntry.value as kotlinx.serialization.json.JsonPrimitive)
.content
.matches(Regex("^[0-9a-fA-F]{64}$")) -> {