feat(linux): add native window frame and pacman packaging

On Linux, `titleBarStyle: 'hidden'` removes the title bar entirely,
leaving no window controls (close/minimize/maximize). macOS has traffic
lights and Windows has a custom title bar component, but Linux gets
nothing. Fix this by omitting the hidden title bar style on Linux,
which gives native window decorations from the desktop environment
(GNOME, KDE, Hyprland, etc.).

Also adds Linux build support:
- electron-builder `linux` config targeting pacman (.pkg.tar.zst)
- `dist:linux` script for standalone Linux builds
- `release-linux` CI job on ubuntu-latest
- `dist` script updated to include --linux
This commit is contained in:
Jeremy Bornstein 2026-02-14 11:14:35 +11:00
parent 834b736af1
commit 50d5b922b6
4 changed files with 856 additions and 30 deletions

View file

@ -153,3 +153,53 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: pnpm dist:win
release-linux:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download dist artifact
uses: actions/download-artifact@v4
with:
name: dist
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- name: Setup Python for node-gyp
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Set version from tag
if: startsWith(github.ref, 'refs/tags/v')
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
pnpm pkg set version="$VERSION"
- name: Build app (Linux)
run: pnpm build
- name: Verify packaged inputs (Linux)
run: |
test -f dist-electron/main/index.cjs
test -f dist-electron/preload/index.js
test -f out/renderer/index.html
- name: Package & Release (Linux)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: pnpm dist:linux

View file

@ -17,9 +17,10 @@
"scripts": {
"dev": "electron-vite dev",
"build": "electron-vite build",
"dist": "electron-builder --mac --win",
"dist": "electron-builder --mac --win --linux",
"dist:mac": "electron-builder --mac --publish always",
"dist:win": "electron-builder --win --publish always",
"dist:linux": "electron-builder --linux --publish always",
"preview": "electron-vite preview",
"typecheck": "tsc --noEmit",
"lint": "eslint src/",
@ -150,6 +151,13 @@
],
"icon": "resources/icons/win/icon.ico"
},
"linux": {
"target": [
"pacman"
],
"icon": "resources/icons/png",
"category": "Development"
},
"nsis": {
"oneClick": false,
"perMachine": false,

File diff suppressed because it is too large Load diff

View file

@ -28,7 +28,10 @@ const getWindowIconPath = (): string | undefined => {
const isDev = process.env.NODE_ENV === 'development';
const candidates = isDev
? [join(process.cwd(), 'resources/icon.png')]
: [join(process.resourcesPath, 'resources/icon.png'), join(__dirname, '../../resources/icon.png')];
: [
join(process.resourcesPath, 'resources/icon.png'),
join(__dirname, '../../resources/icon.png'),
];
for (const candidate of candidates) {
if (existsSync(candidate)) {
@ -363,6 +366,7 @@ function syncTrafficLightPosition(win: BrowserWindow): void {
*/
function createWindow(): void {
const isMac = process.platform === 'darwin';
const isLinux = process.platform === 'linux';
const iconPath = isMac ? undefined : getWindowIconPath();
mainWindow = new BrowserWindow({
width: DEFAULT_WINDOW_WIDTH,
@ -374,7 +378,7 @@ function createWindow(): void {
contextIsolation: true,
},
backgroundColor: '#1a1a1a',
titleBarStyle: 'hidden',
...(isLinux ? {} : { titleBarStyle: 'hidden' as const }),
...(isMac && { trafficLightPosition: getTrafficLightPositionForZoom(1) }),
title: 'claude-devtools',
});