Skip to content

feat(linux): AppImage, deb, rpm packaging with XDG-aware paths#20

Open
rle-mino wants to merge 22 commits into
mainfrom
feature/linux-compatibility-plan-491e
Open

feat(linux): AppImage, deb, rpm packaging with XDG-aware paths#20
rle-mino wants to merge 22 commits into
mainfrom
feature/linux-compatibility-plan-491e

Conversation

@rle-mino

@rle-mino rle-mino commented May 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Ships first-class Linux support alongside macOS:

  • Linux packaging. Produces x86-64 AppImage, DEB, and RPM artifacts, keeps the Rust sidecar executable, supports Wayland/X11 selection, and discovers agent CLIs in common Linux locations.
  • XDG-aware application data. Routes Linux data, config, cache, logs, and worktrees through the XDG base directories while preserving the existing macOS ~/.cadencr/ layout.
  • Linux auto-updates. Official AppImage, DEB, and RPM installs use electron-updater and select the artifact matching the packaged install identity. Custom/unrecognized Linux builds receive a clear unsupported-install message.
  • Release validation. Smoke-tests the AppImage and installed DEB/RPM sidecars, verifies DEB/RPM resources/package-type, and requires latest-linux.yml to advertise all three updater targets.
  • Installation documentation. Adds Linux download detection and AppImage/APT/DNF/Zypper instructions to the landing site, documentation, README, and generated GitHub release notes.
  • Cross-platform contributor guidance. Updates CLAUDE.md, generated AGENTS.md, and a shared rule so macOS and Linux are both evaluated and any real-platform verification still required is explicitly disclosed.

Validation

  • Full pnpm test suite passes
  • Type checks, lint, formatting, Knip, release-script tests, and agent-doc generation checks pass
  • Landing production build passes
  • Live landing QA detects Linux x86-64, recommends the AppImage, exposes all Linux assets/install commands, and shows no console errors
  • Fresh AppImage and DEB artifacts build locally; extracted sidecars run and the DEB contains resources/package-type=deb
  • PR CI is green for the latest commit
  • Real N → N+1 update on AppImage
  • Real N → N+1 update on Ubuntu/Debian DEB
  • Real N → N+1 update on Fedora/RHEL and openSUSE RPM
  • macOS packaged install/update regression on a real Mac

A test on one OS is not treated as proof for the other. The remaining packaged update transitions require two published versions and real target systems.

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Standardizes per-user storage paths (macOS legacy vs Linux XDG), adds Electron/Rust helpers for path resolution, detects Linux install type to disable in-app updates for package-managed installs, refactors CLI discovery into a new module, and implements Linux packaging and release workflow changes with tests/docs.

Changes

Platform-aware storage paths and detection

