Skip to content

Fix desktop native optional dependency packaging#3816

Merged
juliusmarminge merged 1 commit into
pingdotgg:mainfrom
Prgm-code:agent/fix-desktop-native-optional-deps
Jul 9, 2026
Merged

Fix desktop native optional dependency packaging#3816
juliusmarminge merged 1 commit into
pingdotgg:mainfrom
Prgm-code:agent/fix-desktop-native-optional-deps

Conversation

@Prgm-code

@Prgm-code Prgm-code commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes desktop packaging regressions where nightly Linux and Windows builds could ship ffi-rs without the platform-native optional @yuuang/ffi-rs-* binding required at runtime.

Covered issues:

Problem

Recent nightly desktop builds started failing during backend startup because the packaged app included ffi-rs, but did not include the native optional dependency that ffi-rs loads for the current platform.

On Linux AppImage builds, the backend crashed with:

Cannot find module '@yuuang/ffi-rs-linux-x64-gnu'

On Windows builds, affected users saw the app never render a window. The server child process was crash-looping with:

Cannot find module '@yuuang/ffi-rs-win32-x64-msvc'

Both failures happen before the desktop backend can become ready, so the UI either shows a generic Electron process error or never opens.

Root Cause

There were two related packaging gaps.

Linux AppImage

The staged production pnpm-workspace.yaml declared the target os and cpu, but did not declare libc.

Packages such as @yuuang/ffi-rs-linux-x64-gnu are optional dependencies with:

{
  "os": ["linux"],
  "cpu": ["x64"],
  "libc": ["glibc"]
}

Without libc: ["glibc"], pnpm could skip that optional native package during the staged production install, leaving ffi-rs present but unable to resolve its Linux binding.

Windows

The Windows stage already requested the right target architectures, including Windows and Linux/glibc for WSL. However, Electron Builder was detecting the staged app as an npm project when collecting node_modules.

Because the staged install uses pnpm, npm-style collection can miss optional dependency subtrees from the pnpm layout. That caused the Windows artifact to omit packages like:

@yuuang/ffi-rs-win32-x64-msvc

The fix explicitly passes a pnpm user agent to Electron Builder so it uses the pnpm collector for the staged app.

Changes

  • Add libc: ["glibc"] to Linux desktop staging architecture metadata.
  • Keep Windows staging behavior for host Windows plus Linux/glibc WSL backend.
  • Add resolvePackageManagerUserAgent() to convert packageManager syntax:
pnpm@11.10.0

into npm user-agent syntax:

pnpm/11.10.0
  • Set buildEnv.npm_config_user_agent before invoking Electron Builder.
  • Add tests for Linux staging architecture metadata and packageManager-to-user-agent conversion.

Validation

Commands run:

vp test run scripts/build-desktop-artifact.test.ts
vp check
vp run typecheck

Local artifacts generated for verification:

node scripts/build-desktop-artifact.ts --platform linux --target AppImage --arch x64 --build-version 0.0.29-nightly.20260708.999 --output-dir release-test

node scripts/build-desktop-artifact.ts --platform win --target nsis --arch x64 --build-version 0.0.29-nightly.20260708.999 --output-dir release-test --skip-build

Artifact inspection confirmed:

  • Linux AppImage includes:
resources/app.asar.unpacked/node_modules/@yuuang/ffi-rs-linux-x64-gnu/ffi-rs.linux-x64-gnu.node
  • Windows installer includes:
resources/app.asar.unpacked/node_modules/@yuuang/ffi-rs-win32-x64-msvc/ffi-rs.win32-x64-msvc.node

Note: the local Windows installer was generated without T3CODE_DESKTOP_WSL_PREBUILD, so it validates the primary Windows backend packaging path and the missing ffi-rs binding, but not the WSL backend binary path.

Note

