Skip to content

Download Claude Code Offline Packages #11

Download Claude Code Offline Packages

Download Claude Code Offline Packages #11

name: Download Claude Code Offline Packages
on:
# Manual trigger
workflow_dispatch:
inputs:
force_rebuild:
description: 'Force rebuild even if version exists'
required: false
default: 'false'
# Daily check for new versions at 00:00 UTC
# Weekly full rebuild every Monday at 00:00 UTC
schedule:
- cron: '0 0 * * *' # Daily
- cron: '0 0 * * 1' # Weekly (Monday)
env:
NODE_VERSION: '20'
NPM_REGISTRY: 'https://registry.npmmirror.com'
jobs:
check-version:
runs-on: ubuntu-latest
outputs:
latest_version: ${{ steps.check.outputs.latest_version }}
should_build: ${{ steps.check.outputs.should_build }}
release_exists: ${{ steps.check.outputs.release_exists }}
steps:
- name: Install jq
run: |
sudo apt-get update && sudo apt-get install -y jq
- name: Check latest version from npm
id: check
run: |
set -e
echo "=== Checking latest version from npm ==="
# Get latest version from npm
NPM_RESPONSE=$(curl -s https://registry.npmjs.org/@anthropic-ai/claude-code)
LATEST_VERSION=$(echo "$NPM_RESPONSE" | jq -r '.["dist-tags"].latest // empty')
if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then
echo "ERROR: Failed to get version from npm"
echo "Response: $NPM_RESPONSE"
exit 1
fi
echo "Latest npm version: $LATEST_VERSION"
echo "latest_version=$LATEST_VERSION" >> $GITHUB_OUTPUT
# Check if release already exists
echo "=== Checking if release exists ==="
RELEASE_RESPONSE=$(curl -s -w "\n%{http_code}" \
"https://api.github.com/repos/${{ github.repository }}/releases/tags/v${LATEST_VERSION}")
HTTP_CODE=$(echo "$RELEASE_RESPONSE" | tail -1)
if [ "$HTTP_CODE" = "200" ]; then
echo "Release v${LATEST_VERSION} already exists"
echo "release_exists=true" >> $GITHUB_OUTPUT
# Check if force rebuild
FORCE_REBUILD="${{ github.event.inputs.force_rebuild }}"
if [ "$FORCE_REBUILD" = "true" ]; then
echo "Force rebuild requested"
echo "should_build=true" >> $GITHUB_OUTPUT
else
echo "Skipping build - version already exists"
echo "should_build=false" >> $GITHUB_OUTPUT
fi
elif [ "$HTTP_CODE" = "404" ]; then
echo "Release v${LATEST_VERSION} does not exist"
echo "release_exists=false" >> $GITHUB_OUTPUT
echo "should_build=true" >> $GITHUB_OUTPUT
else
echo "WARNING: Unexpected HTTP code $HTTP_CODE"
echo "Assuming release does not exist, proceeding with build"
echo "release_exists=false" >> $GITHUB_OUTPUT
echo "should_build=true" >> $GITHUB_OUTPUT
fi
build-offline-packages:
needs: check-version
runs-on: ubuntu-latest
if: needs.check-version.outputs.should_build == 'true'
permissions:
contents: write
steps:
- name: Debug outputs
run: |
echo "Latest version: ${{ needs.check-version.outputs.latest_version }}"
echo "Should build: ${{ needs.check-version.outputs.should_build }}"
echo "Release exists: ${{ needs.check-version.outputs.release_exists }}"
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Configure npm mirrors
run: |
# Configure npm to use domestic mirror
npm config set registry ${{ env.NPM_REGISTRY }}
# Verify configuration
echo "npm registry configured: $(npm config get registry)"
- name: Install Claude Code globally
run: |
npm install -g @anthropic-ai/claude-code
# Verify installation
echo "=== Verifying installation ==="
which claude || echo "claude not in PATH"
ls -la $(npm prefix -g)/lib/node_modules/@anthropic-ai/claude-code/ || true
CLAUDE_VERSION="${{ needs.check-version.outputs.latest_version }}"
echo "CLAUDE_VERSION=$CLAUDE_VERSION" >> $GITHUB_ENV
echo "Building Claude Code version: $CLAUDE_VERSION"
- name: Prepare offline packages
run: |
set -e
echo "=== Preparing offline packages ==="
# Create output directory
mkdir -p claude-offline-packages
# Get Claude Code version
CLAUDE_VERSION="${{ needs.check-version.outputs.latest_version }}"
echo "CLAUDE_VERSION=$CLAUDE_VERSION" >> $GITHUB_ENV
echo "Building Claude Code version: $CLAUDE_VERSION"
# Find global installation path
GLOBAL_PREFIX=$(npm prefix -g)
echo "NPM global prefix: $GLOBAL_PREFIX"
# Copy global installation directly (don't npm install, it has publish restrictions)
if [ -d "$GLOBAL_PREFIX/lib/node_modules/@anthropic-ai/claude-code" ]; then
echo "Found global installation, copying..."
mkdir -p claude-offline-packages/node_modules/@anthropic-ai
cp -r "$GLOBAL_PREFIX/lib/node_modules/@anthropic-ai/claude-code" claude-offline-packages/node_modules/@anthropic-ai/
# Also copy .bin if exists
if [ -d "$GLOBAL_PREFIX/lib/node_modules/.bin" ]; then
cp -r "$GLOBAL_PREFIX/lib/node_modules/.bin" claude-offline-packages/node_modules/
fi
else
echo "ERROR: Global installation not found"
find "$GLOBAL_PREFIX" -name "claude-code" -type d 2>/dev/null || true
exit 1
fi
cd claude-offline-packages
# Create .bin directory and links if not exist
mkdir -p node_modules/.bin
if [ -f "node_modules/@anthropic-ai/claude-code/cli.js" ]; then
echo "Creating symlink for cli.js"
ln -sf ../@anthropic-ai/claude-code/cli.js node_modules/.bin/claude
else
echo "ERROR: cli.js not found"
find . -name "cli.js" 2>/dev/null || true
exit 1
fi
# Add execute permissions
chmod +x node_modules/.bin/claude 2>/dev/null || true
chmod -R +x node_modules/@anthropic-ai/claude-code/ 2>/dev/null || true
echo "=== Package structure ==="
ls -la
ls -la node_modules/.bin/ || true
ls -la node_modules/@anthropic-ai/claude-code/ | head -20
- name: Download VSCode extension
run: |
# Try to download latest VSCode extension
echo "=== Checking for VSCode extension ==="
# Go back to root directory (Prepare step changed to claude-offline-packages)
cd "$GITHUB_WORKSPACE"
RELEASE_INFO=$(curl -s https://api.github.com/repos/anthropics/claude-code/releases/latest)
EXTENSION_URL=$(echo "$RELEASE_INFO" | jq -r '.assets[] | select(.name | contains(".vsix")) | .browser_download_url' | head -1)
if [ -n "$EXTENSION_URL" ] && [ "$EXTENSION_URL" != "null" ]; then
echo "Downloading VSCode extension from: $EXTENSION_URL"
curl -L -o claude-offline-packages/anthropic.claude-code.vsix "$EXTENSION_URL" || {
echo "WARNING: Failed to download VSCode extension"
}
# Verify download
if [ -f "claude-offline-packages/anthropic.claude-code.vsix" ]; then
echo "✓ VSCode extension downloaded successfully"
ls -lh claude-offline-packages/anthropic.claude-code.vsix
fi
else
echo "No VSCode extension found in releases, skipping..."
fi
continue-on-error: true
- name: Copy setup script
run: |
echo "=== Copying setup script ==="
# Ensure we're in the correct directory
cd "$GITHUB_WORKSPACE"
cp setup-claude-code.sh claude-offline-packages/
chmod +x claude-offline-packages/setup-claude-code.sh
if [ -f "check-update.sh" ]; then
cp check-update.sh claude-offline-packages/
chmod +x claude-offline-packages/check-update.sh
fi
echo "Files in package:"
ls -la claude-offline-packages/
# Verify VSCode extension is included
if [ -f "claude-offline-packages/anthropic.claude-code.vsix" ]; then
echo "✓ VSCode extension included in package"
else
echo "! VSCode extension not found in package"
fi
- name: Create package info
run: |
BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
CLAUDE_VERSION="${{ needs.check-version.outputs.latest_version }}"
cat > claude-offline-packages/package-info.json << EOF
{
"name": "claude-offline-packages",
"version": "${CLAUDE_VERSION}",
"created_at": "${BUILD_DATE}",
"node_version": "${{ env.NODE_VERSION }}",
"source": "https://www.npmjs.com/package/@anthropic-ai/claude-code",
"github_repo": "${{ github.repository }}"
}
EOF
echo "=== Package info ==="
cat claude-offline-packages/package-info.json
- name: Pack offline packages
run: |
echo "=== Packing offline packages ==="
# List all files before packing
echo "Files to be packed:"
ls -la claude-offline-packages/
# Check if VSCode extension exists
if [ -f "claude-offline-packages/anthropic.claude-code.vsix" ]; then
echo "✓ VSCode extension will be included in the package"
else
echo "! Warning: VSCode extension not found"
fi
tar -czf claude-offline-packages.tar.gz claude-offline-packages/
# Calculate checksum
sha256sum claude-offline-packages.tar.gz > claude-offline-packages.tar.gz.sha256
# Show package size
echo "Package size:"
ls -lh claude-offline-packages.tar.gz
ls -lh claude-offline-packages.tar.gz.sha256
# Verify archive contents
echo "=== Verifying archive contents ==="
echo "Looking for VSCode extension in archive:"
tar -tzf claude-offline-packages.tar.gz | grep -i "vsix" || echo "! VSCode extension not found in archive"
- name: Create GitHub Release
id: create_release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ needs.check-version.outputs.latest_version }}
name: Claude Code v${{ needs.check-version.outputs.latest_version }}
body: |
## Claude Code Offline Package v${{ needs.check-version.outputs.latest_version }}
**Version:** ${{ needs.check-version.outputs.latest_version }}
**Node.js:** ${{ env.NODE_VERSION }}
**Build Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")
### Downloads
| File | Description |
|------|-------------|
| `claude-offline-packages.tar.gz` | Offline installation package |
| `claude-offline-packages.tar.gz.sha256` | SHA256 checksum |
### Quick Start
```bash
# 1. Download and extract
tar -xzf claude-offline-packages.tar.gz
# 2. Run installer
cd claude-offline-packages
bash setup-claude-code.sh
```
### Verification
```bash
sha256sum -c claude-offline-packages.tar.gz.sha256
```
### Features
- ✅ Automatic mirror source detection
- ✅ Region restriction bypass
- ✅ Multi-language support (EN/ZH)
- ✅ Universal Node.js installation
- ✅ Uninstall support
draft: false
prerelease: false
files: |
claude-offline-packages.tar.gz
claude-offline-packages.tar.gz.sha256
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: claude-offline-packages-v${{ needs.check-version.outputs.latest_version }}
path: |
claude-offline-packages.tar.gz
claude-offline-packages.tar.gz.sha256
retention-days: 30
notify-no-build:
needs: check-version
runs-on: ubuntu-latest
if: needs.check-version.outputs.should_build == 'false'
steps:
- name: Skip notification
run: |
echo "Skipping build - version ${{ needs.check-version.outputs.latest_version }} already exists"
echo "To force rebuild, trigger workflow with 'force_rebuild' set to 'true'"