Layer / File(s) Summary
Rust service-side path resolution
packages/service/src/shared/app_paths.rs, packages/service/src/shared/mod.rs
Introduces canonical filesystem locations keyed by platform and XDG variables: macOS uses legacy ~/.cadencr; Linux uses XDG_DATA_HOME/config/cache with ~/.local/share, ~/.config, ~/.cache fallbacks. Exports helpers for database, worktrees, and logs paths.
Electron TypeScript path resolution
packages/desktop/electron/main/app-paths.ts, packages/desktop/electron/main/app-paths.test.ts
Mirrors the service-side logic in the Electron main process with platform and XDG awareness, optional test overrides for mocking, and assertion tests covering macOS legacy and Linux XDG behaviors.
Shared path usage in sidecar and worktrees
packages/desktop/electron/main/sidecar.ts, packages/service/src/shared/worktree_paths.rs, packages/service/src/domain/workflow/worktree/reuse.rs, packages/service/tests/common/worktree.rs, packages/service/tests/feature_worktree_test.rs
Sidecar now resolves database paths via the shared helper; worktree code delegates to app_paths::worktrees_dir(); test infrastructure isolates HOME and XDG environment variables to prevent cross-test pollution.
Linux installation type detection
packages/desktop/electron/main/linux-install-type.ts, packages/desktop/electron/main/linux-install-type.test.ts
Detects whether the app was installed as AppImage, deb, rpm, or unknown by checking APPIMAGE env or parsing /etc/os-release; includes configurable paths for testing and user-facing messages for each install type.
Updater service detects and gates unsupported installations
packages/desktop/electron/main/updater.ts
Caches Linux install detection result; prevents electron-updater checks/installs for deb/rpm builds; announces unsupported state via IPC instead.
Frontend update state and UI components
packages/desktop/src/stores/update-store.ts, packages/desktop/src/lib/desktop-bridge.ts, packages/desktop/electron/preload/index.ts, packages/desktop/src/routes/settings.tsx
Extends update store to track unsupported status and accompanying message; disables check button and renders status-specific UI when updates are unavailable.
CLI binary discovery refactoring
packages/claude-agent-sdk-rs/src/discovery.rs, packages/claude-agent-sdk-rs/src/lib.rs, packages/claude-agent-sdk-rs/src/query/metadata.rs, packages/claude-agent-sdk-rs/src/query/spawn.rs, packages/claude-agent-sdk-rs/src/transport.rs
Extracts CLI discovery (global override, caching, semantic version selection) from transport into a new public module; updates all callers to use the new module path.
Login shell environment support on Linux
packages/service/src/shared/login_env.rs
Extends login shell env hydration to macOS and Linux (previously macOS-only); selects platform-specific default shell (zsh on macOS, bash on Linux) when $SHELL is unset.
Shared module exports and discovery specs
packages/service/src/shared/mod.rs, packages/codex-app-server-sdk-rs/src/discovery.rs, packages/opencode-sdk-rs/src/process.rs
Wires new app_paths module into shared exports; expands codex and opencode binary discovery specs to include .cargo/bin, /usr/bin, and /snap/bin install locations.
Documentation updates for platform-aware paths
.agents/skills/db/SKILL.md, .agents/skills/migration-safety/SKILL.md, .claude/skills/migration-safety/SKILL.md, CLAUDE.md, packages/service/src/domain/git/commands/worktree_ops.rs
Describes platform-specific default database paths; mandates using shared path seam modules instead of hardcoded home-directory construction.

Linux build and release infrastructure

Layer / File(s) Summary
GitHub Actions release workflow restructuring
.github/workflows/desktop-release.yml
Adds prepare-release job to manage draft releases, followed by build job on OS matrix (macos-14, ubuntu-latest); platform-specific steps for dependency installation, code signing, and package building; adds containerized smoke tests for produced artifacts.
Electron builder configuration for Linux
packages/desktop/electron-builder.yml, packages/desktop/electron-builder.local.yml
Specifies Linux build targets (AppImage, deb, rpm), package metadata, and distro-level runtime dependencies for both production and local builds.
Post-pack build hooks for Linux
packages/desktop/build/after-pack.cjs, packages/desktop/electron/main/sidecar.test.ts
Updates afterPack hook to mark cadencr-service sidecar executable on Linux; adds test coverage for the Linux chmod behavior.
Electron main process Linux platform configuration
packages/desktop/electron/main/index.ts
Adds ozone-platform-hint=auto command-line switch when running on Linux to influence Wayland/platform behavior.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 Paths laid true on Linux and Mac,
Updates know when they can't come back,
Builds now run on both the stage,
App paths guide us, page by page!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title succinctly captures the Linux packaging and XDG-path work.
Description check ✅ Passed The description matches the PR’s Linux packaging, XDG paths, updates, and docs changes.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/desktop-release.yml:
- Around line 47-49: The build job is unguarded and can run publish-capable
steps even on non-tag workflow_dispatch runs; add a tag-only guard to the build
job (job name "build") by adding a job-level condition such as if:
startsWith(github.ref, 'refs/tags/') so the entire job only runs for tag refs,
and/or add the same conditional to the publish steps that run "electron-builder
... --publish always" to ensure those steps never execute on non-tag refs; make
sure this complements the existing "prepare-release" and "publish-release"
gating so only tag-triggered workflows reach publishing.
- Around line 21-22: Add hardening to the checkout steps and prevent unintended
publishing: add persist-credentials: false to each actions/checkout invocation
(the checkout steps referenced in the workflow), ensure the build job does not
run publisher logic on non-tagged runs by gating the electron-builder publish
behavior (either change the build job's condition to start only on refs/tags or
set electron-builder to --publish never when github.ref is not a tag), and keep
the existing publish-release job gated with if: startsWith(github.ref,
'refs/tags/') so only tagged releases can create/publish GitHub release assets.