Fix desktop native optional dependency packaging for Linux and package manager user agent

  • Adds libc: ["glibc"] to supportedArchitectures in createStageWorkspaceConfig for Linux builds in build-desktop-artifact.ts, ensuring native optional dependencies targeting glibc are included during staged production installs.
  • Introduces resolvePackageManagerUserAgent, which converts a package.json packageManager field (e.g. pnpm@11.10.0) to a user-agent string (pnpm/11.10.0) for use by electron-builder.
  • Sets npm_config_user_agent in the electron-builder environment using the derived user agent before the env-scrubbing step.

Macroscope summarized 6d0d98e.


Note

Medium Risk
Changes only desktop packaging scripts but affect runtime-critical native modules; mis-staging would still break backend startup on Linux/Windows without obvious compile-time failures.

Overview
Fixes desktop builds shipping ffi-rs without the platform-specific @yuuang/ffi-rs-* optional bindings, which caused Linux AppImage and Windows backend crash-loops (Cannot find module '@yuuang/ffi-rs-…').

Linux staging: createStageWorkspaceConfig now sets libc: ["glibc"] for Linux targets (not only Windows), so staged pnpm install --prod resolves glibc-scoped optional natives like @yuuang/ffi-rs-linux-x64-gnu.

Electron Builder / Windows: Adds resolvePackageManagerUserAgent() to map root packageManager (pnpm@11.10.0) to npm_config_user_agent form (pnpm/11.10.0), and sets that on the electron-builder env so collection uses the pnpm layout and optional Windows bindings (e.g. @yuuang/ffi-rs-win32-x64-msvc) are not dropped.

Tests cover Linux workspace supportedArchitectures (including libc in full yaml fixtures) and user-agent conversion.

Reviewed by Cursor Bugbot for commit 6d0d98e. Bugbot is set up for automated code reviews on this repo. Configure here.

Ensure Linux AppImage staging declares glibc so pnpm installs Linux native optional dependencies such as @yuuang/ffi-rs-linux-x64-gnu.

Pass a pnpm npm_config_user_agent to Electron Builder so its node_modules collector uses the pnpm layout instead of falling back to npm and dropping Windows optional native packages such as @yuuang/ffi-rs-win32-x64-msvc.

Add coverage for Linux staging architecture metadata and packageManager-to-user-agent conversion.
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d74879ae-9eee-41bb-bcf3-aeaf77736fca

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 8, 2026
@Prgm-code
Prgm-code marked this pull request as ready for review July 8, 2026 20:17
@macroscopeapp

macroscopeapp Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved

Build script bug fix that adds missing libc: ["glibc"] configuration for Linux desktop builds and a utility function for electron-builder package manager detection. Changes are limited to packaging scripts with good test coverage.

You can customize Macroscope's approvability policy. Learn more.

@phillip-hirsch

Copy link
Copy Markdown

Also seeing this on MacOS chipsets (SEE: Discord Thread):

ARM: Error: Cannot find module '@yuuang/ffi-rs-darwin-arm64'
Intel: Error: Cannot find module '@yuuang/ffi-rs-darwin-x64'

@avocardow

Copy link
Copy Markdown
Contributor

Can confirm the npm_config_user_agent change fixes the macOS arm64 case too (#3804). Traced it independently before finding this PR.

Electron-builder detects pnpm fine at first (staged package.json packageManager field), but then resolves the workspace root via pnpm --workspace-root exec pwd and uses the raw stdout as a path. In the freshly staged app pnpm 11 prepends install/verify output, so the "root" comes back as:

? Verifying lockfile against supply-chain policies (372 entries)...
Lockfile is up to date, resolution step is skipped
...
Done in 2.2s using pnpm v11.10.0
/private/var/folders/.../t3code-desktop-mac-stage-xxx/app

Re-detection at that "path" finds nothing -> falls back to npm_config_user_agent -> unset under vp exec -> npm. The npm collector walks the pnpm tree and silently drops optional dep subtrees. @yuuang/ffi-rs-darwin-arm64, @anthropic-ai/claude-agent-sdk-darwin-arm64, @clerk/electron-passkeys-darwin-arm64, @msgpackr-extract/msgpackr-extract-darwin-arm64, msgpackr-extract, detect-libc, node-gyp-build-optional-packages. (mac arm64)

A/B tested master vs master + the env var (only change): master collects 176 modules via the npm collector; with the var set the pnpm collector runs, 183 modules, all 7 back in the asar, app launches. So this fixes #3804 as well.

@juliusmarminge
juliusmarminge merged commit 18a4138 into pingdotgg:main Jul 9, 2026
20 checks passed
eyeveil pushed a commit to eyeveil/t3code that referenced this pull request Jul 9, 2026
eyeveil added a commit to eyeveil/t3code that referenced this pull request Jul 9, 2026
… + desktop packaging)

