Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions scripts/build-desktop-artifact.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
resolveGitHubPublishConfig,
resolveMockUpdateServerPort,
resolveMockUpdateServerUrl,
resolvePackageManagerUserAgent,
stageLinuxIconSize,
STAGE_INSTALL_ARGS,
} from "./build-desktop-artifact.ts";
Expand Down Expand Up @@ -208,6 +209,13 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
cpu: ["x64"],
},
});
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "linux", arch: "x64" }), {
supportedArchitectures: {
os: ["linux"],
cpu: ["x64"],
libc: ["glibc"],
},
});
// Windows artifacts also bundle the same-architecture WSL (Linux, glibc) backend, so the
// staged install must fetch its native optional deps (e.g. ffi-rs) too.
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "win", arch: "x64" }), {
Expand Down Expand Up @@ -253,6 +261,7 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
supportedArchitectures: {
os: ["linux"],
cpu: ["x64"],
libc: ["glibc"],
},
allowBuilds: {
electron: true,
Expand Down Expand Up @@ -529,6 +538,12 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
assert.equal(resolveMockUpdateServerUrl(4123), "http://localhost:4123");
});

it("derives the electron-builder package manager user agent from packageManager", () => {
assert.equal(resolvePackageManagerUserAgent("pnpm@11.10.0"), "pnpm/11.10.0");
assert.equal(resolvePackageManagerUserAgent(" yarn@4.9.2 "), "yarn/4.9.2");
assert.equal(resolvePackageManagerUserAgent("pnpm"), "pnpm");
});

it.effect("normalizes mock update server ports from env-style strings", () =>
Effect.gen(function* () {
assert.equal(yield* resolveMockUpdateServerPort(undefined), undefined);
Expand Down
41 changes: 30 additions & 11 deletions scripts/build-desktop-artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -890,22 +890,27 @@ export function createStageWorkspaceConfig(input: {
const { platform, arch, allowBuilds, patchedDependencies, overrides } = input;
const hostOs = platform === "mac" ? "darwin" : platform === "win" ? "win32" : "linux";
const hostCpu = arch === "universal" ? ["arm64", "x64"] : [arch];
// Windows artifacts also bundle the same-architecture WSL Linux backend, which loads
// Linux-native optional deps at runtime (e.g. @yuuang/ffi-rs-linux-x64-gnu).
// Pull the Linux (glibc) variants in addition to the host platform's so
// they ship in the asar; without them the WSL backend crash-loops on require
// ("Cannot find module '@yuuang/ffi-rs-linux-x64-gnu'").
// Linux AppImages and Windows WSL backends both execute a Linux/glibc Node
// process that loads Linux-native optional deps at runtime (e.g.
// @yuuang/ffi-rs-linux-x64-gnu). Keep libc explicit so pnpm includes those
// optional packages in the staged production install.
const supportedArchitectures =
platform === "win"
platform === "linux"
? {
os: Array.from(new Set([hostOs, "linux"])),
os: [hostOs],
cpu: hostCpu,
libc: ["glibc"],
}
: {
os: [hostOs],
cpu: hostCpu,
};
: platform === "win"
? {
os: Array.from(new Set([hostOs, "linux"])),
cpu: hostCpu,
libc: ["glibc"],
}
: {
os: [hostOs],
cpu: hostCpu,
};

return {
supportedArchitectures,
Expand Down Expand Up @@ -1339,6 +1344,19 @@ export function resolveMockUpdateServerUrl(mockUpdateServerPort: number | undefi
return `http://localhost:${mockUpdateServerPort ?? 3000}`;
}

// Electron Builder detects pnpm from npm_config_user_agent, whose value uses
// user-agent syntax (pnpm/11.10.0) rather than packageManager syntax
// (pnpm@11.10.0).
export function resolvePackageManagerUserAgent(packageManager: string): string {
const trimmed = packageManager.trim();
const versionSeparator = trimmed.lastIndexOf("@");
if (versionSeparator <= 0 || versionSeparator === trimmed.length - 1) {
return trimmed;
}

return `${trimmed.slice(0, versionSeparator)}/${trimmed.slice(versionSeparator + 1)}`;
}

export function resolveDesktopProductName(version: string): string {
return resolveDesktopUpdateChannel(version) === "nightly"
? "T3 Code (Nightly)"
Expand Down Expand Up @@ -1799,6 +1817,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* (
const buildEnv: NodeJS.ProcessEnv = {
...process.env,
};
buildEnv.npm_config_user_agent = resolvePackageManagerUserAgent(rootPackageJson.packageManager);
for (const [key, value] of Object.entries(buildEnv)) {
if (value === "") {
delete buildEnv[key];
Expand Down
Loading