Test Debian build on dev-debian branch

This commit is contained in:
aaddrick
2025-03-29 02:31:42 -04:00
parent 77b04f009d
commit cc57c396e0
4 changed files with 380 additions and 20 deletions

45
.github/workflows/test-debian-build.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Test Debian Build Script
on:
push:
branches: [ main, dev-debian ] # Trigger on push to main or dev-debian
paths:
- 'build-deb.sh'
- '.github/workflows/test-debian-build.yml'
workflow_dispatch: # Allows manual triggering from the Actions tab on GitHub
inputs:
branch:
description: 'Branch to run on'
required: true
default: 'dev-debian'
jobs:
build:
runs-on: ubuntu-latest # Ubuntu is Debian-based and readily available
steps:
- name: Checkout code
uses: actions/checkout@v4
# Optional: Set up a specific Node.js version if your script needs it
# - name: Set up Node.js
# uses: actions/setup-node@v4
# with:
# node-version: '18' # Example version
- name: Make build script executable
run: chmod +x ./build-deb.sh
- name: Run Debian build script
# GitHub Actions runners provide passwordless sudo
# Use --noprogressbar for cleaner logs if apt commands support it
run: sudo ./build-deb.sh
- name: Upload Debian package artifact
# This step runs even if the previous step fails, change 'always()' if needed
if: always()
uses: actions/upload-artifact@v4
with:
name: claude-desktop-debian-package
path: build/claude-desktop_*.deb # Use wildcard for version
if-no-files-found: ignore # Don't fail if the deb isn't found (e.g., build failed)

196
PKGBUILD Normal file
View File