In `@packages/claude-agent-sdk-rs/src/discovery.rs`:
- Around line 135-145: The test find_cli_returns_searched_dirs_on_not_found
currently allows Ok(_) and can false-positive; update the match on the result of
find_cli(Some(bogus_override)).await to explicitly fail when Ok(_) is returned
(e.g., panic or assert!(false, ...)) so the test only passes for
Err(SdkError::CliNotFound { searched }) and still asserts !searched.is_empty();
ensure you reference the find_cli call and the SdkError::CliNotFound variant
when making the change so overrides returning Ok are treated as test failures.

In `@packages/desktop/electron/main/sidecar.ts`:
- Around line 136-144: The current ensureLinuxSidecarExecutable function must
not abort startup on chmod failure; change it so that if fs.chmodSync(binary,
0o755) throws, catch the error, then check the file's current mode
(fs.statSync(binary).mode & 0o111) to see if it is already executable and simply
return if so, otherwise log a warning (e.g. console.warn with the binary path
and error message) and continue without throwing; keep the platform check and
references to ensureLinuxSidecarExecutable and binary 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 Plus

Run ID: 4c5659e5-41be-4265-8b61-7576714278c3

📥 Commits

Reviewing files that changed from the base of the PR and between 9e20400 and 9f33bd8.

⛔ Files ignored due to path filters (8)
  • packages/desktop/icons/128x128.png is excluded by !**/*.png
  • packages/desktop/icons/16x16.png is excluded by !**/*.png
  • packages/desktop/icons/256x256.png is excluded by !**/*.png
  • packages/desktop/icons/32x32.png is excluded by !**/*.png
  • packages/desktop/icons/48x48.png is excluded by !**/*.png
  • packages/desktop/icons/512x512.png is excluded by !**/*.png
  • packages/desktop/icons/64x64.png is excluded by !**/*.png
  • packages/desktop/icons/icon.png is excluded by !**/*.png
📒 Files selected for processing (35)
  • .agents/skills/db/SKILL.md
  • .agents/skills/migration-safety/SKILL.md
  • .claude/skills/migration-safety/SKILL.md
  • .github/workflows/desktop-release.yml
  • CLAUDE.md
  • packages/claude-agent-sdk-rs/src/discovery.rs
  • packages/claude-agent-sdk-rs/src/lib.rs
  • packages/claude-agent-sdk-rs/src/query/metadata.rs
  • packages/claude-agent-sdk-rs/src/query/spawn.rs
  • packages/claude-agent-sdk-rs/src/transport.rs
  • packages/codex-app-server-sdk-rs/src/discovery.rs
  • packages/desktop/build/after-pack.cjs
  • packages/desktop/electron-builder.local.yml
  • packages/desktop/electron-builder.yml
  • packages/desktop/electron/main/app-paths.test.ts
  • packages/desktop/electron/main/app-paths.ts
  • packages/desktop/electron/main/index.ts
  • packages/desktop/electron/main/linux-install-type.test.ts
  • packages/desktop/electron/main/linux-install-type.ts
  • packages/desktop/electron/main/sidecar.test.ts
  • packages/desktop/electron/main/sidecar.ts
  • packages/desktop/electron/main/updater.ts
  • packages/desktop/electron/preload/index.ts
  • packages/desktop/src/lib/desktop-bridge.ts
  • packages/desktop/src/routes/settings.tsx
  • packages/desktop/src/stores/update-store.ts
  • packages/opencode-sdk-rs/src/process.rs
  • packages/service/src/domain/git/commands/worktree_ops.rs
  • packages/service/src/domain/workflow/worktree/reuse.rs
  • packages/service/src/shared/app_paths.rs
  • packages/service/src/shared/login_env.rs
  • packages/service/src/shared/mod.rs
  • packages/service/src/shared/worktree_paths.rs
  • packages/service/tests/common/worktree.rs
  • packages/service/tests/feature_worktree_test.rs

