mirror of
https://github.com/aaddrick/claude-desktop-debian.git
synced 2026-05-17 00:26:21 +03:00
Test Debian build on dev-debian branch
This commit is contained in:
45
.github/workflows/test-debian-build.yml
vendored
Normal file
45
.github/workflows/test-debian-build.yml
vendored
Normal 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
196
PKGBUILD
Normal 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"
|
||||
}
|
||||
68
README.md
68
README.md
@@ -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.
|
||||
|
||||
|
||||
91
build-deb.sh
91
build-deb.sh
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user