mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
- Add detailed file verification before extraction - Check if downloaded file is a valid ZIP archive - Add file type detection and display - Better error messages showing actual file status - Add ZIP integrity testing on extraction failure - Display temp directory contents on extraction failure Helps diagnose download/extraction issues by showing: - File existence and size - File type (ZIP vs other) - First bytes of file (for debugging) - ZIP integrity test results 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
394 lines
11 KiB
Bash
394 lines
11 KiB
Bash
#!/usr/bin/env bash
|
|
# Claude Code Workflow (CCW) - Remote Installation Script
|
|
# One-liner remote installation for Claude Code Workflow system
|
|
|
|
set -e # Exit on error
|
|
|
|
# Script metadata
|
|
SCRIPT_NAME="Claude Code Workflow (CCW) Remote Installer"
|
|
VERSION="2.1.1"
|
|
BRANCH="${BRANCH:-main}"
|
|
|
|
# Colors for output
|
|
COLOR_RESET='\033[0m'
|
|
COLOR_SUCCESS='\033[0;32m'
|
|
COLOR_INFO='\033[0;36m'
|
|
COLOR_WARNING='\033[0;33m'
|
|
COLOR_ERROR='\033[0;31m'
|
|
|
|
# Variables
|
|
INSTALL_GLOBAL=false
|
|
INSTALL_DIR=""
|
|
FORCE=false
|
|
NO_BACKUP=false
|
|
NON_INTERACTIVE=false
|
|
BACKUP_ALL=false
|
|
|
|
# Functions
|
|
function write_color() {
|
|
local message="$1"
|
|
local color="${2:-$COLOR_RESET}"
|
|
echo -e "${color}${message}${COLOR_RESET}"
|
|
}
|
|
|
|
function show_header() {
|
|
write_color "==== $SCRIPT_NAME v$VERSION ====" "$COLOR_INFO"
|
|
write_color "========================================================" "$COLOR_INFO"
|
|
echo ""
|
|
}
|
|
|
|
function test_prerequisites() {
|
|
# Test bash version
|
|
if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
|
|
write_color "ERROR: Bash 4.0 or higher is required" "$COLOR_ERROR"
|
|
write_color "Current version: ${BASH_VERSION}" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
|
|
# Test required commands
|
|
for cmd in curl unzip; do
|
|
if ! command -v "$cmd" &> /dev/null; then
|
|
write_color "ERROR: Required command '$cmd' not found" "$COLOR_ERROR"
|
|
write_color "Please install: $cmd" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
# Test internet connectivity
|
|
if curl -sSf --connect-timeout 10 "https://github.com" &> /dev/null; then
|
|
write_color "✓ Network connection OK" "$COLOR_SUCCESS"
|
|
else
|
|
write_color "ERROR: Cannot connect to GitHub" "$COLOR_ERROR"
|
|
write_color "Please check your network connection" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
function get_temp_directory() {
|
|
local temp_dir
|
|
temp_dir=$(mktemp -d -t claude-code-workflow-install.XXXXXX)
|
|
echo "$temp_dir"
|
|
}
|
|
|
|
function download_repository() {
|
|
local temp_dir="$1"
|
|
local branch="${2:-main}"
|
|
local repo_url="https://github.com/catlog22/Claude-Code-Workflow"
|
|
local zip_url="${repo_url}/archive/refs/heads/${branch}.zip"
|
|
local zip_path="${temp_dir}/repo.zip"
|
|
|
|
write_color "Downloading from GitHub..." "$COLOR_INFO"
|
|
write_color "Source: $repo_url" "$COLOR_INFO"
|
|
write_color "Branch: $branch" "$COLOR_INFO"
|
|
write_color "URL: $zip_url" "$COLOR_INFO"
|
|
|
|
# Use -L to follow redirects and -J to use server-provided filename
|
|
if curl -fsSL -o "$zip_path" "$zip_url"; then
|
|
# Verify the download
|
|
if [ -f "$zip_path" ] && [ -s "$zip_path" ]; then
|
|
local file_size
|
|
file_size=$(du -h "$zip_path" | cut -f1)
|
|
write_color "✓ Download complete ($file_size)" "$COLOR_SUCCESS"
|
|
write_color "Downloaded to: $zip_path" "$COLOR_INFO"
|
|
|
|
# Check file type
|
|
if command -v file &> /dev/null; then
|
|
local file_type=$(file "$zip_path")
|
|
write_color "File type: $file_type" "$COLOR_INFO"
|
|
fi
|
|
|
|
echo "$zip_path"
|
|
return 0
|
|
else
|
|
write_color "ERROR: Downloaded file is missing or empty" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
else
|
|
write_color "Download failed" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function extract_repository() {
|
|
local zip_path="$1"
|
|
local temp_dir="$2"
|
|
|
|
write_color "Extracting files..." "$COLOR_INFO"
|
|
|
|
# Verify zip file exists and is not empty
|
|
if [ ! -f "$zip_path" ]; then
|
|
write_color "ERROR: Downloaded file not found: $zip_path" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -s "$zip_path" ]; then
|
|
write_color "ERROR: Downloaded file is empty" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
|
|
# Check if file is actually a zip file
|
|
if ! file "$zip_path" 2>/dev/null | grep -q "Zip\|ZIP"; then
|
|
write_color "ERROR: Downloaded file is not a valid ZIP archive" "$COLOR_ERROR"
|
|
write_color "File type: $(file "$zip_path" 2>/dev/null || echo 'unknown')" "$COLOR_ERROR"
|
|
write_color "First few bytes:" "$COLOR_ERROR"
|
|
head -c 100 "$zip_path" | od -A x -t x1z -v | head -n 3
|
|
return 1
|
|
fi
|
|
|
|
# Try to extract
|
|
if unzip -q "$zip_path" -d "$temp_dir" 2>&1; then
|
|
# Find the extracted directory (usually repo-name-branch)
|
|
local repo_dir
|
|
repo_dir=$(find "$temp_dir" -maxdepth 1 -type d -name "Claude-Code-Workflow-*" | head -n 1)
|
|
|
|
if [ -n "$repo_dir" ]; then
|
|
write_color "✓ Extraction complete: $repo_dir" "$COLOR_SUCCESS"
|
|
echo "$repo_dir"
|
|
return 0
|
|
else
|
|
write_color "Could not find extracted repository directory" "$COLOR_ERROR"
|
|
write_color "Contents of temp directory:" "$COLOR_INFO"
|
|
ls -la "$temp_dir"
|
|
return 1
|
|
fi
|
|
else
|
|
write_color "Extraction failed" "$COLOR_ERROR"
|
|
write_color "Testing zip file integrity..." "$COLOR_INFO"
|
|
unzip -t "$zip_path"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function invoke_local_installer() {
|
|
local repo_dir="$1"
|
|
local installer_path="${repo_dir}/Install-Claude.sh"
|
|
|
|
# Make installer executable
|
|
if [ -f "$installer_path" ]; then
|
|
chmod +x "$installer_path"
|
|
else
|
|
write_color "ERROR: Install-Claude.sh not found" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
|
|
write_color "Running local installer..." "$COLOR_INFO"
|
|
echo ""
|
|
|
|
# Build parameters for local installer
|
|
local params=()
|
|
|
|
if [ "$INSTALL_GLOBAL" = true ]; then
|
|
params+=("-InstallMode" "Global")
|
|
fi
|
|
|
|
if [ -n "$INSTALL_DIR" ]; then
|
|
params+=("-InstallMode" "Path" "-TargetPath" "$INSTALL_DIR")
|
|
fi
|
|
|
|
if [ "$FORCE" = true ]; then
|
|
params+=("-Force")
|
|
fi
|
|
|
|
if [ "$NO_BACKUP" = true ]; then
|
|
params+=("-NoBackup")
|
|
fi
|
|
|
|
if [ "$NON_INTERACTIVE" = true ]; then
|
|
params+=("-NonInteractive")
|
|
fi
|
|
|
|
if [ "$BACKUP_ALL" = true ]; then
|
|
params+=("-BackupAll")
|
|
fi
|
|
|
|
# Execute installer
|
|
if (cd "$repo_dir" && "$installer_path" "${params[@]}"); then
|
|
return 0
|
|
else
|
|
write_color "Installation script failed" "$COLOR_ERROR"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function cleanup_temp_files() {
|
|
local temp_dir="$1"
|
|
|
|
if [ -d "$temp_dir" ]; then
|
|
if rm -rf "$temp_dir"; then
|
|
write_color "✓ Temporary files cleaned up" "$COLOR_INFO"
|
|
else
|
|
write_color "WARNING: Failed to clean temporary files" "$COLOR_WARNING"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function wait_for_user() {
|
|
local message="${1:-Press Enter to continue...}"
|
|
|
|
if [ "$NON_INTERACTIVE" != true ]; then
|
|
echo ""
|
|
write_color "$message" "$COLOR_INFO"
|
|
read -r
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
function parse_arguments() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--global)
|
|
INSTALL_GLOBAL=true
|
|
shift
|
|
;;
|
|
--directory)
|
|
INSTALL_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--force)
|
|
FORCE=true
|
|
shift
|
|
;;
|
|
--no-backup)
|
|
NO_BACKUP=true
|
|
shift
|
|
;;
|
|
--non-interactive)
|
|
NON_INTERACTIVE=true
|
|
shift
|
|
;;
|
|
--backup-all)
|
|
BACKUP_ALL=true
|
|
shift
|
|
;;
|
|
--branch)
|
|
BRANCH="$2"
|
|
shift 2
|
|
;;
|
|
--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
*)
|
|
write_color "Unknown option: $1" "$COLOR_ERROR"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
function show_help() {
|
|
cat << EOF
|
|
$SCRIPT_NAME v$VERSION
|
|
|
|
Usage: $0 [OPTIONS]
|
|
|
|
Options:
|
|
--global Install to global user directory (~/.claude)
|
|
--directory DIR Install to custom directory
|
|
--force Force installation without prompts
|
|
--no-backup Skip backup creation
|
|
--non-interactive Non-interactive mode (no prompts)
|
|
--backup-all Backup all files before installation
|
|
--branch BRANCH Specify GitHub branch (default: main)
|
|
--help Show this help message
|
|
|
|
Examples:
|
|
# Interactive installation
|
|
$0
|
|
|
|
# Global installation without prompts
|
|
$0 --global --non-interactive
|
|
|
|
# Custom directory installation
|
|
$0 --directory /opt/claude-code-workflow
|
|
|
|
EOF
|
|
}
|
|
|
|
function main() {
|
|
show_header
|
|
|
|
write_color "This will download and install Claude Code Workflow System from GitHub." "$COLOR_INFO"
|
|
echo ""
|
|
|
|
# Test prerequisites
|
|
write_color "Checking system requirements..." "$COLOR_INFO"
|
|
if ! test_prerequisites; then
|
|
wait_for_user "System check failed! Press Enter to exit..."
|
|
exit 1
|
|
fi
|
|
|
|
# Confirm installation
|
|
if [ "$NON_INTERACTIVE" != true ] && [ "$FORCE" != true ]; then
|
|
echo ""
|
|
write_color "SECURITY NOTE:" "$COLOR_WARNING"
|
|
echo "- This script will download and execute Claude Code Workflow from GitHub"
|
|
echo "- Repository: https://github.com/catlog22/Claude-Code-Workflow"
|
|
echo "- Branch: $BRANCH (latest stable version)"
|
|
echo "- Features: Intelligent workflow orchestration with multi-agent coordination"
|
|
echo "- Please ensure you trust this source"
|
|
echo ""
|
|
|
|
read -p "Continue with installation? (y/N) " -r choice
|
|
if [[ ! $choice =~ ^[Yy]$ ]]; then
|
|
write_color "Installation cancelled" "$COLOR_WARNING"
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Create temp directory
|
|
local temp_dir
|
|
temp_dir=$(get_temp_directory)
|
|
write_color "Temporary directory: $temp_dir" "$COLOR_INFO"
|
|
|
|
local success=false
|
|
|
|
# Download repository
|
|
local zip_path
|
|
if zip_path=$(download_repository "$temp_dir" "$BRANCH"); then
|
|
# Extract repository
|
|
local repo_dir
|
|
if repo_dir=$(extract_repository "$zip_path" "$temp_dir"); then
|
|
# Run local installer
|
|
if invoke_local_installer "$repo_dir"; then
|
|
success=true
|
|
echo ""
|
|
write_color "✓ Remote installation completed successfully!" "$COLOR_SUCCESS"
|
|
else
|
|
write_color "Installation script failed" "$COLOR_ERROR"
|
|
fi
|
|
else
|
|
write_color "Extraction failed" "$COLOR_ERROR"
|
|
fi
|
|
else
|
|
write_color "Download failed" "$COLOR_ERROR"
|
|
fi
|
|
|
|
# Cleanup
|
|
cleanup_temp_files "$temp_dir"
|
|
|
|
if [ "$success" = true ]; then
|
|
echo ""
|
|
write_color "Next steps:" "$COLOR_INFO"
|
|
echo "1. Review CLAUDE.md for project-specific guidelines"
|
|
echo "2. Try /workflow commands for Agent coordination"
|
|
echo "3. Use /update-memory to manage distributed documentation"
|
|
|
|
wait_for_user "Remote installation done! Press Enter to exit..."
|
|
exit 0
|
|
else
|
|
echo ""
|
|
wait_for_user "Installation failed! Press Enter to exit..."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Parse command line arguments
|
|
parse_arguments "$@"
|
|
|
|
# Run main function
|
|
main
|