From 4c2803c994cc5278afe775f74ec2bfe5ac361417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 2 Oct 2026 12:29:33 +0100 Subject: [PATCH] feat(desktop): let distribution packages point at their own resources Distribution packages run the app on a shared Electron, whose process.resourcesPath is that Electron's own resources directory. The desktop app then looks there for the GNOME extension, the KDE and Hyprland capture helpers, the browser-secret helper and the resource monitor, and finds none of them. T3CODE_DESKTOP_RESOURCES_PATH lets the package name its own resources directory; unset, nothing changes. Assisted-By: Claude Opus 5.5 --- apps/desktop/src/app/DesktopConfig.ts | 1 + .../src/app/DesktopEnvironment.test.ts | 21 +++++++++++++++++++ apps/desktop/src/app/DesktopEnvironment.ts | 11 +++++++--- docs/operations/development.md | 6 ++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/app/DesktopConfig.ts b/apps/desktop/src/app/DesktopConfig.ts index 773ea24509cf..16e5c7c1a207 100644 --- a/apps/desktop/src/app/DesktopConfig.ts +++ b/apps/desktop/src/app/DesktopConfig.ts @@ -55,6 +55,7 @@ export const DesktopConfig = Config.all({ otlpProtocol: Config.schema(OtlpProtocol, "T3CODE_OTLP_PROTOCOL").pipe( Config.withDefault("http/json"), ), + resourcesPathOverride: trimmedString("T3CODE_DESKTOP_RESOURCES_PATH"), appImagePath: trimmedString("APPIMAGE"), disableAutoUpdate: optionalBoolean("T3CODE_DISABLE_AUTO_UPDATE"), mockUpdates: optionalBoolean("T3CODE_DESKTOP_MOCK_UPDATES"), diff --git a/apps/desktop/src/app/DesktopEnvironment.test.ts b/apps/desktop/src/app/DesktopEnvironment.test.ts index b5aabf253d0f..8f50e397f295 100644 --- a/apps/desktop/src/app/DesktopEnvironment.test.ts +++ b/apps/desktop/src/app/DesktopEnvironment.test.ts @@ -155,6 +155,27 @@ describe("DesktopEnvironment", () => { }), ); + it.effect("reads resources from a distribution package instead of the shared Electron", () => + Effect.gen(function* () { + const environment = yield* makeEnvironment( + { + platform: "linux", + isPackaged: true, + appPath: "/usr/lib/t3code/app.asar", + resourcesPath: "/usr/lib/electron44/resources", + }, + { T3CODE_DESKTOP_RESOURCES_PATH: " /usr/lib/t3code/resources " }, + ); + + assert.equal(environment.resourcesPath, "/usr/lib/t3code/resources"); + assert.equal(environment.appUpdateYmlPath, "/usr/lib/t3code/resources/app-update.yml"); + assert.include( + environment.resolveResourcePathCandidates("icon.png"), + "/usr/lib/t3code/resources/icon.png", + ); + }), + ); + it.effect("keeps implicit development state separate from production state", () => Effect.gen(function* () { const development = yield* makeEnvironment( diff --git a/apps/desktop/src/app/DesktopEnvironment.ts b/apps/desktop/src/app/DesktopEnvironment.ts index beb09bd50a46..ad1d4e1ba4ad 100644 --- a/apps/desktop/src/app/DesktopEnvironment.ts +++ b/apps/desktop/src/app/DesktopEnvironment.ts @@ -173,9 +173,16 @@ const make = Effect.fn("desktop.environment.make")(function* ( }); const rootDir = path.resolve(input.dirname, "../../.."); const appRoot = input.isPackaged ? input.appPath : rootDir; + // Electron places the resources directory next to its own executable. + // Distribution packages that run the app on a shared Electron keep the + // app's resources elsewhere and point here instead. + const resourcesPath = Option.match(config.resourcesPathOverride, { + onNone: () => input.resourcesPath, + onSome: (override) => path.resolve(override), + }); const serverRoot = input.isPackaged && input.platform === "win32" - ? path.join(input.resourcesPath, "server.asar") + ? path.join(resourcesPath, "server.asar") : appRoot; const branding = resolveDesktopAppBranding({ isDevelopment, @@ -194,8 +201,6 @@ const make = Effect.fn("desktop.environment.make")(function* ( Option.getOrElse(config.xdgDataHome, () => path.join(homeDirectory, ".local", "share")), "applications", ); - const resourcesPath = input.resourcesPath; - return DesktopEnvironment.of({ path, dirname: input.dirname, diff --git a/docs/operations/development.md b/docs/operations/development.md index b7e1b257d0b2..d1ef6c2aa3e0 100644 --- a/docs/operations/development.md +++ b/docs/operations/development.md @@ -143,6 +143,12 @@ DMGs default to the host architecture. Use `--arch` to choose another target and to retain packaging files for inspection. Run `vp run dist:desktop:artifact --help` for other options. +### Distribution packages + +Packages that run the app on a shared Electron, such as `electron /usr/lib/t3code/app.asar`, set +`T3CODE_DESKTOP_RESOURCES_PATH` to the directory holding the app's resources. Otherwise the app +looks in Electron's own resources directory and finds none of its helpers. + ### Linux AppImage prerequisites Build on Linux because the browser-secret helper links against the host's libsecret. Install