mirror of
https://github.com/aaddrick/claude-desktop-debian.git
synced 2026-05-17 08:36:35 +03:00
PR 1 of 3 for issue #559 — docs and conventions, no behaviour change. - New `docs/learnings/patching-minified-js.md` covering anchor selection, identifier capture (`\w` vs `$`), beautified false-negative trap, whitespace tolerance, replacement-string escaping, idempotency, multi-site coordination, lastIndexOf disambiguation, and the SHA-256-pinned hypothesis-verification recipe. - New `CONTRIBUTING.md` as a navigation hub: scope policy (no net-new features outside Linux-environment parity), upstream routing, subsystem owners, PR checklist, AI-assisted contribution disclosure format, and the patch-script regex intent comment + markdown wrapping conventions. - Fix CLAUDE.md:126 example regex `\w+` → `[$\w]+` (same class of bug the new learnings doc documents). - CLAUDE.md learnings index entry for the new doc. PRs 2 (`verify-cowork-patches.sh` + BATS) and 3 (silent-no-op WARNING retrofits) follow. Refs #559 Co-authored-by: Claude <claude@anthropic.com>
452 lines
20 KiB
Markdown
452 lines
20 KiB
Markdown
# Claude Desktop Debian - Development Notes
|
||
|
||
## Project Overview
|
||
|
||
This project repackages Claude Desktop (Electron app) for Debian/Ubuntu Linux, applying necessary patches for Linux compatibility.
|
||
|
||
## Learnings
|
||
|
||
The [`docs/learnings/`](docs/learnings/) directory contains hard-won technical knowledge from debugging and fixing issues — things that aren't obvious from reading the code or docs alone. Consult these before working on related areas. Add new entries when you discover something non-obvious that would save future contributors (human or AI) significant time.
|
||
|
||
- [`nix.md`](docs/learnings/nix.md) — NixOS packaging, Electron resource path resolution, testing without NixOS
|
||
- [`cowork-vm-daemon.md`](docs/learnings/cowork-vm-daemon.md) — Cowork VM daemon lifecycle, respawn logic, crash diagnosis
|
||
- [`plugin-install.md`](docs/learnings/plugin-install.md) — Anthropic & Partners plugin install flow, gate logic, backend endpoints, and DevTools recipes
|
||
- [`apt-worker-architecture.md`](docs/learnings/apt-worker-architecture.md) — APT/DNF binary distribution via Cloudflare Worker + GitHub Releases, redirect chain, credential ownership, heartbeat runbook
|
||
- [`tray-rebuild-race.md`](docs/learnings/tray-rebuild-race.md) — why destroy + recreate on `nativeTheme` updates briefly duplicates the tray icon on KDE Plasma, and the in-place `setImage` + `setContextMenu` fast-path that avoids the SNI re-registration race
|
||
- [`mcp-double-spawn.md`](docs/learnings/mcp-double-spawn.md) — Stdio MCPs spawn 2× when chat and Code/Agent panels are both active, root cause in upstream session managers, MCP-author workaround
|
||
- [`linux-topbar-shim.md`](docs/learnings/linux-topbar-shim.md) — why claude.ai's in-app topbar is missing on Linux, the four gates that hide it, why the upstream `frame:false` + WCO config has unclickable buttons on X11 (Chromium-level implicit drag region), and the resolution: hybrid mode (system frame + UA-spoof shim → stacked layout, full button functionality)
|
||
- [`test-harness-electron-hooks.md`](docs/learnings/test-harness-electron-hooks.md) — why constructor-level `BrowserWindow` wraps are silently bypassed by `frame-fix-wrapper`'s Proxy, and the prototype-method hook pattern that works (used by the Quick Entry test runners)
|
||
- [`test-harness-ax-tree-walker.md`](docs/learnings/test-harness-ax-tree-walker.md) — five non-obvious traps in the v7 fingerprint walker after the AX-tree migration: AX-enable async lag, navigateTo-to-same-URL no-op, claude.ai's flat `dialog>button[]` lists, the `more options for X` per-row shape, and sidebar virtualization vs the lookup-failure threshold
|
||
- [`patching-minified-js.md`](docs/learnings/patching-minified-js.md) — general lessons from maintaining a long-lived patch suite against an actively re-minified upstream: anchor selection (literals over identifiers), the `\w` vs `$` identifier-capture trap, beautified false-negatives, idempotency guards, multi-site coordination, non-unique anchor disambiguation, and the SHA-256-pinned hypothesis-verification recipe
|
||
|
||
## Code Style
|
||
|
||
All shell scripts in this project must follow the [Bash Style Guide](STYLEGUIDE.md). Key points:
|
||
|
||
- Tabs for indentation, lines under 80 characters (exception: URLs and regex patterns)
|
||
- Use `[[ ]]` for conditionals, `$(...)` for command substitution
|
||
- Single quotes for literals, double quotes for expansions
|
||
- Lowercase variables; UPPERCASE only for constants/exports
|
||
- Use `local` in functions, avoid `set -e` and `eval`
|
||
|
||
### Linting
|
||
|
||
Shell scripts are checked with `shellcheck` and GitHub Actions workflows with `actionlint` before pushing. When lint issues are found:
|
||
|
||
1. **Fix the code** - Correct the underlying issue rather than suppressing the warning
|
||
2. **Disable directives are a last resort** - Only use `# shellcheck disable=SCXXXX` when:
|
||
- The warning is a false positive
|
||
- The pattern is intentional and unavoidable
|
||
- Always add a comment explaining why the disable is needed
|
||
3. **Run `/lint` to check manually** - Use this skill to check for issues before pushing
|
||
|
||
## GitHub Workflow
|
||
|
||
### General Approach
|
||
|
||
- Use `gh` CLI for all GitHub interactions
|
||
- Create branches based on issue numbers: `fix/123-description` or `feature/123-description`
|
||
- Reference issues in commits and PRs with `#123` or `Fixes #123`
|
||
- After creating a PR, add a comment to the related issue with a summary and link to the PR
|
||
|
||
### Investigating Issues
|
||
|
||
For older issues, review the state of the code when the issue was raised - it may have already been addressed:
|
||
|
||
```bash
|
||
# Get issue creation date
|
||
gh issue view 123 --json createdAt
|
||
|
||
# Find the commit just before the issue was created
|
||
git log --oneline --until="2025-08-23T08:48:35Z" -1
|
||
|
||
# View a file at that point in time
|
||
git show <commit>:path/to/file.sh
|
||
|
||
# Search for relevant changes since the issue was created
|
||
git log --oneline --after="2025-08-23" -- path/to/file.sh
|
||
|
||
# View a specific commit that may have fixed the issue
|
||
git show <commit>
|
||
```
|
||
|
||
This helps identify if the issue was already fixed, and allows referencing the specific commit in the response.
|
||
|
||
### Attribution
|
||
|
||
**For PR descriptions**, include full attribution:
|
||
|
||
```
|
||
---
|
||
Generated with [Claude Code](https://claude.ai/code)
|
||
Co-Authored-By: Claude <model-name> <noreply@anthropic.com>
|
||
<XX>% AI / <YY>% Human
|
||
Claude: <what AI did>
|
||
Human: <what human did>
|
||
```
|
||
|
||
- Use the actual model name (e.g., `Claude Opus 4.5`, `Claude Sonnet 4`)
|
||
- The percentage split should honestly reflect the contribution balance for that specific work
|
||
- This provides a trackable record of AI-assisted development over time
|
||
|
||
**For issues and comments**, use simplified attribution:
|
||
|
||
```
|
||
---
|
||
Written by Claude <model-name> via [Claude Code](https://claude.ai/code)
|
||
```
|
||
|
||
**For commits**, include a Co-Authored-By trailer:
|
||
|
||
```
|
||
Co-Authored-By: Claude <claude@anthropic.com>
|
||
```
|
||
|
||
### Contributor Credits
|
||
|
||
The README Acknowledgments section credits external contributors in chronological order (by merge date or fix date). Update it when:
|
||
|
||
1. **Merging an external PR** — Add the author to the Acknowledgments list with a link to their GitHub profile and a brief description of their contribution.
|
||
2. **Implementing a fix suggested in an issue** — If an issue author (or commenter) provided a concrete fix, workaround, code snippet, or detailed technical analysis that was directly used, credit them too.
|
||
|
||
Contributors are listed in chronological order: inspirational projects first (k3d3, emsi, leobuskin), then contributors ordered by when their contribution was merged or implemented.
|
||
|
||
## Working with Minified JavaScript
|
||
|
||
### Important Guidelines
|
||
|
||
1. **Always use regex patterns** when modifying the source JavaScript. Patches live in `scripts/patches/*.sh` (one file per subsystem: `tray.sh`, `cowork.sh`, `claude-code.sh`, etc.); `build.sh` is only an orchestrator that sources them. Variable and function names are minified and **change between releases**.
|
||
|
||
2. **The beautified code in `build-reference/` has different spacing** than the actual minified code in the app. Patterns must handle both:
|
||
- Minified: `oe.nativeTheme.on("updated",()=>{`
|
||
- Beautified: `oe.nativeTheme.on("updated", () => {`
|
||
|
||
3. **Use `-E` flag with sed** for extended regex support when patterns need grouping or alternation.
|
||
|
||
4. **Extract variable names dynamically** rather than hardcoding them. Shared extraction helpers live in `scripts/patches/_common.sh`. Example:
|
||
```bash
|
||
# Extract function name from a known pattern
|
||
TRAY_FUNC=$(grep -oP 'on\("menuBarEnabled",\(\)=>\{\K[$\w]+(?=\(\)\})' app.asar.contents/.vite/build/index.js)
|
||
```
|
||
|
||
5. **Handle optional whitespace** in regex patterns:
|
||
```bash
|
||
# Bad: assumes no spaces
|
||
sed -i 's/oe.nativeTheme.on("updated",()=>{/...'
|
||
|
||
# Good: handles optional whitespace
|
||
sed -i -E 's/(oe\.nativeTheme\.on\(\s*"updated"\s*,\s*\(\)\s*=>\s*\{)/...'
|
||
```
|
||
|
||
### Reference Files
|
||
|
||
- `build-reference/app-extracted/` - Extracted and beautified source for analysis
|
||
- `build-reference/tray-icons/` - Tray icon assets for reference
|
||
|
||
## Frame Fix Wrapper
|
||
|
||
The app uses a wrapper system to intercept and fix Electron behavior for Linux:
|
||
|
||
- **`frame-fix-wrapper.js`** - Intercepts `require('electron')` to patch BrowserWindow defaults (e.g., `frame: true` for proper window decorations on Linux)
|
||
- **`frame-fix-entry.js`** - Entry point that loads the wrapper before the main app
|
||
|
||
These are injected by `scripts/patches/app-asar.sh` (inside `patch_app_asar`) and referenced in `package.json`'s `main` field. The wrapper pattern allows fixing Electron behavior without modifying the minified app code directly.
|
||
|
||
## Setting Up build-reference
|
||
|
||
If `build-reference/` is missing or you need to inspect source for a new version, follow these steps to download, extract, and beautify the source code.
|
||
|
||
### Prerequisites
|
||
|
||
```bash
|
||
# Install required tools
|
||
sudo apt install p7zip-full wget nodejs npm
|
||
|
||
# Install asar and prettier globally (or use npx)
|
||
npm install -g @electron/asar prettier
|
||
```
|
||
|
||
### Step 1: Download the Windows Installer
|
||
|
||
The Windows installer contains the app.asar which has the full Electron app source.
|
||
|
||
```bash
|
||
# Create working directory
|
||
mkdir -p build-reference && cd build-reference
|
||
|
||
# Download URL pattern (update version as needed):
|
||
# x64: https://downloads.claude.ai/releases/win32/x64/VERSION/Claude-COMMIT.exe
|
||
# arm64: https://downloads.claude.ai/releases/win32/arm64/VERSION/Claude-COMMIT.exe
|
||
|
||
# Example for version 1.1.381:
|
||
wget -O Claude-Setup-x64.exe "https://downloads.claude.ai/releases/win32/x64/1.1.381/Claude-c2a39e9c82f5a4d51f511f53f532afd276312731.exe"
|
||
```
|
||
|
||
### Step 2: Extract the Installer
|
||
|
||
```bash
|
||
# Extract the exe (it's a 7z archive)
|
||
7z x -y Claude-Setup-x64.exe -o"exe-contents"
|
||
|
||
# Find and extract the nupkg
|
||
cd exe-contents
|
||
NUPKG=$(find . -name "AnthropicClaude-*.nupkg" | head -1)
|
||
7z x -y "$NUPKG" -o"nupkg-contents"
|
||
cd ..
|
||
|
||
# Copy out the important files
|
||
cp exe-contents/nupkg-contents/lib/net45/resources/app.asar .
|
||
cp -a exe-contents/nupkg-contents/lib/net45/resources/app.asar.unpacked .
|
||
|
||
# Optional: copy tray icons for reference
|
||
mkdir -p tray-icons
|
||
cp exe-contents/nupkg-contents/lib/net45/resources/*.png tray-icons/ 2>/dev/null || true
|
||
cp exe-contents/nupkg-contents/lib/net45/resources/*.ico tray-icons/ 2>/dev/null || true
|
||
```
|
||
|
||
### Step 3: Extract app.asar
|
||
|
||
```bash
|
||
# Extract the asar archive
|
||
asar extract app.asar app-extracted
|
||
```
|
||
|
||
### Step 4: Beautify the JavaScript Files
|
||
|
||
The extracted JS files are minified. Use prettier to make them readable:
|
||
|
||
```bash
|
||
# Beautify all JS files in the build directory
|
||
npx prettier --write "app-extracted/.vite/build/*.js"
|
||
|
||
# Or beautify specific files
|
||
npx prettier --write app-extracted/.vite/build/index.js
|
||
npx prettier --write app-extracted/.vite/build/mainWindow.js
|
||
```
|
||
|
||
### Step 5: Clean Up (Optional)
|
||
|
||
```bash
|
||
# Remove intermediate files, keep only what's needed for reference
|
||
rm -rf exe-contents
|
||
rm Claude-Setup-x64.exe
|
||
rm -rf app.asar app.asar.unpacked # Keep only app-extracted
|
||
```
|
||
|
||
### Final Structure
|
||
|
||
```
|
||
build-reference/
|
||
├── app-extracted/
|
||
│ ├── .vite/
|
||
│ │ ├── build/
|
||
│ │ │ ├── index.js # Main process (beautified)
|
||
│ │ │ ├── mainWindow.js # Main window preload
|
||
│ │ │ ├── mainView.js # Main view preload
|
||
│ │ │ └── ...
|
||
│ │ └── renderer/
|
||
│ │ └── ...
|
||
│ ├── node_modules/
|
||
│ │ └── @ant/claude-native/ # Native bindings (stubs)
|
||
│ └── package.json
|
||
├── tray-icons/
|
||
│ ├── TrayIconTemplate.png # Black icon (for light panels)
|
||
│ ├── TrayIconTemplate-Dark.png # White icon (for dark panels)
|
||
│ └── ...
|
||
└── nupkg-contents/ # Optional: full extracted nupkg
|
||
```
|
||
|
||
## Adding New Package Formats or Repositories
|
||
|
||
When adding support for new distribution formats (e.g., RPM, Flatpak, Snap) or package repositories, follow these guidelines to avoid iterative debugging in CI.
|
||
|
||
### Research Before Implementing
|
||
|
||
1. **Understand the target system's constraints** - Each package format has specific rules:
|
||
- Version string formats (e.g., RPM cannot have hyphens in Version field)
|
||
- Required metadata fields
|
||
- Signing requirements and tools
|
||
|
||
2. **Search for existing CI implementations** - Look for "GitHub Actions [format] signing" or similar. Existing workflows reveal required flags, environment setup, and common pitfalls.
|
||
|
||
3. **Check tool behavior in non-interactive environments** - CI has no TTY. Tools like GPG need flags like `--batch` and `--yes` to work without prompts.
|
||
|
||
### Consider Concurrency
|
||
|
||
1. **Multiple jobs writing to the same branch will race** - If APT and DNF repos both push to `gh-pages`, add:
|
||
- Job dependencies (`needs: [other-job]`), or
|
||
- Retry loops with `git pull --rebase` before push
|
||
|
||
2. **External processes may also modify branches** - GitHub Pages deployment runs automatically and can cause push conflicts.
|
||
|
||
### Test the Full Pipeline
|
||
|
||
1. **Test CI steps locally first** - Run the signing/packaging commands manually to catch errors before committing.
|
||
|
||
2. **Use a test tag for new infrastructure** - Create a non-release tag to validate the full CI pipeline before merging to main.
|
||
|
||
3. **Verify the end-user experience** - After CI succeeds, actually test the install commands from the README on a clean system.
|
||
|
||
### Common CI Pitfalls
|
||
|
||
| Issue | Solution |
|
||
|-------|----------|
|
||
| GPG "cannot open /dev/tty" | Add `--batch` flag |
|
||
| GPG "File exists" error | Add `--yes` flag to overwrite |
|
||
| Push rejected (ref changed) | Add `git pull --rebase` before push, with retry loop |
|
||
| Version format invalid | Research target format's version constraints upfront |
|
||
| Signing key not found | Ensure key is imported before signing step, check key ID output |
|
||
|
||
## CI/CD
|
||
|
||
### Triggering Builds
|
||
|
||
```bash
|
||
# Trigger CI on a branch
|
||
gh workflow run CI --ref branch-name
|
||
|
||
# Watch the run
|
||
gh run watch RUN_ID
|
||
|
||
# Download artifacts
|
||
gh run download RUN_ID -n artifact-name
|
||
```
|
||
|
||
### Build Artifacts
|
||
|
||
- `claude-desktop-VERSION-amd64.deb` - Debian package for x86_64
|
||
- `claude-desktop-VERSION-amd64.AppImage` - AppImage for x86_64
|
||
- `claude-desktop-VERSION-arm64.deb` - Debian package for ARM64
|
||
- `claude-desktop-VERSION-arm64.AppImage` - AppImage for ARM64
|
||
- `result/` - Nix build output (symlink, gitignored)
|
||
|
||
## Distribution
|
||
|
||
APT and DNF binaries are fronted by a Cloudflare Worker at `pkg.claude-desktop-debian.dev`. Metadata (`InRelease`, `Packages`, `KEY.gpg`, `repodata/*`) passes through to the `gh-pages` branch; binary requests (`/pool/.../*.deb`, `/rpm/*/*.rpm`) get 302'd to the corresponding GitHub Release asset. This keeps `.deb` / `.rpm` files out of `gh-pages` entirely, so they never hit GitHub's 100 MB per-file push cap.
|
||
|
||
Key files:
|
||
- `worker/src/worker.js` — Worker source
|
||
- `worker/wrangler.toml` — Worker config (route, `custom_domain = true`)
|
||
- `.github/workflows/deploy-worker.yml` — deploys on push to `main` when `worker/**` changes
|
||
- `.github/workflows/apt-repo-heartbeat.yml` — daily chain validation, auto-opens tracking issue on failure
|
||
- `update-apt-repo` and `update-dnf-repo` jobs in `.github/workflows/ci.yml` — gate a strip step on Worker liveness, so binaries are removed from the local pool tree before push
|
||
|
||
Repo secrets: `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID`. Token scoped to the "Edit Cloudflare Workers" template.
|
||
|
||
Full details including the redirect chain, the http-scheme-downgrade gotcha, credential ownership, and heartbeat failure runbook: [`docs/learnings/apt-worker-architecture.md`](docs/learnings/apt-worker-architecture.md).
|
||
|
||
## Testing
|
||
|
||
### Local Build
|
||
|
||
```bash
|
||
./build.sh --build appimage --clean no
|
||
```
|
||
|
||
### Nix Build
|
||
|
||
```bash
|
||
nix build .#claude-desktop
|
||
nix build .#claude-desktop-fhs
|
||
```
|
||
|
||
### Testing AppImage
|
||
|
||
```bash
|
||
# Run with logging
|
||
./test-build/claude-desktop-*.AppImage 2>&1 | tee ~/.cache/claude-desktop-debian/launcher.log
|
||
```
|
||
|
||
## Debugging Workflow
|
||
|
||
### Inspecting the Running App's Code
|
||
|
||
```bash
|
||
# Find the mounted AppImage path
|
||
mount | grep claude
|
||
# Example: /tmp/.mount_claudeXXXXXX
|
||
|
||
# Extract the running app's asar for inspection
|
||
npx asar extract /tmp/.mount_claudeXXXXXX/usr/lib/node_modules/electron/dist/resources/app.asar /tmp/claude-inspect
|
||
|
||
# Search for patterns in the extracted code
|
||
grep -n "pattern" /tmp/claude-inspect/.vite/build/index.js
|
||
```
|
||
|
||
### Checking DBus/Tray Status
|
||
|
||
```bash
|
||
# List registered tray icons
|
||
gdbus call --session --dest=org.kde.StatusNotifierWatcher \
|
||
--object-path=/StatusNotifierWatcher \
|
||
--method=org.freedesktop.DBus.Properties.Get \
|
||
org.kde.StatusNotifierWatcher RegisteredStatusNotifierItems
|
||
|
||
# Find which process owns a DBus connection
|
||
gdbus call --session --dest=org.freedesktop.DBus \
|
||
--object-path=/org/freedesktop/DBus \
|
||
--method=org.freedesktop.DBus.GetConnectionUnixProcessID ":1.XXXX"
|
||
```
|
||
|
||
### Log Locations
|
||
|
||
- Launcher log: `~/.cache/claude-desktop-debian/launcher.log`
|
||
- App logs: `~/.config/Claude/logs/`
|
||
- Run with logging: `./app.AppImage 2>&1 | tee ~/.cache/claude-desktop-debian/launcher.log`
|
||
|
||
## Useful Locations
|
||
|
||
- App data: `~/.config/Claude/`
|
||
- Logs: `~/.config/Claude/logs/`
|
||
- SingletonLock: `~/.config/Claude/SingletonLock`
|
||
- Launcher log: `~/.cache/claude-desktop-debian/launcher.log`
|
||
|
||
## Versioning
|
||
|
||
Release versions are managed via two GitHub Actions repository variables (not files):
|
||
|
||
- **`REPO_VERSION`** - The project's own version (e.g., `1.3.23`). Bump this manually via `gh variable set REPO_VERSION --body "X.Y.Z"` when shipping project changes.
|
||
- **`CLAUDE_DESKTOP_VERSION`** - The upstream Claude Desktop version (e.g., `1.1.8629`). Updated automatically by the `check-claude-version` workflow when a new upstream release is detected.
|
||
|
||
### Tag format
|
||
|
||
Tags follow the pattern `v{REPO_VERSION}+claude{CLAUDE_DESKTOP_VERSION}`, e.g., `v1.3.23+claude1.1.7714`. Pushing a tag triggers the CI release build.
|
||
|
||
```bash
|
||
# Check current values
|
||
gh variable get REPO_VERSION
|
||
gh variable get CLAUDE_DESKTOP_VERSION
|
||
|
||
# Bump repo version and tag a release
|
||
gh variable set REPO_VERSION --body "1.3.24"
|
||
git tag "v1.3.24+claude$(gh variable get CLAUDE_DESKTOP_VERSION)"
|
||
git push origin "v1.3.24+claude$(gh variable get CLAUDE_DESKTOP_VERSION)"
|
||
```
|
||
|
||
When upstream Claude Desktop updates, the `check-claude-version` workflow automatically updates `CLAUDE_DESKTOP_VERSION`, patches the URLs in `scripts/setup/detect-host.sh`, and creates a new tag — no manual intervention needed.
|
||
|
||
## Common Gotchas
|
||
|
||
- **`.zsync` files** - Used for delta updates, can be ignored/deleted
|
||
- **AppImage mount points** - Running AppImages mount to `/tmp/.mount_claude*`; check with `mount | grep claude`
|
||
- **Killing the app** - Must kill all electron child processes, not just the main one:
|
||
```bash
|
||
pkill -9 -f "mount_claude"
|
||
```
|
||
- **SingletonLock** - If app won't start, check for stale lock: `~/.config/Claude/SingletonLock`
|
||
- **Node version** - Build requires Node.js; the script downloads its own if needed
|
||
- **Nix hashes** - When Claude Desktop version changes, both the URLs in `scripts/setup/detect-host.sh` and `nix/claude-desktop.nix` (version, URLs, SRI hashes) must be updated. The CI handles this automatically.
|
||
- **Claude Desktop version** - A GitHub Action automatically updates the `CLAUDE_DESKTOP_VERSION` repo variable and the URLs in `scripts/setup/detect-host.sh` on main when a new version is detected. Before committing `scripts/setup/detect-host.sh`, ensure your branch has the latest URLs:
|
||
```bash
|
||
# Check repo variable (source of truth)
|
||
gh variable get CLAUDE_DESKTOP_VERSION
|
||
|
||
# Check current version in the detect_architecture case statement
|
||
grep -oP 'x64/\K[0-9]+\.[0-9]+\.[0-9]+' scripts/setup/detect-host.sh | head -1
|
||
|
||
# If outdated, pull URLs from main branch
|
||
gh api repos/aaddrick/claude-desktop-debian/contents/scripts/setup/detect-host.sh?ref=main \
|
||
--jq '.content' | base64 -d | grep -E "claude_download_url="
|
||
```
|
||
Update both amd64 and arm64 URLs in `detect_architecture()` to match main
|