Comment thread .github/workflows/desktop-release.yml
Comment thread .github/workflows/desktop-release.yml
Comment thread packages/claude-agent-sdk-rs/src/discovery.rs Outdated
Comment thread packages/desktop/electron/main/sidecar.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/claude-agent-sdk-rs/src/discovery.rs (1)

134-155: 💤 Low value

Consider renaming this test to reflect its actual contract.

The test name find_cli_returns_searched_dirs_on_not_found implies it always exercises the CliNotFound path, but as the new comment explains, it can return Ok(_) when a real claude binary exists. A name like find_cli_reports_searched_dirs_when_cli_not_found or splitting into two tests (one with a mock that guarantees no binary) would make the intent clearer.

The detailed comment is helpful, but the test effectively becomes a no-op on systems with claude installed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/claude-agent-sdk-rs/src/discovery.rs` around lines 134 - 155, The
test name find_cli_returns_searched_dirs_on_not_found is misleading because the
test can succeed with Ok(_) on systems that have a real claude binary; rename
the test function to something that reflects the conditional assertion (e.g.,
find_cli_reports_searched_dirs_when_cli_not_found) or split into two tests: one
deterministic unit test that mocks/resolves find_cli to produce
Err(SdkError::CliNotFound { searched }) and asserts searched is non-empty, and
another integration-style test that allows Ok(_) to pass; update the test
function name and/or add a mock-based test so the contract around
SdkError::CliNotFound and the searched list is explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/claude-agent-sdk-rs/src/discovery.rs`:
- Around line 134-155: The test name find_cli_returns_searched_dirs_on_not_found
is misleading because the test can succeed with Ok(_) on systems that have a
real claude binary; rename the test function to something that reflects the
conditional assertion (e.g., find_cli_reports_searched_dirs_when_cli_not_found)
or split into two tests: one deterministic unit test that mocks/resolves
find_cli to produce Err(SdkError::CliNotFound { searched }) and asserts searched
is non-empty, and another integration-style test that allows Ok(_) to pass;
update the test function name and/or add a mock-based test so the contract
around SdkError::CliNotFound and the searched list is explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 406980ab-aac7-4c88-b6a5-9984b240bc66

📥 Commits

Reviewing files that changed from the base of the PR and between 036255b and b471ef5.

📒 Files selected for processing (4)
  • .github/workflows/desktop-release.yml
  • packages/claude-agent-sdk-rs/src/discovery.rs
  • packages/desktop/electron/main/sidecar.test.ts
  • packages/desktop/electron/main/sidecar.ts

@rle-mino
rle-mino force-pushed the feature/linux-compatibility-plan-491e branch from b471ef5 to d99a9eb Compare June 6, 2026 16:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/desktop-release.yml:
- Around line 171-203: The workflow step named "Smoke-test .deb on debian:12 and
.rpm on fedora:40" validates DEB and RPM but omits the built AppImage; add an
AppImage smoke test by locating the AppImage (e.g., APPIMAGE="$(ls *.AppImage |
head -n1)" under packages/desktop/dist-electron), ensure it is executable, and
run a non-invasive check like APPIMAGE --help or --version inside a container
(similar to the docker run blocks used for DEB/RPM) to verify the
updater-enabled Linux artifact actually runs and retains +x before publishing.
🪄 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 Plus

Run ID: 2db5c2f8-69ac-4771-abb4-13d40614b57d

📥 Commits

Reviewing files that changed from the base of the PR and between b471ef5 and d99a9eb.

⛔ Files ignored due to path filters (8)
  • packages/desktop/icons/128x128.png is excluded by !**/*.png
  • packages/desktop/icons/16x16.png is excluded by !**/*.png
  • packages/desktop/icons/256x256.png is excluded by !**/*.png
  • packages/desktop/icons/32x32.png is excluded by !**/*.png
  • packages/desktop/icons/48x48.png is excluded by !**/*.png
  • packages/desktop/icons/512x512.png is excluded by !**/*.png
  • packages/desktop/icons/64x64.png is excluded by !**/*.png
  • packages/desktop/icons/icon.png is excluded by !**/*.png
