Files
claude-desktop-debian/build-deb.sh
aaddrick d8f4bbebbc Initial commit: Claude Desktop for Debian-based Linux distributions
- Build script for creating Debian package
- Linux-compatible native module implementation
- Based on insights from k3d3's claude-desktop-linux-flake
2024-12-26 11:08:01 -05:00

326 lines
8.4 KiB
Bash
Executable File

#!/bin/bash
set -e
# Update this URL when a new version of Claude Desktop is released
CLAUDE_DOWNLOAD_URL="https://storage.googleapis.com/osprey-downloads-c02f6a0d-347c-492b-a752-3e0651722e97/nest-win-x64/Claude-Setup-x64.exe"
# Check for Debian-based system
if [ ! -f "/etc/debian_version" ]; then
echo "❌ This script requires a Debian-based Linux distribution"
exit 1
fi
# Check for root/sudo
if [ "$EUID" -ne 0 ]; then
echo "Please run with sudo to install dependencies"
exit 1
fi
# Print system information
echo "System Information:"
echo "Distribution: $(cat /etc/os-release | grep "PRETTY_NAME" | cut -d'"' -f2)"
echo "Debian version: $(cat /etc/debian_version)"
# Function to check if a command exists
check_command() {
if ! command -v "$1" &> /dev/null; then
echo "$1 not found"
return 1
else
echo "$1 found"
return 0
fi
}
# Check and install dependencies
echo "Checking dependencies..."
DEPS_TO_INSTALL=""
# Check system package dependencies
for cmd in p7zip wget wrestool icotool convert npx dpkg-deb; do
if ! check_command "$cmd"; then
case "$cmd" in
"p7zip")
DEPS_TO_INSTALL="$DEPS_TO_INSTALL p7zip-full"
;;
"wget")
DEPS_TO_INSTALL="$DEPS_TO_INSTALL wget"
;;
"wrestool"|"icotool")
DEPS_TO_INSTALL="$DEPS_TO_INSTALL icoutils"
;;
"convert")
DEPS_TO_INSTALL="$DEPS_TO_INSTALL imagemagick"
;;
"npx")
DEPS_TO_INSTALL="$DEPS_TO_INSTALL nodejs npm"
;;
"dpkg-deb")
DEPS_TO_INSTALL="$DEPS_TO_INSTALL dpkg-dev"
;;
esac
fi
done
# Install system dependencies if any
if [ ! -z "$DEPS_TO_INSTALL" ]; then
echo "Installing system dependencies: $DEPS_TO_INSTALL"
apt update
apt install -y $DEPS_TO_INSTALL
echo "System dependencies installed successfully"
fi
# Install electron globally via npm if not present
if ! check_command "electron"; then
echo "Installing electron via npm..."
npm install -g electron
if ! check_command "electron"; then
echo "Failed to install electron. Please install it manually:"
echo "sudo npm install -g electron"
exit 1
fi
echo "Electron installed successfully"
fi
# Extract version from the installer filename
VERSION=$(basename "$CLAUDE_DOWNLOAD_URL" | grep -oP 'Claude-Setup-x64\.exe' | sed 's/Claude-Setup-x64\.exe/0.7.7/')
PACKAGE_NAME="claude-desktop"
ARCHITECTURE="amd64"
MAINTAINER="Claude Desktop Linux Maintainers"
DESCRIPTION="Claude Desktop for Linux"
# Create working directories
WORK_DIR="$(pwd)/build"
DEB_ROOT="$WORK_DIR/deb-package"
INSTALL_DIR="$DEB_ROOT/usr"
# Clean previous build
rm -rf "$WORK_DIR"
mkdir -p "$WORK_DIR"
mkdir -p "$DEB_ROOT/DEBIAN"
mkdir -p "$INSTALL_DIR/lib/$PACKAGE_NAME"
mkdir -p "$INSTALL_DIR/share/applications"
mkdir -p "$INSTALL_DIR/share/icons"
mkdir -p "$INSTALL_DIR/bin"
# Install asar if needed
if ! npm list -g asar > /dev/null 2>&1; then
echo "Installing asar package globally..."
npm install -g asar
fi
# Download Claude Windows installer
echo "📥 Downloading Claude Desktop installer..."
CLAUDE_EXE="$WORK_DIR/Claude-Setup-x64.exe"
if ! wget -O "$CLAUDE_EXE" "$CLAUDE_DOWNLOAD_URL"; then
echo "❌ Failed to download Claude Desktop installer"
exit 1
fi
echo "✓ Download complete"
# Extract resources
echo "📦 Extracting resources..."
cd "$WORK_DIR"
if ! 7z x -y "$CLAUDE_EXE"; then
echo "❌ Failed to extract installer"
exit 1
fi
if ! 7z x -y "AnthropicClaude-$VERSION-full.nupkg"; then
echo "❌ Failed to extract nupkg"
exit 1
fi
echo "✓ Resources extracted"
# Extract and convert icons
echo "🎨 Processing icons..."
if ! wrestool -x -t 14 "lib/net45/claude.exe" -o claude.ico; then
echo "❌ Failed to extract icons from exe"
exit 1
fi
if ! icotool -x claude.ico; then
echo "❌ Failed to convert icons"
exit 1
fi
echo "✓ Icons processed"
# Map icon sizes to their corresponding extracted files
declare -A icon_files=(
["16"]="claude_13_16x16x32.png"
["24"]="claude_11_24x24x32.png"
["32"]="claude_10_32x32x32.png"
["48"]="claude_8_48x48x32.png"
["64"]="claude_7_64x64x32.png"
["256"]="claude_6_256x256x32.png"
)
# Install icons
for size in 16 24 32 48 64 256; do
icon_dir="$INSTALL_DIR/share/icons/hicolor/${size}x${size}/apps"
mkdir -p "$icon_dir"
if [ -f "${icon_files[$size]}" ]; then
echo "Installing ${size}x${size} icon..."
install -Dm 644 "${icon_files[$size]}" "$icon_dir/claude-desktop.png"
else
echo "Warning: Missing ${size}x${size} icon"
fi
done
# Process app.asar
mkdir -p electron-app
cp "lib/net45/resources/app.asar" electron-app/
cp -r "lib/net45/resources/app.asar.unpacked" electron-app/
cd electron-app
npx asar extract app.asar app.asar.contents
# Replace native module with stub implementation
echo "Creating stub native module..."
cat > app.asar.contents/node_modules/claude-native/index.js << EOF
// Stub implementation of claude-native using KeyboardKey enum values
const KeyboardKey = {
Backspace: 43,
Tab: 280,
Enter: 261,
Shift: 272,
Control: 61,
Alt: 40,
CapsLock: 56,
Escape: 85,
Space: 276,
PageUp: 251,
PageDown: 250,
End: 83,
Home: 154,
LeftArrow: 175,
UpArrow: 282,
RightArrow: 262,
DownArrow: 81,
Delete: 79,
Meta: 187
};
Object.freeze(KeyboardKey);
module.exports = {
getWindowsVersion: () => "10.0.0",
setWindowEffect: () => {},
removeWindowEffect: () => {},
getIsMaximized: () => false,
flashFrame: () => {},
clearFlashFrame: () => {},
showNotification: () => {},
setProgressBar: () => {},
clearProgressBar: () => {},
setOverlayIcon: () => {},
clearOverlayIcon: () => {},
KeyboardKey
};
EOF
# Copy Tray icons
mkdir -p app.asar.contents/resources
cp ../lib/net45/resources/Tray* app.asar.contents/resources/
# Repackage app.asar
npx asar pack app.asar.contents app.asar
# Create native module with keyboard constants
mkdir -p "$INSTALL_DIR/lib/$PACKAGE_NAME/app.asar.unpacked/node_modules/claude-native"
cat > "$INSTALL_DIR/lib/$PACKAGE_NAME/app.asar.unpacked/node_modules/claude-native/index.js" << EOF
// Stub implementation of claude-native using KeyboardKey enum values
const KeyboardKey = {
Backspace: 43,
Tab: 280,
Enter: 261,
Shift: 272,
Control: 61,
Alt: 40,
CapsLock: 56,
Escape: 85,
Space: 276,
PageUp: 251,
PageDown: 250,
End: 83,
Home: 154,
LeftArrow: 175,
UpArrow: 282,
RightArrow: 262,
DownArrow: 81,
Delete: 79,
Meta: 187
};
Object.freeze(KeyboardKey);
module.exports = {
getWindowsVersion: () => "10.0.0",
setWindowEffect: () => {},
removeWindowEffect: () => {},
getIsMaximized: () => false,
flashFrame: () => {},
clearFlashFrame: () => {},
showNotification: () => {},
setProgressBar: () => {},
clearProgressBar: () => {},
setOverlayIcon: () => {},
clearOverlayIcon: () => {},
KeyboardKey
};
EOF
# Copy app files
cp app.asar "$INSTALL_DIR/lib/$PACKAGE_NAME/"
cp -r app.asar.unpacked "$INSTALL_DIR/lib/$PACKAGE_NAME/"
# Create desktop entry
cat > "$INSTALL_DIR/share/applications/claude-desktop.desktop" << EOF
[Desktop Entry]
Name=Claude
Exec=claude-desktop %u
Icon=claude-desktop
Type=Application
Terminal=false
Categories=Office;Utility;
MimeType=x-scheme-handler/claude;
EOF
# Create launcher script
cat > "$INSTALL_DIR/bin/claude-desktop" << EOF
#!/bin/bash
electron /usr/lib/claude-desktop/app.asar "\$@"
EOF
chmod +x "$INSTALL_DIR/bin/claude-desktop"
# Create control file
cat > "$DEB_ROOT/DEBIAN/control" << EOF
Package: claude-desktop
Version: $VERSION
Architecture: $ARCHITECTURE
Maintainer: $MAINTAINER
Depends: nodejs, npm, p7zip-full
Description: $DESCRIPTION
Claude is an AI assistant from Anthropic.
This package provides the desktop interface for Claude.
.
Supported on Debian-based Linux distributions (Debian, Ubuntu, Linux Mint, MX Linux, etc.)
Requires: nodejs (>= 12.0.0), npm
EOF
# Build .deb package
echo "📦 Building .deb package..."
DEB_FILE="$(pwd)/claude-desktop_${VERSION}_${ARCHITECTURE}.deb"
if ! dpkg-deb --build "$DEB_ROOT" "$DEB_FILE"; then
echo "❌ Failed to build .deb package"
exit 1
fi
if [ -f "$DEB_FILE" ]; then
echo "✓ Package built successfully at: $DEB_FILE"
echo "🎉 Done! You can now install the package with: sudo dpkg -i $DEB_FILE"
else
echo "❌ Package file not found at expected location: $DEB_FILE"
exit 1
fi