#!/bin/bash # VS Code Sandbox - macOS Version for Apple Silicon # Complete VS Code isolation solution for macOS with global installation and self-update # # Author: Mamun Hoque # Repository: https://github.com/MamunHoque/VSCodeSandbox # Version: 3.0.0-macos # Platform: macOS (Apple Silicon M4 optimized) set -euo pipefail # Script metadata SCRIPT_VERSION="3.0.0-macos" SCRIPT_NAME="vscode-sandbox-macos" REPOSITORY_URL="https://github.com/MamunHoque/VSCodeSandbox" REPOSITORY_RAW_URL="https://raw.githubusercontent.com/MamunHoque/VSCodeSandbox/main" INSTALL_PATH="/usr/local/bin/$SCRIPT_NAME" # Configuration ISOLATION_ROOT="${VSCODE_ISOLATION_ROOT:-$HOME/.vscode-isolated}" PROFILE_NAME="${1:-}" COMMAND="${2:-create}" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' WHITE='\033[1;37m' NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${BLUE}โ„น${NC} $1"; } log_success() { echo -e "${GREEN}โœ…${NC} $1"; } log_warning() { echo -e "${YELLOW}โš ${NC} $1"; } log_error() { echo -e "${RED}โŒ${NC} $1"; } log_header() { echo -e "${PURPLE}๐Ÿš€${NC} $1"; } log_step() { echo -e "${CYAN}โ–ถ${NC} $1"; } # Show banner show_banner() { echo -e "${CYAN}" cat << 'EOF' โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ•‘ VS Code Sandbox v3.0 - macOS โ•‘ โ•‘ Complete VS Code Isolation Solution โ•‘ โ•‘ Apple Silicon M4 Optimized โ•‘ โ•‘ โ•‘ โ•‘ ๐Ÿ”’ Complete Isolation ๐Ÿ  Fresh macOS Environment โ•‘ โ•‘ ๐Ÿšซ Zero Interference ๐Ÿ”„ Multiple Profiles โ•‘ โ•‘ ๐Ÿ—‚๏ธ Advanced Management ๐Ÿงช Well Tested โ•‘ โ•‘ ๐ŸŒ Global Installation ๐Ÿ”„ Self-Updating โ•‘ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• EOF echo -e "${NC}" } # Show usage information show_usage() { echo -e "${WHITE}USAGE:${NC}" echo -e " $SCRIPT_NAME [command] [options]" echo -e " $SCRIPT_NAME [global-command] [options]" echo echo -e "${WHITE}PROFILE COMMANDS:${NC}" echo -e " ${CYAN}create${NC} - Create and launch isolated VS Code profile (default)" echo -e " ${CYAN}launch${NC} - Launch existing profile" echo -e " ${CYAN}remove${NC} - Remove profile completely" echo -e " ${CYAN}status${NC} - Show profile status and information" echo -e " ${CYAN}scaffold${NC} - Create project template within profile" echo -e " ${CYAN}uri-status${NC} - Show vscode:// URI handler status for profile" echo echo -e "${WHITE}GLOBAL COMMANDS:${NC}" echo -e " ${CYAN}list${NC} - List all isolated profiles" echo -e " ${CYAN}clean${NC} - Remove all profiles and projects" echo -e " ${CYAN}uninstall${NC} - Completely remove VS Code Sandbox from system" echo -e " ${CYAN}--help, -h${NC} - Show this help message" echo -e " ${CYAN}--version, -v${NC} - Show version information" echo -e " ${CYAN}--update${NC} - Update to the latest version" echo -e " ${CYAN}--install${NC} - Install globally to /usr/local/bin" echo echo -e "${WHITE}SCAFFOLD OPTIONS:${NC}" echo -e " ${CYAN}--type ${NC} - Project type (react, node, python, go, static)" echo -e " ${CYAN}--git${NC} - Initialize Git repository" echo -e " ${CYAN}--vscode${NC} - Add VS Code configuration" echo -e " ${CYAN}--docker${NC} - Add Docker configuration" echo echo -e "${WHITE}ISOLATION OPTIONS:${NC}" echo -e " ${CYAN}--isolated${NC} - Enable enhanced isolation (default)" echo -e " ${CYAN}--no-extensions${NC} - Skip automatic extension installation" echo echo -e "${WHITE}URI SUPPORT:${NC}" echo -e " ${CYAN}vscode://file/path${NC} - Open specific file" echo -e " ${CYAN}vscode://folder/path${NC} - Open specific folder" echo -e " ${CYAN}vscode://extension/id${NC} - Install/open extension" echo -e " ${CYAN}vscode://augment.vscode-augment/...${NC} - Augment extension URIs (auth, etc.)" echo -e " ${CYAN}vscode-://file/path${NC} - Profile-specific file URI" echo -e " ${CYAN}file:///path/to/file${NC} - Local file URI" echo -e " ${CYAN}--open-url=vscode://...${NC} - Explicit URI parameter" echo echo -e "${WHITE}EXAMPLES:${NC}" echo -e " # Create isolated VS Code profile" echo -e " $SCRIPT_NAME myproject create" echo echo -e " # Create project within isolated profile" echo -e " $SCRIPT_NAME myproject scaffold --type react --git --vscode" echo echo -e " # Launch existing profile" echo -e " $SCRIPT_NAME myproject launch" echo echo -e " # Check URI handler status" echo -e " $SCRIPT_NAME myproject uri-status" echo echo -e " # List all profiles" echo -e " $SCRIPT_NAME list" echo echo -e "${WHITE}ENVIRONMENT VARIABLES:${NC}" echo -e " ${CYAN}VSCODE_ISOLATION_ROOT${NC} - Root directory for profiles (default: ~/.vscode-isolated)" echo -e " ${CYAN}VSCODE_BINARY${NC} - Path to VS Code binary (default: auto-detect)" echo echo -e "${WHITE}REPOSITORY:${NC} $REPOSITORY_URL" echo -e "${WHITE}PLATFORM:${NC} macOS (Apple Silicon M4 Optimized)" } # Show version information show_version() { echo -e "${WHITE}VS Code Sandbox${NC} version ${GREEN}$SCRIPT_VERSION${NC}" echo -e "Platform: ${BLUE}macOS (Apple Silicon M4)${NC}" echo -e "Repository: ${BLUE}$REPOSITORY_URL${NC}" echo -e "Installation: ${CYAN}$INSTALL_PATH${NC}" echo -e "Isolation Root: ${CYAN}$ISOLATION_ROOT${NC}" } # Check if command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Detect VS Code binary on macOS detect_vscode_binary() { local candidates=( "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" "$HOME/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" "/usr/local/bin/code" "/opt/homebrew/bin/code" "$(which code 2>/dev/null || true)" ) for candidate in "${candidates[@]}"; do if [[ -x "$candidate" ]]; then echo "$candidate" return 0 fi done log_error "VS Code binary not found. Please install VS Code or set VSCODE_BINARY environment variable." log_info "Download VS Code from: https://code.visualstudio.com/download" exit 1 } VSCODE_BINARY="${VSCODE_BINARY:-$(detect_vscode_binary)}" # Check macOS version and architecture check_macos_compatibility() { if [[ "$(uname)" != "Darwin" ]]; then log_error "This script is designed for macOS only" log_info "For Linux, use the main vscode-sandbox script" exit 1 fi local macos_version=$(sw_vers -productVersion) local arch=$(uname -m) log_info "macOS Version: $macos_version" log_info "Architecture: $arch" if [[ "$arch" == "arm64" ]]; then log_success "Apple Silicon detected - optimized for M4 performance" else log_warning "Intel Mac detected - script will work but is optimized for Apple Silicon" fi } # Profile paths get_profile_paths() { PROFILE_ROOT="$ISOLATION_ROOT/profiles/$PROFILE_NAME" PROFILE_CONFIG="$PROFILE_ROOT/config" PROFILE_EXTENSIONS="$PROFILE_ROOT/extensions" PROFILE_PROJECTS="$PROFILE_ROOT/projects" LAUNCHER_SCRIPT="$ISOLATION_ROOT/launchers/$PROFILE_NAME-launcher.sh" # macOS specific paths PROFILE_LIBRARY="$PROFILE_ROOT/Library" PROFILE_APP_SUPPORT="$PROFILE_LIBRARY/Application Support" PROFILE_CACHES="$PROFILE_LIBRARY/Caches" PROFILE_PREFERENCES="$PROFILE_LIBRARY/Preferences" } # Self-update functionality self_update() { log_header "Updating VS Code Sandbox for macOS" # Check if we have write permissions if [[ ! -w "$INSTALL_PATH" ]] && [[ -f "$INSTALL_PATH" ]]; then log_error "No write permission to $INSTALL_PATH" log_info "Try running with sudo: sudo $SCRIPT_NAME --update" exit 1 fi # Create temporary file local temp_file=$(mktemp) # Download latest version log_step "Downloading latest macOS version..." if command_exists "curl"; then if curl -sSL "$REPOSITORY_RAW_URL/vscode-sandbox-macos" -o "$temp_file"; then log_success "Downloaded latest version" else log_error "Failed to download update" rm -f "$temp_file" exit 1 fi else log_error "curl not available for downloading" log_info "Install curl with: brew install curl" rm -f "$temp_file" exit 1 fi # Verify the downloaded file if [[ ! -s "$temp_file" ]]; then log_error "Downloaded file is empty" rm -f "$temp_file" exit 1 fi # Check if it's a valid script if ! head -1 "$temp_file" | grep -q "#!/bin/bash"; then log_error "Downloaded file is not a valid bash script" rm -f "$temp_file" exit 1 fi # Backup current version if it exists if [[ -f "$INSTALL_PATH" ]]; then log_step "Backing up current version..." cp "$INSTALL_PATH" "${INSTALL_PATH}.backup" fi # Install new version log_step "Installing new version..." if [[ -f "$INSTALL_PATH" ]]; then # Update existing installation cp "$temp_file" "$INSTALL_PATH" chmod +x "$INSTALL_PATH" else # Install to current location if not globally installed cp "$temp_file" "$0" chmod +x "$0" fi # Clean up rm -f "$temp_file" log_success "Update completed successfully!" log_info "Restart your terminal or run the command again to use the new version" } # Install globally to /usr/local/bin install_globally() { log_header "Installing VS Code Sandbox for macOS Globally" # Check if running as root or with sudo if [[ $EUID -ne 0 ]]; then log_error "Global installation requires root privileges" log_info "Run with sudo: sudo $0 --install" exit 1 fi # Create /usr/local/bin if it doesn't exist mkdir -p /usr/local/bin # Copy script to global location log_step "Installing to $INSTALL_PATH..." cp "$0" "$INSTALL_PATH" chmod +x "$INSTALL_PATH" # Verify installation if [[ -x "$INSTALL_PATH" ]]; then log_success "Successfully installed to $INSTALL_PATH" log_info "You can now run 'vscode-sandbox-macos' from anywhere" # Show version to confirm "$INSTALL_PATH" --version else log_error "Installation failed" exit 1 fi } # Create isolated directory structure for macOS create_profile_structure() { log_step "Creating isolated directory structure for profile '$PROFILE_NAME'" # Create all necessary directories for macOS isolation mkdir -p "$PROFILE_ROOT"/{config,extensions,projects} mkdir -p "$PROFILE_LIBRARY"/{Application\ Support,Caches,Preferences} mkdir -p "$ISOLATION_ROOT/launchers" # Create macOS-specific directories mkdir -p "$PROFILE_APP_SUPPORT"/{Code,com.microsoft.VSCode} mkdir -p "$PROFILE_CACHES"/{Code,com.microsoft.VSCode} mkdir -p "$PROFILE_PREFERENCES" # Create welcome file cat > "$PROFILE_PROJECTS/README.md" << EOF # Welcome to $PROFILE_NAME Profile! (macOS) This is your isolated VS Code environment on macOS. Everything here is completely separated from other profiles and your main VS Code installation. ## What's Isolated: - โœ… Extensions (installed separately for this profile) - โœ… Settings and preferences - โœ… Workspace configurations - โœ… Recently opened files - โœ… Git credentials and SSH keys - โœ… Terminal history and environment - โœ… macOS Application Support data - โœ… Cache and temporary files ## Pre-installed Extensions: - ๐Ÿค– **Augment** - AI-powered development assistant - ๐Ÿ“ **Essential Development Extensions** - EditorConfig, TypeScript, Tailwind CSS ## Profile Information: - **Profile Name**: $PROFILE_NAME - **Platform**: macOS (Apple Silicon M4 Optimized) - **Profile Root**: $PROFILE_ROOT - **Projects Directory**: $PROFILE_PROJECTS - **Created**: $(date) ## Useful Commands: \`\`\`bash # Launch this profile vscode-sandbox-macos $PROFILE_NAME launch # Create a project template vscode-sandbox-macos $PROFILE_NAME scaffold --type react --git # Remove this profile vscode-sandbox-macos $PROFILE_NAME remove # List all profiles vscode-sandbox-macos list \`\`\` Happy coding on macOS! ๐Ÿš€๐ŸŽ EOF log_success "Directory structure created" } # Register URI handlers for macOS register_uri_handlers_macos() { log_step "Registering vscode:// URI handlers for profile '$PROFILE_NAME' on macOS" # Create a simple app bundle for URI handling local app_bundle="$HOME/Applications/VSCode-$PROFILE_NAME.app" local contents_dir="$app_bundle/Contents" local macos_dir="$contents_dir/MacOS" local resources_dir="$contents_dir/Resources" mkdir -p "$macos_dir" "$resources_dir" # Create Info.plist for the app bundle cat > "$contents_dir/Info.plist" << EOF CFBundleExecutable vscode-$PROFILE_NAME CFBundleIdentifier com.vscode-sandbox.$PROFILE_NAME CFBundleName VS Code - $PROFILE_NAME CFBundleVersion 1.0 CFBundleShortVersionString 1.0 CFBundleURLTypes CFBundleURLName VS Code URL CFBundleURLSchemes vscode vscode-$PROFILE_NAME LSMinimumSystemVersion 10.15 NSHighResolutionCapable EOF # Create executable script cat > "$macos_dir/vscode-$PROFILE_NAME" << EOF #!/bin/bash # URI handler for VS Code profile: $PROFILE_NAME exec "$LAUNCHER_SCRIPT" "\$@" EOF chmod +x "$macos_dir/vscode-$PROFILE_NAME" # Register the app bundle with Launch Services if command_exists "lsregister"; then /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -f "$app_bundle" log_success "Registered URI handlers for profile '$PROFILE_NAME'" else log_warning "Could not register URI handlers automatically" log_info "You may need to manually set the default application for vscode:// URLs" fi } # Create launcher script for macOS create_launcher_script_macos() { log_step "Creating macOS launcher script with comprehensive URI support" cat > "$LAUNCHER_SCRIPT" << EOF #!/bin/bash # VS Code Launcher for isolated profile: $PROFILE_NAME (macOS) # Supports comprehensive URI handling set -euo pipefail PROFILE_NAME="$PROFILE_NAME" PROFILE_ROOT="$PROFILE_ROOT" PROFILE_CONFIG="$PROFILE_CONFIG" PROFILE_EXTENSIONS="$PROFILE_EXTENSIONS" PROFILE_PROJECTS="$PROFILE_PROJECTS" PROFILE_APP_SUPPORT="$PROFILE_APP_SUPPORT" VSCODE_BINARY="$VSCODE_BINARY" # Check if profile exists if [[ ! -d "\$PROFILE_ROOT" ]]; then echo "โŒ Profile '\$PROFILE_NAME' does not exist" echo "๐Ÿ’ก Create it first with: vscode-sandbox-macos \$PROFILE_NAME create" exit 1 fi # Parse arguments and handle various URI formats URI="" OPEN_FOLDER="" OPEN_FILE="" EXTRA_ARGS=() # Enhanced argument processing for arg in "\$@"; do case "\$arg" in vscode://*) URI="\$arg" ;; vscode-file://*) URI="\$arg" ;; vscode-$PROFILE_NAME://*) # Convert profile-specific URI to standard vscode:// URI URI="\${arg/vscode-$PROFILE_NAME:/vscode:}" ;; --open-url=*) URI="\${arg#--open-url=}" ;; --folder-uri=*) OPEN_FOLDER="\${arg#--folder-uri=}" ;; --file-uri=*) OPEN_FILE="\${arg#--file-uri=}" ;; file://*) # Handle file:// URIs by converting to local path local file_path="\${arg#file://}" if [[ -e "\$file_path" ]]; then if [[ -d "\$file_path" ]]; then OPEN_FOLDER="\$file_path" else OPEN_FILE="\$file_path" fi fi ;; --goto=*) # Handle --goto=file:line:column format URI="vscode://file\${arg#--goto=}" ;; *) # Check if it's a file or directory path if [[ -e "\$arg" && "\$arg" != --* ]]; then if [[ -d "\$arg" ]]; then OPEN_FOLDER="\$arg" else OPEN_FILE="\$arg" fi else EXTRA_ARGS+=("\$arg") fi ;; esac done # Set up macOS-specific environment variables for isolation export HOME="\$PROFILE_ROOT" export XDG_CONFIG_HOME="\$PROFILE_CONFIG" export XDG_DATA_HOME="\$PROFILE_APP_SUPPORT" export XDG_CACHE_HOME="\$PROFILE_CACHES" # Build final arguments FINAL_ARGS=( --user-data-dir="\$PROFILE_CONFIG" --extensions-dir="\$PROFILE_EXTENSIONS" --disable-gpu-sandbox --no-sandbox ) # Add URI if specified if [[ -n "\$URI" ]]; then FINAL_ARGS+=(--open-url "\$URI") fi # Add folder if specified (default to projects directory if none specified) if [[ -n "\$OPEN_FOLDER" ]]; then FINAL_ARGS+=("\$OPEN_FOLDER") elif [[ \${#EXTRA_ARGS[@]} -eq 0 && -z "\$URI" && -z "\$OPEN_FILE" ]]; then # No specific target, open projects directory FINAL_ARGS+=("\$PROFILE_PROJECTS") fi # Add file if specified if [[ -n "\$OPEN_FILE" ]]; then FINAL_ARGS+=(--goto "\$OPEN_FILE") fi # Add extra arguments FINAL_ARGS+=("\${EXTRA_ARGS[@]}") # Launch VS Code with isolated profile exec "\$VSCODE_BINARY" "\${FINAL_ARGS[@]}" EOF chmod +x "$LAUNCHER_SCRIPT" log_success "macOS launcher script created with comprehensive URI support" } # Install Augment extension for macOS install_augment_extension_macos() { log_step "Installing Augment extension for macOS..." # Create extensions directory if it doesn't exist mkdir -p "$PROFILE_EXTENSIONS" mkdir -p "$PROFILE_CONFIG" # Install Augment extension using VS Code CLI log_info "Installing Augment extension to isolated profile..." # Try different possible Augment extension IDs local augment_extensions=( "augmentcode.augment" "augment.augment" "augment-code.augment" "augment.vscode-augment" ) local augment_installed=false for ext_id in "${augment_extensions[@]}"; do if "$VSCODE_BINARY" \ --user-data-dir="$PROFILE_CONFIG" \ --extensions-dir="$PROFILE_EXTENSIONS" \ --install-extension "$ext_id" \ --force \ --disable-gpu-sandbox \ --no-sandbox \ >/dev/null 2>&1; then log_success "Augment extension installed successfully ($ext_id)" augment_installed=true break fi done if [[ "$augment_installed" != true ]]; then log_warning "Augment extension not found in marketplace with standard IDs" log_info "You can install Augment manually from the Extensions marketplace" fi # Also try to install some commonly useful extensions for development local common_extensions=( "editorconfig.editorconfig" "ms-vscode.vscode-typescript-next" "bradlc.vscode-tailwindcss" ) log_info "Installing common development extensions..." for extension in "${common_extensions[@]}"; do if "$VSCODE_BINARY" \ --user-data-dir="$PROFILE_CONFIG" \ --extensions-dir="$PROFILE_EXTENSIONS" \ --install-extension "$extension" \ --force \ --disable-gpu-sandbox \ --no-sandbox \ >/dev/null 2>&1; then log_info "โœ… Installed: $extension" else log_info "โš ๏ธ Skipped: $extension (not available or failed)" fi done log_success "Extension installation completed" } # Create VS Code settings optimized for macOS create_vscode_settings_macos() { local settings_file="$PROFILE_CONFIG/User/settings.json" # Create User directory if it doesn't exist mkdir -p "$(dirname "$settings_file")" log_step "Creating macOS-optimized VS Code settings..." cat > "$settings_file" << 'EOF' { "editor.tabSize": 2, "editor.insertSpaces": true, "editor.detectIndentation": false, "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.fixAll": true }, "files.trimTrailingWhitespace": true, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "editor.minimap.enabled": true, "editor.wordWrap": "on", "editor.lineNumbers": "on", "editor.rulers": [80, 120], "workbench.colorTheme": "Default Dark+", "workbench.iconTheme": "vs-seti", "terminal.integrated.fontSize": 14, "editor.fontSize": 14, "editor.fontFamily": "'SF Mono', 'Fira Code', 'Cascadia Code', 'JetBrains Mono', 'Source Code Pro', monospace", "editor.fontLigatures": true, "git.enableSmartCommit": true, "git.confirmSync": false, "git.autofetch": true, "extensions.autoUpdate": true, "update.mode": "start", "telemetry.telemetryLevel": "off", "workbench.startupEditor": "welcomePage", "editor.suggestSelection": "first", "editor.acceptSuggestionOnCommitCharacter": false, "editor.acceptSuggestionOnEnter": "on", "editor.quickSuggestions": { "other": true, "comments": false, "strings": false }, "editor.parameterHints.enabled": true, "editor.hover.enabled": true, "editor.lightbulb.enabled": true, "terminal.integrated.shell.osx": "/bin/zsh", "terminal.integrated.fontFamily": "'SF Mono', 'Fira Code', monospace" } EOF log_success "macOS-optimized settings created" } # Create profile function for macOS create_profile() { if [[ -d "$PROFILE_ROOT" ]]; then log_warning "Profile '$PROFILE_NAME' already exists" read -p "Do you want to recreate it? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_info "Launching existing profile instead" launch_profile return fi remove_profile_internal fi log_header "Creating isolated VS Code profile for macOS: $PROFILE_NAME" # Check macOS compatibility check_macos_compatibility create_profile_structure create_launcher_script_macos register_uri_handlers_macos create_vscode_settings_macos # Install Augment extension and common development extensions if [[ "${SKIP_EXTENSIONS:-false}" != true ]]; then install_augment_extension_macos else log_info "Skipping automatic extension installation (--no-extensions flag)" log_info "You can install Augment and other extensions manually later" fi log_success "Profile '$PROFILE_NAME' created successfully!" log_info "Launching isolated VS Code with Augment extension..." # Launch the profile "$LAUNCHER_SCRIPT" >/dev/null 2>&1 & echo log_success "๐Ÿš€ VS Code '$PROFILE_NAME' is running in complete isolation on macOS!" echo -e "${BLUE}๐ŸŽ${NC} Platform: macOS (Apple Silicon M4 Optimized)" echo -e "${BLUE}๐Ÿ“${NC} Projects directory: $PROFILE_PROJECTS" echo -e "${BLUE}๐Ÿ”ง${NC} Launcher script: $LAUNCHER_SCRIPT" echo -e "${BLUE}๐Ÿค–${NC} Augment extension pre-installed for AI assistance" echo echo -e "${GREEN}๐Ÿ’ก Tips:${NC}" echo " โ€ข Each profile is completely isolated from others" echo " โ€ข Optimized for Apple Silicon M4 performance" echo " โ€ข Augment extension is pre-installed for AI-powered development" echo " โ€ข Use 'vscode-sandbox-macos $PROFILE_NAME launch' to start this profile again" echo " โ€ข Use 'vscode-sandbox-macos $PROFILE_NAME scaffold --type react' to create projects" echo " โ€ข Use 'vscode-sandbox-macos $PROFILE_NAME remove' to completely remove this profile" echo " โ€ข Use 'vscode-sandbox-macos list' to see all profiles" } # Launch existing profile launch_profile() { if [[ ! -d "$PROFILE_ROOT" ]]; then log_error "Profile '$PROFILE_NAME' does not exist" log_info "Create it first with: vscode-sandbox-macos $PROFILE_NAME create" exit 1 fi log_info "Launching isolated VS Code profile: $PROFILE_NAME" exec "$LAUNCHER_SCRIPT" "$@" } # Remove profile completely remove_profile_internal() { if [[ -d "$PROFILE_ROOT" ]]; then log_step "Removing profile directory: $PROFILE_ROOT" rm -rf "$PROFILE_ROOT" fi if [[ -f "$LAUNCHER_SCRIPT" ]]; then log_step "Removing launcher script: $LAUNCHER_SCRIPT" rm -f "$LAUNCHER_SCRIPT" fi # Remove macOS app bundle local app_bundle="$HOME/Applications/VSCode-$PROFILE_NAME.app" if [[ -d "$app_bundle" ]]; then log_step "Removing app bundle: $app_bundle" rm -rf "$app_bundle" fi } remove_profile() { if [[ ! -d "$PROFILE_ROOT" ]]; then log_warning "Profile '$PROFILE_NAME' does not exist" return fi echo -e "${YELLOW}โš ${NC} This will completely remove the isolated VS Code profile '$PROFILE_NAME'" echo -e "${YELLOW}โš ${NC} All settings, extensions, and data will be permanently deleted" echo read -p "Are you sure you want to remove profile '$PROFILE_NAME'? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then log_info "Removing profile '$PROFILE_NAME'..." remove_profile_internal log_success "Profile '$PROFILE_NAME' removed successfully" else log_info "Profile removal cancelled" fi } # List all profiles list_profiles() { local profiles_dir="$ISOLATION_ROOT/profiles" if [[ ! -d "$profiles_dir" ]]; then log_info "No isolated VS Code profiles found" log_info "Create one with: vscode-sandbox-macos create" return fi local profiles=($(find "$profiles_dir" -maxdepth 1 -type d -not -path "$profiles_dir" -exec basename {} \; 2>/dev/null | sort)) if [[ ${#profiles[@]} -eq 0 ]]; then log_info "No isolated VS Code profiles found" log_info "Create one with: vscode-sandbox-macos create" return fi echo -e "${BLUE}๐Ÿ“‹ Isolated VS Code Profiles (macOS):${NC}" echo for profile in "${profiles[@]}"; do local profile_path="$profiles_dir/$profile" local launcher_path="$ISOLATION_ROOT/launchers/$profile-launcher.sh" local projects_path="$profile_path/projects" echo -e "${GREEN}๐Ÿ”น $profile${NC}" echo -e " ${BLUE}Path:${NC} $profile_path" if [[ -f "$launcher_path" ]]; then echo -e " ${BLUE}Launcher:${NC} โœ… Available" else echo -e " ${BLUE}Launcher:${NC} โŒ Missing" fi if [[ -d "$projects_path" ]]; then local project_count=$(find "$projects_path" -maxdepth 1 -type d | wc -l) ((project_count--)) # Subtract the parent directory echo -e " ${BLUE}Projects:${NC} $project_count" else echo -e " ${BLUE}Projects:${NC} 0" fi echo -e " ${CYAN}Launch:${NC} vscode-sandbox-macos $profile launch" echo done echo -e "${CYAN}๐Ÿ’ก Total profiles: ${#profiles[@]}${NC}" } # Show profile status show_profile_status() { if [[ ! -d "$PROFILE_ROOT" ]]; then log_error "Profile '$PROFILE_NAME' does not exist" log_info "Create it first with: vscode-sandbox-macos $PROFILE_NAME create" exit 1 fi echo -e "${BLUE}๐Ÿ“Š Profile Status: ${WHITE}$PROFILE_NAME${NC} (macOS)" echo echo -e "${GREEN}๐ŸŽ Platform Information:${NC}" echo -e " ${BLUE}Platform:${NC} macOS (Apple Silicon M4 Optimized)" echo -e " ${BLUE}Architecture:${NC} $(uname -m)" echo -e " ${BLUE}macOS Version:${NC} $(sw_vers -productVersion)" echo echo -e "${GREEN}๐Ÿ“ Profile Paths:${NC}" echo -e " ${BLUE}Profile Root:${NC} $PROFILE_ROOT" echo -e " ${BLUE}Projects:${NC} $PROFILE_PROJECTS" echo -e " ${BLUE}Config:${NC} $PROFILE_CONFIG" echo -e " ${BLUE}Extensions:${NC} $PROFILE_EXTENSIONS" echo # Extensions count local ext_count=0 if [[ -d "$PROFILE_EXTENSIONS" ]]; then ext_count=$(find "$PROFILE_EXTENSIONS" -maxdepth 1 -type d | wc -l) ((ext_count--)) # Subtract the parent directory fi # Projects count local project_count=0 if [[ -d "$PROFILE_PROJECTS" ]]; then project_count=$(find "$PROFILE_PROJECTS" -maxdepth 1 -type d | wc -l) ((project_count--)) # Subtract the parent directory fi echo -e "${GREEN}๐Ÿ“ฆ Content Summary:${NC}" echo -e " ${BLUE}Installed Extensions:${NC} $ext_count" echo -e " ${BLUE}Project Directories:${NC} $project_count" echo # Launcher status if [[ -f "$LAUNCHER_SCRIPT" ]]; then echo -e "${GREEN}๐Ÿš€ Launcher:${NC} โœ… Available" echo -e " ${BLUE}Script:${NC} $LAUNCHER_SCRIPT" echo -e " ${CYAN}Command:${NC} vscode-sandbox-macos $PROFILE_NAME launch" else echo -e "${GREEN}๐Ÿš€ Launcher:${NC} โŒ Not configured" fi echo # App bundle status local app_bundle="$HOME/Applications/VSCode-$PROFILE_NAME.app" if [[ -d "$app_bundle" ]]; then echo -e "${GREEN}๐Ÿ“ฑ App Bundle:${NC} โœ… Available" echo -e " ${BLUE}Bundle:${NC} $app_bundle" else echo -e "${GREEN}๐Ÿ“ฑ App Bundle:${NC} โŒ Not configured" fi } # Show URI handler status for macOS show_uri_status() { if [[ ! -d "$PROFILE_ROOT" ]]; then log_error "Profile '$PROFILE_NAME' does not exist" log_info "Create it first with: vscode-sandbox-macos $PROFILE_NAME create" exit 1 fi echo -e "${BLUE}๐Ÿ”— URI Handler Status: ${WHITE}$PROFILE_NAME${NC} (macOS)" echo # Check app bundle local app_bundle="$HOME/Applications/VSCode-$PROFILE_NAME.app" echo -e "${GREEN}๐Ÿ“ฑ App Bundle:${NC}" if [[ -d "$app_bundle" ]]; then echo -e " ${GREEN}โœ… Available${NC}" echo -e " ${BLUE}Bundle:${NC} $app_bundle" else echo -e " ${YELLOW}โš ๏ธ Not found${NC}" echo -e " ${CYAN}Recreate with:${NC} vscode-sandbox-macos $PROFILE_NAME create" fi echo # Check Launch Services registration echo -e "${GREEN}๐ŸŽฏ Launch Services Registration:${NC}" if command_exists "lsregister"; then if /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump | grep -q "vscode-$PROFILE_NAME" 2>/dev/null; then echo -e " ${GREEN}โœ… Registered${NC}" else echo -e " ${YELLOW}โš ๏ธ Not registered${NC}" echo -e " ${CYAN}Fix with:${NC} Re-create the profile to register URI handlers" fi else echo -e " ${YELLOW}โš ๏ธ Cannot check (lsregister not available)${NC}" fi echo # Test URI examples echo -e "${GREEN}๐Ÿงช Test URI Examples:${NC}" echo -e " ${CYAN}File:${NC} vscode://file/path/to/file.js" echo -e " ${CYAN}Folder:${NC} vscode://folder$PROFILE_PROJECTS" echo -e " ${CYAN}Extension:${NC} vscode://extension/ms-python.python" echo -e " ${CYAN}Augment Auth:${NC} vscode://augment.vscode-augment/auth/result?code=...&state=..." echo -e " ${CYAN}Profile-specific:${NC} vscode-$PROFILE_NAME://file/path/to/file.js" echo # Quick fix commands echo -e "${GREEN}๐Ÿ”ง Quick Fix Commands:${NC}" echo -e " ${CYAN}Recreate profile to fix URI handlers:${NC}" echo -e " vscode-sandbox-macos $PROFILE_NAME create" echo echo -e " ${CYAN}Test complex Augment URI:${NC}" echo -e " vscode-sandbox-macos $PROFILE_NAME launch --open-url 'vscode://augment.vscode-augment/auth/result?code=test'" } # Clean all profiles clean_all() { echo -e "${YELLOW}โš ${NC} This will remove ALL isolated VS Code profiles and data" echo -e "${YELLOW}โš ${NC} This action cannot be undone" echo read -p "Are you sure you want to remove all profiles? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then log_info "Removing all profiles and data..." if [[ -d "$ISOLATION_ROOT" ]]; then rm -rf "$ISOLATION_ROOT" log_success "All profiles removed" else log_info "No profiles found to remove" fi # Remove all app bundles if ls "$HOME/Applications/VSCode-"*.app >/dev/null 2>&1; then log_step "Removing app bundles..." rm -rf "$HOME/Applications/VSCode-"*.app log_success "App bundles removed" fi else log_info "Clean operation cancelled" fi } # Uninstall the script completely uninstall_script() { log_header "Uninstalling VS Code Sandbox for macOS" echo -e "${YELLOW}โš ${NC} This will:" echo " โ€ข Remove the globally installed script" echo " โ€ข Remove all isolated profiles and data" echo " โ€ข Remove all app bundles" echo " โ€ข Clean up URI handlers" echo read -p "Are you sure you want to completely uninstall? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then # Remove global script if [[ -f "$INSTALL_PATH" ]]; then log_step "Removing global script..." if [[ $EUID -eq 0 ]]; then rm -f "$INSTALL_PATH" else sudo rm -f "$INSTALL_PATH" fi log_success "Global script removed" fi # Remove all profiles if [[ -d "$ISOLATION_ROOT" ]]; then log_step "Removing all profiles..." rm -rf "$ISOLATION_ROOT" log_success "All profiles removed" fi # Remove app bundles if ls "$HOME/Applications/VSCode-"*.app >/dev/null 2>&1; then log_step "Removing app bundles..." rm -rf "$HOME/Applications/VSCode-"*.app log_success "App bundles removed" fi log_success "VS Code Sandbox for macOS uninstalled successfully!" echo echo -e "${CYAN}๐Ÿ’ก You can reinstall anytime with:${NC}" echo -e " curl -sSL https://raw.githubusercontent.com/MamunHoque/VSCodeSandbox/main/vscode-sandbox-macos | sudo bash -s -- --install" else log_info "Uninstall cancelled" fi } # Parse command line arguments and execute main() { # Initialize options SKIP_EXTENSIONS=false # Handle global commands first case "${1:-}" in "--help"|"-h"|"help") show_banner show_usage exit 0 ;; "--version"|"-v"|"version") show_version exit 0 ;; "--update"|"update") self_update exit 0 ;; "--install"|"install") install_globally exit 0 ;; "list") list_profiles exit 0 ;; "clean") clean_all exit 0 ;; "uninstall") uninstall_script exit 0 ;; esac # Check if profile name is provided if [[ -z "$PROFILE_NAME" ]]; then show_banner log_error "Profile name is required" echo show_usage exit 1 fi # Get profile paths get_profile_paths # Parse options shift 2 2>/dev/null || shift 1 2>/dev/null || true while [[ $# -gt 0 ]]; do case $1 in --no-extensions) SKIP_EXTENSIONS=true shift ;; *) break ;; esac done # Execute command case "$COMMAND" in "create") create_profile ;; "launch") launch_profile "$@" ;; "remove") remove_profile ;; "status") show_profile_status ;; "uri-status") show_uri_status ;; *) log_error "Unknown command: $COMMAND" echo show_usage exit 1 ;; esac } # Run main function with all arguments main "$@"