📒 Files selected for processing (23)
  • .agents/skills/db/SKILL.md
  • .agents/skills/migration-safety/SKILL.md
  • .claude/skills/migration-safety/SKILL.md
  • .github/workflows/desktop-release.yml
  • CLAUDE.md
  • packages/claude-agent-sdk-rs/src/discovery.rs
  • packages/claude-agent-sdk-rs/src/lib.rs
  • packages/claude-agent-sdk-rs/src/query/metadata.rs
  • packages/claude-agent-sdk-rs/src/query/spawn.rs
  • packages/claude-agent-sdk-rs/src/transport.rs
  • packages/codex-app-server-sdk-rs/src/discovery.rs
  • packages/desktop/build/after-pack.cjs
  • packages/desktop/electron-builder.local.yml
  • packages/desktop/electron-builder.yml
  • packages/desktop/electron/main/app-paths.test.ts
  • packages/desktop/electron/main/app-paths.ts
  • packages/desktop/electron/main/index.ts
  • packages/desktop/electron/main/linux-install-type.test.ts
  • packages/desktop/electron/main/linux-install-type.ts
  • packages/desktop/electron/main/sidecar.test.ts
  • packages/desktop/electron/main/sidecar.ts
  • packages/desktop/electron/main/updater.ts
  • packages/desktop/electron/preload/index.ts
✅ Files skipped from review due to trivial changes (6)
  • .agents/skills/migration-safety/SKILL.md
  • packages/claude-agent-sdk-rs/src/query/metadata.rs
  • .claude/skills/migration-safety/SKILL.md
  • packages/desktop/electron-builder.local.yml
  • packages/claude-agent-sdk-rs/src/query/spawn.rs
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (12)
  • .agents/skills/db/SKILL.md
  • packages/desktop/electron-builder.yml
  • packages/codex-app-server-sdk-rs/src/discovery.rs
  • packages/desktop/electron/main/index.ts
  • packages/desktop/build/after-pack.cjs
  • packages/desktop/electron/main/sidecar.test.ts
  • packages/desktop/electron/main/app-paths.test.ts
  • packages/desktop/electron/main/linux-install-type.test.ts
  • packages/desktop/electron/main/app-paths.ts
  • packages/claude-agent-sdk-rs/src/transport.rs
  • packages/desktop/electron/main/updater.ts
  • packages/claude-agent-sdk-rs/src/discovery.rs

Comment thread .github/workflows/desktop-release.yml Outdated
@rle-mino
rle-mino force-pushed the feature/linux-compatibility-plan-491e branch from ba59636 to 534be4b Compare June 29, 2026 17:02
rle-mino added 16 commits July 19, 2026 13:43
Build and publish AppImage artifacts from the desktop release workflow so Linux users can launch Cadencr from a single packaged binary.

The release workflow now prepares a draft once, uploads macOS and Linux artifacts through a matrix build, and publishes only after both build legs complete.
Hydrate Linux GUI launch environments from the user's login shell so local agent CLIs remain discoverable outside terminal launches.

Add common Linux install locations to provider discovery specs while preserving provider-neutral boundaries.
Phase 2 of Linux support. On Linux, Cadencr now stores data under
$XDG_DATA_HOME/cadencr (default ~/.local/share/cadencr), config under
$XDG_CONFIG_HOME/cadencr, and cache under $XDG_CACHE_HOME/cadencr — the
locations packagers, distros, and sandbox tooling expect. macOS keeps
the legacy ~/.cadencr/... layout bit-for-bit, so existing installs and
the db/migration skills keep working with no migration.

Introduces a single seam in each runtime so future callers don't reach
for dirs::home_dir() directly:
  - packages/service/src/shared/app_paths.rs (Rust)
  - packages/desktop/electron/main/app-paths.ts (Electron main)

Both helpers route the production DB path, the worktrees root, and the
logs directory through one macOS-or-XDG resolver. The existing
worktree_paths and sidecar callsites now delegate to them; the
integration tests' HomeGuard also clears the XDG vars so Linux runs
get a predictable tempdir layout.
…type

