feat: add Ubuntu/Linux .deb build support#44
Conversation
Add electron-builder Linux configuration with AppImage and deb targets, npm scripts for Linux builds, and a GitHub Actions workflow that builds on ubuntu-latest and uploads artifacts to releases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…PIPE) - Remove AppImage target, keep .deb only for Ubuntu/Linux - Add CI smoke tests: size check, dpkg-deb metadata, binary presence - Fix EPIPE errors on stdout/stderr for desktop entry launches - Add --no-sandbox flag to .desktop file executable args - Add description and author fields to package.json - Wire after-install script via fpm for chrome-sandbox SUID Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@davebulaval is attempting to deploy a commit to the Charlie Rabiller's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Linux packaging and CI: a GitHub Actions workflow builds, validates, and uploads Debian Changes
Sequence Diagram(s)sequenceDiagram
participant Tag as Git Tag / Manual Trigger
participant GH as GitHub Actions
participant Runner as Ubuntu Runner
participant NPM as npm / electron-builder
participant Art as Artifact Storage
participant Rel as GitHub Release
Tag->>GH: push tag / workflow_dispatch
GH->>Runner: start `build-linux` job (ubuntu-latest)
Runner->>NPM: checkout, setup Node.js 20, npm ci
Runner->>Runner: apt-get install libarchive-tools
Runner->>NPM: run `npm run electron:build:linux` (electron-builder)
NPM-->>Runner: produce `release/*.deb`
Runner->>Runner: validate .deb files (dpkg-deb info, contains `opt/Dorothy/dorothy`, non-zero size)
Runner->>Art: upload `.deb` artifacts
alt refs/tags/v*
Runner->>Rel: upload `.deb` to GitHub Release
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Just to be clear, I never built (before working with Claude Code) a .deb for Ubuntu. So it is 100% Claude Code code generation, but I have tested the app locally, and it works. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
package.json (1)
19-22: Consolidate duplicated Electron build pipelines.The four scripts duplicate a long command chain; this is easy to drift and hard to maintain. Extract the shared prep/build steps into one script and pass platform flags.
♻️ Suggested script consolidation
"scripts": { - "electron:build": "bash -c '...; electron-builder --mac'", - "electron:build:linux": "bash -c '...; electron-builder --linux'", - "electron:pack": "tsc ... && electron-builder --dir --mac", - "electron:pack:linux": "tsc ... && electron-builder --dir --linux" + "electron:prepare": "bash scripts/electron-prepare.sh", + "electron:build": "npm run electron:prepare && electron-builder --mac", + "electron:build:linux": "npm run electron:prepare && electron-builder --linux", + "electron:pack": "npm run electron:prepare && electron-builder --dir --mac", + "electron:pack:linux": "npm run electron:prepare && electron-builder --dir --linux" }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@package.json` around lines 19 - 22, The four npm scripts ("electron:build", "electron:build:linux", "electron:pack", "electron:pack:linux") duplicate the same prep and subproject build chain; extract that common sequence into a single script (e.g., "electron:prepare" or "electron:build:common") that performs the mv/backups/trap, NEXT/TSC build steps and the looped npm install/npm run build for mcp-* packages, and then have the four platform-specific scripts simply set platform flags/environment (ELECTRON_BUILD or a PLATFORM var) and call the shared script before invoking electron-builder with the appropriate platform arguments. Update references to the unique script names ("electron:prepare" and the original four) and ensure the backup/trap logic and tsc invocation remain in the shared script so behavior is unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/build-linux.yml:
- Around line 1-13: The workflow fails in orgs with hardened token settings
because the release upload step using softprops/action-gh-release@v2 requires
write access to repo contents but no explicit permissions are declared; add an
explicit permissions block to the workflow (top-level) granting contents: write
so the build-linux job and the release upload step can write release assets
(reference: job name build-linux and action softprops/action-gh-release@v2).
- Around line 44-48: The current DEB handling uses DEB=$(ls release/*.deb) and
then stat "$DEB", which breaks if multiple .deb files exist; update the
validation block to iterate over release/*.deb (or explicitly select a single
file e.g., the first or largest) and perform the existence check and stat on
each candidate rather than on a concatenated string. Specifically change the
logic around the DEB variable and DEB_SIZE calculation so you loop (for deb in
release/*.deb) or use an array expansion to set DEB to a single path before
calling stat, and emit an error/exit if any checked .deb is missing or below the
50MB threshold; touch references to DEB and DEB_SIZE in that block so the script
works with multiple artifacts.
In `@package.json`:
- Around line 124-135: Remove the global "--no-sandbox" from the
linux.executableArgs in package.json and instead implement the SUID setup script
referenced as build/linux/after-install.sh to set the chrome-sandbox binary
owner to root and the setuid bit (e.g., chown root:root chrome-sandbox && chmod
4755 chrome-sandbox) as part of the package post-install; alternatively, if you
must keep a flag for dev builds, gate executableArgs so it only applies in
development (not production) and wire a postinstall hook in package.json that
invokes build/linux/after-install.sh; ensure the script exists, is executable,
idempotent, and documents why it sets SUID on chrome-sandbox.
---
Nitpick comments:
In `@package.json`:
- Around line 19-22: The four npm scripts ("electron:build",
"electron:build:linux", "electron:pack", "electron:pack:linux") duplicate the
same prep and subproject build chain; extract that common sequence into a single
script (e.g., "electron:prepare" or "electron:build:common") that performs the
mv/backups/trap, NEXT/TSC build steps and the looped npm install/npm run build
for mcp-* packages, and then have the four platform-specific scripts simply set
platform flags/environment (ELECTRON_BUILD or a PLATFORM var) and call the
shared script before invoking electron-builder with the appropriate platform
arguments. Update references to the unique script names ("electron:prepare" and
the original four) and ensure the backup/trap logic and tsc invocation remain in
the shared script so behavior is unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4bc56f5e-cd56-4da7-b3a8-df6075e98a01
📒 Files selected for processing (3)
.github/workflows/build-linux.ymlelectron/main.tspackage.json
…andbox - Add explicit `permissions: contents: write` to workflow for hardened orgs - Use bash array loop for .deb validation (handles multiple artifacts) - Remove `--no-sandbox` from desktop entry; rely on SUID chrome-sandbox set by after-install.sh (chown root + chmod 4755) per Electron guidance - Make after-install.sh idempotent with chown root:root Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JiwaniZakir
left a comment
There was a problem hiding this comment.
The optional chaining in electron/main.ts (process.stdout?.on?.('error', ...)) is unnecessary — process.stdout and process.stderr are always defined in Node.js, so this reads as defensive code without purpose and may mislead future readers about their nullability.
The 50MB size threshold in the Verify build artifacts step is a magic number that will cause false-positive failures if the app grows naturally or shrinks due to dependency changes. A more robust check would be to verify the .deb contains a non-zero-size binary rather than asserting an absolute byte threshold.
The after-install.sh script sets SUID on chrome-sandbox, but there's no corresponding before-remove.sh to clean up that SUID root binary on uninstall — leaving a world-executable SUID binary behind on uninstall is a minor security hygiene issue worth addressing.
The electron:build and electron:build:linux scripts in package.json are nearly identical 200-character bash one-liners duplicated across both entries, differing only in the final --mac/--linux flag. Extracting the shared MCP build steps into a separate script (e.g., build/scripts/build-mcps.sh) would make both commands dramatically easier to maintain and less error-prone when new MCP modules are added.
…p on uninstall - Remove unnecessary optional chaining on process.stdout/stderr (always defined in Node.js) - Replace magic 50MB size threshold with non-zero binary size check in CI smoke tests - Add before-remove.sh to strip SUID bit from chrome-sandbox on package uninstall (security hygiene) - Wire before-remove.sh into deb fpm config Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@JiwaniZakir Thanks for the thorough review! All points addressed in 81697a9: 1. Optional chaining on 2. Magic 50MB threshold — Fixed. Replaced the hardcoded byte threshold with a check that the 3. SUID cleanup on uninstall — Fixed. Added 4. Script duplication (nitpick) — Not addressed in this PR. Extracting a shared |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
package.json (1)
19-22: Consider extracting common build steps to reduce duplication.The
electron:build,electron:build:linux,electron:pack, andelectron:pack:linuxscripts share nearly identical logic for moving API files, building sub-packages, and running traps. This duplication makes maintenance harder—any change to the build process must be applied in multiple places.♻️ Suggested approach
Extract the common build logic into a shell script:
# scripts/build-subpackages.sh #!/bin/bash set -e for pkg in mcp-orchestrator mcp-telegram mcp-kanban mcp-vault mcp-socialdata mcp-x mcp-world; do cd "$pkg" && npm install && npm run build && cd .. doneThen simplify the npm scripts:
-"electron:build": "bash -c 'set -e; mv src/app/api src/app/_api_backup; mv src/app/icon.tsx src/app/_icon_backup.tsx 2>/dev/null || true; trap \"mv src/app/_api_backup src/app/api 2>/dev/null; mv src/app/_icon_backup.tsx src/app/icon.tsx 2>/dev/null\" EXIT; ELECTRON_BUILD=1 next build; tsc -p electron/tsconfig.json; cd mcp-orchestrator && npm install && npm run build && cd ..; cd mcp-telegram && npm install && npm run build && cd ..; cd mcp-kanban && npm install && npm run build && cd ..; cd mcp-vault && npm install && npm run build && cd ..; cd mcp-socialdata && npm install && npm run build && cd ..; cd mcp-x && npm install && npm run build && cd ..; cd mcp-world && npm install && npm run build && cd ..; electron-builder --mac'", +"electron:build": "bash scripts/electron-build.sh --mac",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@package.json` around lines 19 - 22, The package.json scripts "electron:build", "electron:build:linux", "electron:pack", and "electron:pack:linux" duplicate the same subpackage build and file-move logic; extract the repeated steps into a single executable script (e.g. scripts/build-subpackages.sh) that loops over the packages (mcp-orchestrator, mcp-telegram, mcp-kanban, mcp-vault, mcp-socialdata, mcp-x, mcp-world) and runs npm install && npm run build for each, preserve the existing API/icon backup and trap logic and the ELECTRON_BUILD/next/tsc/electron-builder steps, then update the four npm script entries to call the new script (and keep platform-specific electron-builder flags) to remove duplication while keeping behavior identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@package.json`:
- Around line 19-22: The package.json scripts "electron:build",
"electron:build:linux", "electron:pack", and "electron:pack:linux" duplicate the
same subpackage build and file-move logic; extract the repeated steps into a
single executable script (e.g. scripts/build-subpackages.sh) that loops over the
packages (mcp-orchestrator, mcp-telegram, mcp-kanban, mcp-vault, mcp-socialdata,
mcp-x, mcp-world) and runs npm install && npm run build for each, preserve the
existing API/icon backup and trap logic and the
ELECTRON_BUILD/next/tsc/electron-builder steps, then update the four npm script
entries to call the new script (and keep platform-specific electron-builder
flags) to remove duplication while keeping behavior identical.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1ddfe0d5-f00e-4d7a-8c4e-5238c7ce38e7
📒 Files selected for processing (4)
.github/workflows/build-linux.ymlbuild/linux/before-remove.shelectron/main.tspackage.json
🚧 Files skipped from review as they are similar to previous changes (1)
- .github/workflows/build-linux.yml
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
package.json (1)
20-22: Extract a shared Electron prepare/build command to avoid drift.These scripts duplicate a long command chain; one future edit can easily diverge behavior between mac/linux build/pack.
Refactor sketch
"scripts": { + "electron:prepare": "tsc -p electron/tsconfig.json && cd mcp-orchestrator && npm install && npm run build && cd .. && cd mcp-telegram && npm install && npm run build && cd .. && cd mcp-kanban && npm install && npm run build && cd .. && cd mcp-vault && npm install && npm run build && cd .. && cd mcp-socialdata && npm install && npm run build && cd .. && cd mcp-x && npm install && npm run build && cd .. && cd mcp-world && npm install && npm run build && cd ..", - "electron:pack": "... && electron-builder --dir --mac", - "electron:pack:linux": "... && electron-builder --dir --linux" + "electron:pack": "npm run electron:prepare && electron-builder --dir --mac", + "electron:pack:linux": "npm run electron:prepare && electron-builder --dir --linux" }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@package.json` around lines 20 - 22, The three npm scripts electron:build:linux, electron:pack, and electron:pack:linux duplicate a long prepare/build command; create a new shared script (e.g., "electron:prepare" or "electron:build:prepare") that contains the common steps (the mv/trap backups, ELECTRON_BUILD=1 next build, tsc -p electron/tsconfig.json, and the repeated cd ... && npm install && npm run build for each mcp-*), then update electron:build:linux, electron:pack, and electron:pack:linux to call npm run electron:prepare (or the chosen name) and append only the platform-specific final electron-builder invocation (and any platform flags like --linux or --mac); ensure you preserve the exact backup/trap semantics and order so behavior remains identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@package.json`:
- Around line 20-22: The three npm scripts electron:build:linux, electron:pack,
and electron:pack:linux duplicate a long prepare/build command; create a new
shared script (e.g., "electron:prepare" or "electron:build:prepare") that
contains the common steps (the mv/trap backups, ELECTRON_BUILD=1 next build, tsc
-p electron/tsconfig.json, and the repeated cd ... && npm install && npm run
build for each mcp-*), then update electron:build:linux, electron:pack, and
electron:pack:linux to call npm run electron:prepare (or the chosen name) and
append only the platform-specific final electron-builder invocation (and any
platform flags like --linux or --mac); ensure you preserve the exact backup/trap
semantics and order so behavior remains identical.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: feabeb8e-bcb6-4bdf-a9c1-83016d7bf406
📒 Files selected for processing (2)
electron/main.tspackage.json
✅ Files skipped from review due to trivial changes (1)
- electron/main.ts
|
The SUID setup in |
…repare.sh The 4 electron build/pack scripts duplicated ~200 chars of identical logic (API backup, next build, tsc, MCP sub-package builds). Extract into a shared script and simplify each npm script to a one-liner. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
scripts/electron-prepare.sh (1)
12-12: Ensurenextcommand is available in PATH.The script invokes
next builddirectly. If run outside of an npm script context (e.g., viabash scripts/electron-prepare.shdirectly),nextmay not be in PATH. Consider usingnpx next buildor./node_modules/.bin/next buildfor robustness.♻️ Suggested change
# Build Next.js static export -ELECTRON_BUILD=1 next build +ELECTRON_BUILD=1 npx next build🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/electron-prepare.sh` at line 12, The script currently runs the Next.js build with the bare command "next build" (line containing ELECTRON_BUILD=1 next build), which can fail if "next" isn't in PATH; update that invocation to use a project-local resolver such as "npx next build" or "./node_modules/.bin/next build" so the script works when run directly (e.g., bash scripts/electron-prepare.sh) and preserves the ELECTRON_BUILD=1 environment variable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@package.json`:
- Around line 138-148: The deb packaging depends array in package.json currently
lists libgtk-3-0 and libatspi2.0-0 which will fail on Ubuntu 24.04; update the
"depends" array to replace "libgtk-3-0" with "libgtk-3-0t64" and "libatspi2.0-0"
with "libatspi2.0-0t64" (or alternatively implement separate build targets that
produce distinct .deb artifacts for Ubuntu 22.04 and 24.04 with the appropriate
dependency sets) so that the depends list in package.json matches the t64 time_t
transition requirements.
In `@scripts/electron-prepare.sh`:
- Around line 7-9: The trap uses relative paths so if the script changes
directories (e.g., after cd "$pkg" in the MCP build loop) the cleanup mv
commands can run from the wrong cwd and silently fail; modify the script to
compute and use absolute paths (or capture and use pushd/popd) for the backup
files referenced in the trap and in the mv calls — specifically update the mv
commands that move src/app/api and src/app/icon.tsx and the trap restore
commands so they reference a project-root variable (e.g., ROOT) or use
pushd/popd around cd "$pkg" to guarantee the trap always moves
ROOT/src/app/_api_backup and ROOT/src/app/_icon_backup.tsx back to
ROOT/src/app/api and ROOT/src/app/icon.tsx even if the script exits from a
different working directory.
---
Nitpick comments:
In `@scripts/electron-prepare.sh`:
- Line 12: The script currently runs the Next.js build with the bare command
"next build" (line containing ELECTRON_BUILD=1 next build), which can fail if
"next" isn't in PATH; update that invocation to use a project-local resolver
such as "npx next build" or "./node_modules/.bin/next build" so the script works
when run directly (e.g., bash scripts/electron-prepare.sh) and preserves the
ELECTRON_BUILD=1 environment variable.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0cf6e4a5-9f71-45c4-afe9-919e16eb44ae
📒 Files selected for processing (2)
package.jsonscripts/electron-prepare.sh
|
Addressed the repeated nitpick about script duplication in c257ae2:
|
…tignore - Add post-install check: warn if SUID bit didn't stick (nosuid mount) - Change .gitignore from `/build` to `/build/*` + `!/build/linux/` so Linux packaging scripts are tracked without git add -f Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@JiwaniZakir Good catches, both addressed in 06031f3: 1. nosuid mount warning — 2. |
|
The |
|
@JiwaniZakir Both points are already addressed in earlier commits:
|
…4.04 - Use REPO_ROOT absolute paths in trap/cleanup so API route restoration works even if script exits from a subdirectory (cd into mcp-* packages) - Use pushd/popd instead of cd for MCP sub-package builds - Use npx for next build to ensure it's found outside npm script context - Add t64 alternatives for libgtk-3-0 and libatspi2.0-0 in deb depends (Ubuntu 24.04 Y2038 transition, electron-builder#9539) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Replying to the two remaining CodeRabbit comments from review Re: Trap uses relative paths (Critical — Fixed:
Re: Update deb dependencies for Ubuntu 24.04 t64 transition (Major — Fixed:
|
|
The fixes look good — removing the optional chaining on |
|
Any update on the merge timeframe? |
|
Hey @davebulaval, thanks a lot for your contribution! |
Summary
.debpackage build for Ubuntu/Linux (x64) viaelectron-builderbuild-linux.yml) triggered on tags andworkflow_dispatchdpkg-debmetadata validation, binary presence verificationWhat's included
package.json: Linux electron-builder config (deb target),electron:build:linux/electron:pack:linuxscripts, addeddescriptionandauthorfieldselectron/main.ts: EPIPE error handler for stdout/stderr on Linux (crashes when launched from.desktopentries with no TTY).github/workflows/build-linux.yml: Full CI pipeline — build, smoke test, upload artifact, publish to GitHub Release on tagsbuild/linux/after-install.sh: Post-install script that sets SUID bit onchrome-sandbox(required for Electron sandbox)--no-sandboxflag,Developmentcategory,StartupNotify=trueTested on
dpkg -iinstall + launch from/opt/Dorothy/dorothy✅127.0.0.1:31415✅Test plan
.debartifact is downloadable from workflow runsudo dpkg -i Dorothy-*.debon Ubuntu 22.04+latest-linux.yml(expected until first Linux release)🤖 Generated with Claude Code
Summary by CodeRabbit