@@ -0,0 +1,196 @@
# Maintainer: Your Name <your_email@domain.com> # Please update maintainer info
_pkgname=claude-desktop
pkgname=$_pkgname
pkgver=0.9.0 # Hardcode version - update manually for new releases
pkgrel=1
pkgdesc="Claude Desktop for Linux an AI assistant from Anthropic"
arch=('x86_64')
url="https://github.com/aaddrick/claude-desktop-debian"
license=('custom: LICENSE-MIT AND LICENSE-APACHE')
depends=('nodejs' 'npm' 'electron' 'p7zip' 'icoutils' 'imagemagick')
makedepends=('wget' 'p7zip') # p7zip needed in build()
# Use a generic name for the installer in source array
_installer_filename="Claude-Setup-x64.exe"
source=("$_installer_filename::https://storage.googleapis.com/osprey-downloads-c02f6a0d-347c-492b-a752-3e0651722e97/nest-win-x64/Claude-Setup-x64.exe"
"LICENSE-MIT::https://raw.githubusercontent.com/aaddrick/claude-desktop-debian/main/LICENSE-MIT"
"LICENSE-APACHE::https://raw.githubusercontent.com/aaddrick/claude-desktop-debian/main/LICENSE-APACHE")
sha256sums=('SKIP' # Installer checksum changes with version
'SKIP' # MIT License
'SKIP') # Apache License
build() {
cd "$srcdir"
# Use the downloaded installer filename
local _installer_file="$srcdir/$_installer_filename"
mkdir -p build
cd build
echo "Extracting Windows installer..."
7z x -y "$_installer_file" || { echo "Extraction failed"; exit 1; }
# The installer contains a .nupkg file named using the version
echo "Extracting nupkg for version ${pkgver}..."
# Find the nupkg file using the hardcoded pkgver
local _nupkg_path="./AnthropicClaude-${pkgver}-full.nupkg"
if [ ! -f "$_nupkg_path" ]; then
echo "❌ Could not find nupkg file for version ${pkgver}: $_nupkg_path"
# List files to help debug if needed
ls -la
exit 1
fi
echo "✓ Using nupkg: $_nupkg_path"
7z x -y "$_nupkg_path" || { echo "nupkg extraction failed"; exit 1; }
echo "Processing icons..."
# Extract icons from the exe (wrestool and icotool come from icoutils)
wrestool -x -t 14 "lib/net45/claude.exe" -o claude.ico || { echo "wrestool failed"; exit 1; }
icotool -x claude.ico || { echo "icotool failed"; exit 1; }
echo "Preparing Electron app..."
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
# Extract the asar package to allow modifications
npx asar extract app.asar app.asar.contents || { echo "asar extract failed"; exit 1; }
echo "Creating stub native module..."
mkdir -p app.asar.contents/node_modules/claude-native
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
echo "Copying tray and i18n resources..."
mkdir -p app.asar.contents/resources
cp ../lib/net45/resources/Tray* app.asar.contents/resources/
# Copy i18n files
mkdir -p app.asar.contents/resources/i18n
cp ../lib/net45/resources/*-*.json app.asar.contents/resources/i18n/
echo "Repacking asar..."
npx asar pack app.asar.contents app.asar || { echo "asar pack failed"; exit 1; }
# Return to the build directory root
cd "$srcdir/build"
}
package() {
cd "$srcdir/build"
echo "Installing files..."
# Create installation directories
install -d "$pkgdir/usr/lib/$_pkgname"
install -d "$pkgdir/usr/share/applications"
install -d "$pkgdir/usr/share/icons/hicolor"
install -d "$pkgdir/usr/bin"
# Install the Electron app (app.asar and its unpacked resources)
cp electron-app/app.asar "$pkgdir/usr/lib/$_pkgname/"
cp -r electron-app/app.asar.unpacked "$pkgdir/usr/lib/$_pkgname/"
echo "Installing icons..."
# Map icon sizes to the extracted filenames
for size in 16 24 32 48 64 256; do
icon_file=""
case "$size" in
16) icon_file="claude_13_16x16x32.png" ;;
24) icon_file="claude_11_24x24x32.png" ;;
32) icon_file="claude_10_32x32x32.png" ;;
48) icon_file="claude_8_48x48x32.png" ;;
64) icon_file="claude_7_64x64x32.png" ;;
256) icon_file="claude_6_256x256x32.png" ;;
esac
if [ -f "$srcdir/build/$icon_file" ]; then
install -Dm644 "$srcdir/build/$icon_file" "$pkgdir/usr/share/icons/hicolor/${size}x${size}/apps/${_pkgname}.png"
else
echo "Warning: Missing ${size}x${size} icon"
fi
done
echo "Creating desktop entry..."
cat > "$pkgdir/usr/share/applications/${_pkgname}.desktop" << EOF
[Desktop Entry]
Name=Claude
Exec=$_pkgname %u
Icon=$_pkgname
Type=Application
Terminal=false
Categories=Office;Utility;
MimeType=x-scheme-handler/claude;
StartupWMClass=Claude
EOF
echo "Creating launcher script..."
# Add Wayland flags similar to the debian script
cat > "$pkgdir/usr/bin/$_pkgname" << EOF
#!/bin/bash
# Detect if Wayland is likely running
IS_WAYLAND=false
if [ ! -z "\$WAYLAND_DISPLAY" ]; then
IS_WAYLAND=true
fi
# Base command arguments
ELECTRON_ARGS=("/usr/lib/$_pkgname/app.asar")
# Add Wayland flags if Wayland is detected
if [ "\$IS_WAYLAND" = true ]; then
echo "Wayland detected, adding Wayland flags to Electron..."
ELECTRON_ARGS+=("--enable-features=UseOzonePlatform,WaylandWindowDecorations" "--ozone-platform=wayland")
fi
# Append any arguments passed to the script
ELECTRON_ARGS+=("\$@")
# Execute electron with arguments
electron "\${ELECTRON_ARGS[@]}"
EOF
chmod +x "$pkgdir/usr/bin/$_pkgname"
# Install license files fetched by makepkg
install -Dm644 "$srcdir/LICENSE-MIT" "$pkgdir/usr/share/licenses/$pkgname/LICENSE-MIT"
install -Dm644 "$srcdir/LICENSE-APACHE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE-APACHE"
}

View File

@@ -1,5 +1,4 @@
## LOOKING FOR NEW MAINTAINER
I've had fun with this, but I'm ready to pass the torch. Let me know if you'd like to take a swing at this!
Now with Arch(PKGBUILD) support!
***THIS IS AN UNOFFICIAL BUILD SCRIPT!***
@@ -34,7 +33,9 @@ cd claude-desktop-debian
# Build the package
sudo ./build-deb.sh
sudo dpkg -i ./build/claude-desktop_0.8.1_amd64.deb
# Note: The version number (e.g., 0.8.1) in the command below is an example.
# The actual filename will contain the version detected by the script.
sudo dpkg -i ./build/claude-desktop_VERSION_amd64.deb
# The script will automatically:
# - Check for and install required dependencies
@@ -48,7 +49,66 @@ Requirements:
- Node.js >= 12.0.0 and npm
- Root/sudo access for dependency installation
## 2. NixOS Implementation
## 2. Arch Linux (PKGBUILD)
For Arch Linux and Arch-based distributions, you can build and install using the provided `PKGBUILD`:
```bash
# Clone this repository
git clone https://github.com/aaddrick/claude-desktop-debian.git
cd claude-desktop-debian
# Build and install the package
# This command automatically handles dependencies and installation
makepkg -si
# The PKGBUILD will:
# - Check for and install required dependencies (nodejs, npm, electron, p7zip, icoutils, imagemagick)
# - Download and extract resources from the Windows version
# - Create an Arch Linux package
```
**Note:** The `pkgver` in the `PKGBUILD` is currently hardcoded (`0.9.0`). You may need to update it manually if a newer version of Claude Desktop is released before the `PKGBUILD` is updated in this repository.
## Uninstallation
If you installed the package using `dpkg`, you can uninstall it using:
```bash
sudo dpkg -r claude-desktop
```
If you also want to remove configuration files (including MCP settings), use `purge`:
```bash
sudo dpkg -P claude-desktop
```
## Troubleshooting
### Application Fails to Launch
If the Claude Desktop application installs successfully but fails to launch (you might see errors related to sandboxing or zygote processes in the terminal when running `claude-desktop`), try launching it with the `--no-sandbox` flag:
```bash
claude-desktop --no-sandbox
```
If this works, you can make it permanent by editing the launcher script:
1. Open `/usr/bin/claude-desktop` with root privileges (e.g., `sudo nano /usr/bin/claude-desktop`).
2. Find the line starting with `electron` or `$(dirname $0)/../lib/claude-desktop/node_modules/.bin/electron`.
3. Append `--no-sandbox` to that line, before the `"$@"` part. For example:
```bash
# Original:
# electron /usr/lib/claude-desktop/app.asar "$@"
# Modified:
electron /usr/lib/claude-desktop/app.asar --no-sandbox "$@"
```
4. Save the file.
**Note:** Disabling the sandbox reduces security isolation. Use this workaround if you understand the implications.
## 3. NixOS Implementation
For NixOS users, please refer to [k3d3's claude-desktop-linux-flake](https://github.com/k3d3/claude-desktop-linux-flake) repository. Their implementation is specifically designed for NixOS and provides the original Nix flake that inspired this project.

View File

@@ -11,11 +11,43 @@ if [ ! -f "/etc/debian_version" ]; then
fi
# Check for root/sudo
if [ "$EUID" -ne 0 ]; then
IS_SUDO=false
if [ "$EUID" -eq 0 ]; then
IS_SUDO=true
# Check if running via sudo (and not directly as root)
if [ -n "$SUDO_USER" ]; then
ORIGINAL_USER="$SUDO_USER"
ORIGINAL_HOME=$(eval echo ~$ORIGINAL_USER)
else
# Running directly as root, no original user context
ORIGINAL_USER="root"
ORIGINAL_HOME="/root"
fi
else
echo "Please run with sudo to install dependencies"
exit 1
fi
# Preserve NVM path if running under sudo and NVM exists for the original user
if [ "$IS_SUDO" = true ] && [ "$ORIGINAL_USER" != "root" ] && [ -d "$ORIGINAL_HOME/.nvm" ]; then
echo "Found NVM installation for user $ORIGINAL_USER, attempting to preserve npm/npx path..."
# Source NVM script to set up NVM environment variables temporarily
export NVM_DIR="$ORIGINAL_HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
# Find the path to the currently active or default Node version's bin directory
# nvm_find_node_version might not be available, try finding the latest installed version
NODE_BIN_PATH=$(find "$NVM_DIR/versions/node" -maxdepth 2 -type d -name 'bin' | sort -V | tail -n 1)
if [ -n "$NODE_BIN_PATH" ] && [ -d "$NODE_BIN_PATH" ]; then
echo "Adding $NODE_BIN_PATH to PATH"
export PATH="$NODE_BIN_PATH:$PATH"
else
echo "Warning: Could not determine NVM Node bin path. npm/npx might not be found."
fi
fi
# Print system information
echo "System Information:"
echo "Distribution: $(cat /etc/os-release | grep "PRETTY_NAME" | cut -d'"' -f2)"
@@ -88,20 +120,34 @@ elif ! check_command "electron"; then
export PATH="$(pwd)/node_modules/.bin:$PATH"
else
# Fall back to global installation if local fails
echo "Local electron install failed or not possible, trying global..."
npm install -g electron
# Attempt to fix permissions if installed globally
if check_command "electron"; then
ELECTRON_PATH=$(command -v electron)
echo "Attempting to fix permissions for global electron at $ELECTRON_PATH..."
chmod -R a+rx "$(dirname "$ELECTRON_PATH")/../lib/node_modules/electron" || echo "Warning: Failed to chmod global electron installation directory. Permissions might be incorrect."
fi
if ! check_command "electron"; then
echo "Failed to install electron. Please install it manually:"
echo "npm install --save-dev electron"
echo "Failed to install electron globally. Please install it manually:"
echo "npm install -g electron # or npm install --save-dev electron in project root"
exit 1
fi
echo "Global electron installed successfully"
fi
else
# No package.json, try global installation
echo "No package.json found, trying global electron installation..."
npm install -g electron
# Attempt to fix permissions if installed globally
if check_command "electron"; then
ELECTRON_PATH=$(command -v electron)
echo "Attempting to fix permissions for global electron at $ELECTRON_PATH..."
chmod -R a+rx "$(dirname "$ELECTRON_PATH")/../lib/node_modules/electron" || echo "Warning: Failed to chmod global electron installation directory. Permissions might be incorrect."
fi
if ! check_command "electron"; then
echo "Failed to install electron. Please install it manually:"
echo "npm install --save-dev electron"
echo "Failed to install electron globally. Please install it manually:"
echo "npm install -g electron"
exit 1
fi
echo "Global electron installed successfully"
@@ -156,10 +202,10 @@ if [ -z "$NUPKG_PATH" ]; then
exit 1
fi
# Extract version from the nupkg filename
VERSION=$(echo "$NUPKG_PATH" | grep -oP 'AnthropicClaude-\K[0-9]+\.[0-9]+\.[0-9]+(?=-full)')
# Extract version from the nupkg filename (using LC_ALL=C for locale compatibility)
VERSION=$(echo "$NUPKG_PATH" | LC_ALL=C grep -oP 'AnthropicClaude-\K[0-9]+\.[0-9]+\.[0-9]+(?=-full)')
if [ -z "$VERSION" ]; then
echo "❌ Could not extract version from nupkg filename"
echo "❌ Could not extract version from nupkg filename: $NUPKG_PATH"
exit 1
fi
echo "✓ Detected Claude version: $VERSION"
@@ -262,13 +308,9 @@ mkdir -p app.asar.contents/resources
mkdir -p app.asar.contents/resources/i18n
cp ../lib/net45/resources/Tray* app.asar.contents/resources/
# Copy only the language-specific JSON files (e.g., en-US.json)
cp ../lib/net45/resources/*-*.json app.asar.contents/resources/i18n/
# Copy i18n json files
mkdir -p app.asar.contents/resources/i18n
cp ../lib/net45/resources/*.json app.asar.contents/resources/i18n/
# Repackage app.asar
npx asar pack app.asar.contents app.asar
@@ -340,16 +382,33 @@ MimeType=x-scheme-handler/claude;
StartupWMClass=Claude
EOF
# Create launcher script
# Create launcher script with Wayland flags
cat > "$INSTALL_DIR/bin/claude-desktop" << EOF
#!/bin/bash
# Detect if Wayland is likely running
IS_WAYLAND=false
if [ ! -z "\$WAYLAND_DISPLAY" ]; then
IS_WAYLAND=true
fi
# Base command arguments
ELECTRON_ARGS=("/usr/lib/claude-desktop/app.asar")
# Add Wayland flags if Wayland is detected
if [ "\$IS_WAYLAND" = true ]; then
echo "Wayland detected, adding Wayland flags to Electron..."
ELECTRON_ARGS+=("--enable-features=UseOzonePlatform,WaylandWindowDecorations" "--ozone-platform=wayland")
fi
# Append any arguments passed to the script
ELECTRON_ARGS+=("\$@")
# Try to use local electron if available
if [ -f "\$(dirname \$0)/../lib/claude-desktop/node_modules/.bin/electron" ]; then
"\$(dirname \$0)/../lib/claude-desktop/node_modules/.bin/electron" /usr/lib/claude-desktop/app.asar "\$@"
"\$(dirname \$0)/../lib/claude-desktop/node_modules/.bin/electron" "\${ELECTRON_ARGS[@]}"
else
# Fall back to globally installed electron
electron /usr/lib/claude-desktop/app.asar "\$@"
electron "\${ELECTRON_ARGS[@]}"
fi
EOF
chmod +x "$INSTALL_DIR/bin/claude-desktop"