Phase 3 of Linux compatibility. CI now produces .AppImage, .deb, and .rpm
artifacts per release; the in-app auto-updater stays active only on
AppImage installs and surfaces a "managed by your package manager" hint
on deb/rpm/unknown installs instead of silently no-op'ing.

- electron-builder.yml / .local.yml: add deb + rpm targets with pinned
  depends lists (default electron-builder deps can drift between
  releases; pinning keeps Ubuntu/Fedora installability predictable).
- desktop-release.yml: install `rpm` on ubuntu-latest so rpmbuild is
  available; rename the Linux build step.
- after-pack.cjs: comment clarifying the sidecar chmod propagates to
  deb/rpm because afterPack runs once before any target packager.
- linux-install-type.ts (+ test): detect install type from $APPIMAGE
  and /etc/os-release ID/ID_LIKE; returns the apt/dnf upgrade command.
- updater.ts: new `update:unsupported` IPC channel; check / install
  handlers and the startup announce skip electron-updater entirely on
  deb/rpm/unknown installs. Tracks the announce timeout so
  shutdownAutoUpdater can cancel it on fast quit.
- preload + desktop-bridge + update-store: thread the new event
  through, add `"unsupported"` status with the package-manager message.
- settings.tsx: About button reads "Managed by package manager",
  disabled, with the distro-specific upgrade command as tooltip + a11y
  status line — never silently no-ops, per error-handling.md.
- H1: namespace macOS config/cache under ~/.cadencr/{config,cache} so
  future callers can't collide on a shared filename. Data stays at the
  legacy root — moving it would orphan existing installs.
- H2: surface productionDbPath mkdir failures with the resolved path,
  rather than leaking a raw EACCES from Node.
- H3: smoke-install the produced .deb (debian:12) and .rpm (fedora:40)
  in CI and run `cadencr-service --help` to validate both the depends
  lists and that the sidecar keeps its +x bit through dpkg/rpm.
- M1: move .cargo/bin to the end of the well_known relative-to-home
  lists in claude-agent-sdk-rs and codex-app-server-sdk-rs to match
  the original ordering convention.
- M3: switch the Rust Linux app_paths tests to tempfile::tempdir()
  instead of hardcoded /tmp paths to remove cross-binary races.
- sidecar chmod (critical): skip the chmod when the binary is already
  executable, and re-check the X bit on EPERM/EROFS/EACCES before
  throwing. dpkg/rpm install the sidecar into a root-owned, read-only
  /opt/Cadencr/resources/, so the previous unconditional chmod would
  hard-fail startup for every .deb/.rpm user even though the bit was
  already set. AppImage and dev paths still get the chmod they need.
- Workflow hardening: add persist-credentials: false to all three
  actions/checkout steps so the GITHUB_TOKEN doesn't linger in
  .git/config — we only ever use gh with an explicit GH_TOKEN env.
- Gate the build job to refs/tags/ so a branch workflow_dispatch can't
  fire electron-builder --publish always (which uploads to the
  configured GitHub draft release).
- Document why find_cli_returns_searched_dirs_on_not_found can't assert
  panic-on-Ok — find_cli intentionally falls back from a bogus override
  to PATH/login-shell/well-known discovery, so any host with a
  resolvable `claude` binary hits the Ok arm legitimately.
Build local Linux packages from the production Electron Builder config so
local testing uses the same package metadata and artifact names as release
builds. Install the generated Debian package after successful local builds to
make repeated Ubuntu testing one command.
Capture the Linux package strategy, AppImage caveats, and installer checklist
so the future one-line installer can build on the compatibility work already
validated locally.
Bind the Cadencr service listener before expensive startup work so dev startup stops immediately when the configured port is already in use.
Replace the native Linux window frame with app-owned controls so the header can reserve space and avoid overlap with feature actions.
Use Ctrl+Shift+C/V for terminal copy and paste on Linux without stealing Ctrl+C from the PTY. Add native clipboard IPC so terminal paste works reliably from the Electron renderer.
Replace macOS-only Cmd glyphs in shortcut labels with platform-aware formatting and tune Ctrl/Shift key badge alignment for Linux.
@rle-mino
rle-mino force-pushed the feature/linux-compatibility-plan-491e branch from 6286123 to 0b94b68 Compare July 19, 2026 12:13
@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