Merge upstream/main into the fork. Notable upstream changes: Clerk stack
upgrade (pingdotgg#3821), mobile offline persistence + preferences refactor (pingdotgg#3795),
mobile PR number badges + a11y (pingdotgg#3827, pingdotgg#3828), font embedding (pingdotgg#3823),
worktree metadata preservation during branch sync (pingdotgg#3822), codex reasoning
labels (pingdotgg#3824), desktop native optional dependency packaging (pingdotgg#3816).

Preserved fork features across conflicts: iOS personal-team build support,
Material3 dynamic accent theming, verbose work-log, mobile visible queue,
MarkdownCodeBlock, native Android composer/header layout, and the fork's
asar:false + afterPack/afterSign node_modules copy hooks for desktop packaging.
Lockfile regenerated on pnpm 11 (upstream lock as base).
adamfgr pushed a commit to agriffiths-bots/t3code that referenced this pull request Jul 10, 2026
* Fix desktop native optional dependency packaging (pingdotgg#3816)

* [codex] Upgrade Clerk stack (pingdotgg#3821)

Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Preserve worktree metadata during branch sync (pingdotgg#3822)

Co-authored-by: codex <codex@users.noreply.github.com>

* feat(client): persist offline environment data and mobile preferences (pingdotgg#3795)

Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Label max and ultra reasoning (pingdotgg#3824)

Co-authored-by: codex <codex@users.noreply.github.com>

* fix(mobile): embed fonts and render project favicons reliably (pingdotgg#3823)

Co-authored-by: codex <codex@users.noreply.github.com>

* Show compact PR number badges in mobile thread rows (pingdotgg#3827)

Co-authored-by: codex <codex@users.noreply.github.com>

* Expose mobile PR indicator labels to accessibility (pingdotgg#3828)

Co-authored-by: codex <codex@users.noreply.github.com>

* test(client-runtime): stub new EnvironmentCacheStore methods in shell-sync mocks

Upstream pingdotgg#3795 expanded the EnvironmentCacheStore interface with
loadServerConfig/saveServerConfig/loadVcsRefs/saveVcsRefs; add those
stubs to the fork-local shell-sync mock stores so typecheck passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(client-runtime): pass heartbeat opt-in from offline server-config subscription

Upstream pingdotgg#3795's makeEnvironmentServerConfigState subscribed to
subscribeServerConfig with {} instead of the fork-local shared
SERVER_CONFIG_SUBSCRIPTION_INPUT ({ supportsHeartbeat: true }). That
opts the quiet offline-persistence subscription out of the server's
keepalive frames (and diverges from the shared subscription key), so
idle transports/proxies could drop it and leave provider/model metadata
stale. Hoist the const above makeEnvironmentServerConfigState and pass
it at the subscription site so every consumer shares the same input.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Patricio Gómez Meneses <107218376+Prgm-code@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: wizzoapp[bot] <254688279+wizzoapp[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
tarik02 added a commit to tarik02/t3code that referenced this pull request Jul 13, 2026
* Add middle-click close for right panel tabs (pingdotgg#3161)

Co-authored-by: Julius Marminge <jmarminge@gmail.com>

* fix: warm WSL before preflight in WSL-only backend mode (pingdotgg#3588)

* Add Claude Sonnet 5 as the default Claude model (pingdotgg#3620)

* Restore the ultrathink frame border effect (pingdotgg#3625)

* fix(dev): Fix electron dev launch and add test (pingdotgg#3662)

* Add adaptive split-view layout for iPad/mobile workspace (pingdotgg#3514)

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* fix(mobile): compile patched native pods from source on EAS (pingdotgg#3667)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Make the thread composer read as elevated liquid glass (pingdotgg#3668)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Upgrade Vite Plus and enable bundled dev opt-in (pingdotgg#3679)

* Surface pending tasks in mobile home and draft flow (pingdotgg#3670)

* fix(mobile): combined test branch — scroll, back-swipe, thread lists, computer switching (pingdotgg#3687)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Add repo-root favicon.svg so t3 code shows its own icon (pingdotgg#3683)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Load thread snapshots over HTTP before live sync (pingdotgg#3719)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Fix mobile legend anchor under automatic iOS insets (pingdotgg#3684)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Improve live activity routing and diagnostics (pingdotgg#3685)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Prevent Add Project sheet from collapsing on relayout (pingdotgg#3759)

* Use variant-specific splash icons in mobile app (pingdotgg#3762)

* Fix Expo widget asset wiring order (pingdotgg#3763)

* Extend Done display to 15 minutes and show up to 5 Live Activity banner rows (pingdotgg#3761)

* Clear VCS presentation state on finish (pingdotgg#3764)

* Lead with the outcome when no agents are active in the Live Activity (pingdotgg#3768)

* Add T3 Connect onboarding for mobile and web (pingdotgg#3765)

* Revert "Add T3 Connect onboarding for mobile and web" (pingdotgg#3776)

* Expose Clerk Google sign-in env vars to Expo (pingdotgg#3772)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Set up Cursor Cloud dev environment (web + Android toolchain) (pingdotgg#3755)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* Revert "Revert "Add T3 Connect onboarding for mobile and web"" (pingdotgg#3777)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Use rounded depth logo for production splash screen (pingdotgg#3780)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* fix(release): stage pnpm 11 allowBuilds for desktop installs (pingdotgg#3781)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* Upgrade Clerk toolchain to latest versions (pingdotgg#3785)

* fix(release): bump electron-builder so pnpm 11 deduped deps land in the asar (pingdotgg#3790)

* Fix desktop native optional dependency packaging (pingdotgg#3816)

* [codex] Upgrade Clerk stack (pingdotgg#3821)

Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Preserve worktree metadata during branch sync (pingdotgg#3822)

Co-authored-by: codex <codex@users.noreply.github.com>

* feat(client): persist offline environment data and mobile preferences (pingdotgg#3795)

Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>

* [codex] Label max and ultra reasoning (pingdotgg#3824)

Co-authored-by: codex <codex@users.noreply.github.com>

* fix(mobile): embed fonts and render project favicons reliably (pingdotgg#3823)

Co-authored-by: codex <codex@users.noreply.github.com>

* Show compact PR number badges in mobile thread rows (pingdotgg#3827)

Co-authored-by: codex <codex@users.noreply.github.com>

* Expose mobile PR indicator labels to accessibility (pingdotgg#3828)

Co-authored-by: codex <codex@users.noreply.github.com>

* Fix truncated chat error alert layout (pingdotgg#3899)

* fix(marketing): show platform-appropriate commit shortcut on the website (pingdotgg#3644)

* [codex] Add Android mobile support (pingdotgg#3579)

Co-authored-by: Horus Lugo <horusgoul@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: maria-rcks <maria@kuuro.net>
Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com>
Co-authored-by: Alex <me@pixp.cc>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>

---------

Co-authored-by: Hugo Blom <6117705+huxcrux@users.noreply.github.com>
Co-authored-by: Julius Marminge <jmarminge@gmail.com>
Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>
Co-authored-by: Rowan <rowan@cardow.co>
Co-authored-by: Patricio Gómez Meneses <107218376+Prgm-code@users.noreply.github.com>
Co-authored-by: Jake Leventhal <jakeleventhal@me.com>
Co-authored-by: Vedank Purohit <VedankPurohit2@gmail.com>
Co-authored-by: Horus Lugo <horusgoul@gmail.com>
Co-authored-by: maria-rcks <maria@kuuro.net>
Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com>
Co-authored-by: Alex <me@pixp.cc>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

4 participants