Safe to merge. The XDG path helpers are mirrored and tested in both Rust and TypeScript, macOS paths are unchanged, and all three previously flagged concerns have been addressed in this revision.

The XDG path layer, install-type detector, and CI restructuring are all well-tested and internally consistent. The remaining observations are minor: the upload-count guard threshold is one below the actual artifact count, and one Linux distro-detection token is misleading in isolation but harmless in practice.

.github/workflows/desktop-release.yml — the upload-count guard (< 4) and unguarded macOS sidecar-check steps are worth a second look before the first Linux release tag fires.

Important Files Changed

Filename Overview
.github/workflows/desktop-release.yml Refactored into prepare-release / build (matrix) / publish-release stages; adds Ubuntu leg, Docker smoke tests, Linux asset upload and verification. Minor: upload-count guard is < 4 but 5 artifacts are expected; macOS-only scripts run unguarded on the Ubuntu leg.
packages/desktop/electron/main/linux-install-type.ts New module detecting AppImage vs deb/rpm vs unknown via APPIMAGE env and /etc/os-release. SUSE correctly uses zypper message. Minor: mint token won't match ID=linuxmint; Mint is caught via ID_LIKE in practice.
packages/desktop/electron/main/app-paths.ts New XDG-aware path resolver. Correctly preserves macOS legacy layout, validates non-absolute XDG values per spec, and mirrors the Rust implementation. Well-tested.
packages/service/src/shared/app_paths.rs New Rust mirror of the TS path resolver. Uses dirs crate for XDG on Linux, hard-codes legacy ~/.cadencr layout on macOS. Platform-gated unit tests confirm both data-dir and XDG override behaviour.
packages/desktop/electron/main/updater.ts Adds Linux deb/rpm update-suppression path. Correctly sends update:unsupported at init and on every explicit check, clears the deferred timeout in shutdownAutoUpdater, and caches the result after one /etc/os-release read.
packages/desktop/electron/main/sidecar.ts Switches database/settings paths to XDG-aware helpers. resolveSettingsDir correctly routes Linux to $XDG_CONFIG_HOME/cadencr/settings and preserves the macOS legacy layout.
packages/desktop/electron/main/sidecar-executable.ts New helper ensuring the Linux sidecar is executable, tolerating EPERM/EROFS/EACCES when the bit is already set (e.g. root-owned deb/rpm installs). Well-tested.
packages/desktop/build/after-pack.cjs Adds a Linux after-pack hook that chmods the sidecar to 0o755 before AppImage/deb/rpm packagers consume the app directory.
packages/desktop/electron-builder.yml Adds Linux AppImage/deb/rpm targets with explicit depends lists for both deb and rpm (including gtk3, libXtst, at-spi2-atk, mesa-libgbm, libxkbcommon).
packages/desktop/src/stores/update-store.ts Adds unsupported status and unsupportedMessage field. Idempotent applyEvent case short-circuits Zustand re-renders when the same payload arrives multiple times.
packages/service/src/shared/login_env.rs Extends login-shell PATH hydration from macOS-only to macOS+Linux, with a platform-appropriate fallback shell (/bin/bash on Linux). Well-commented and test-covered.

Reviews (3): Last reviewed commit: "Use zypper for openSUSE update guidance" | Re-trigger Greptile

Comment thread packages/desktop/electron-builder.yml
Comment thread packages/desktop/electron/main/sidecar.ts Outdated
Comment thread .github/workflows/desktop-release.yml
Comment thread packages/desktop/electron/main/linux-install-type.ts Outdated
@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown

Too many files changed for review. (104 files found, 100 file limit)

Bypass the limit by tagging @greptile-apps to review.

rle-mino added 3 commits July 19, 2026 17:41
Use Electron's X11 compatibility backend by default on Linux to prevent
Wayland WebContentsView scroll drift while preserving explicit overrides.
Handle continuous debounced writes so live Git data stays fresh, while
coalescing queued recomputes to keep sustained churn bounded.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant