Skip to content

Commit 81d608f

Browse files
committed
feat: cross-platform release (macOS dmg + Linux AppImage)
- Regenerate icon.icns from V13 Tally PNGs via png2icons (pure-JS, runs on any CI host — no Apple toolchain required) - Emit assets/icon.png (1024 px) for Linux AppImage; electron-builder expands it into freedesktop hicolor sizes at pack time - electron-builder.json linux.icon: .icns → .png - package.json: add dist:linux script (--publish never), bump 0.4.0 - .github/workflows/release.yml: rename job to neutral "Release" and add macos (dmg x64+arm64) + linux (AppImage) jobs, each uploading artifacts + attaching to the same GitHub Release
1 parent bbc3e0c commit 81d608f

7 files changed

Lines changed: 124 additions & 4 deletions

File tree

.github/workflows/release.yml

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
name: Release (Windows)
1+
name: Release
22

3-
# Push a tag like `v0.1.0` to build and publish a Windows release.
3+
# Push a tag like `v0.1.0` to build and publish a cross-platform release
4+
# (Windows NSIS + portable, macOS dmg x64/arm64, Linux AppImage).
45
# Can also be run manually from the Actions tab for dry runs.
56
on:
67
push:
@@ -74,3 +75,92 @@ jobs:
7475
prerelease: false
7576
generate_release_notes: true
7677
fail_on_unmatched_files: true
78+
79+
macos:
80+
runs-on: macos-latest
81+
steps:
82+
- name: Checkout
83+
uses: actions/checkout@v4
84+
85+
- name: Setup Node
86+
uses: actions/setup-node@v4
87+
with:
88+
node-version: '20'
89+
cache: 'npm'
90+
91+
- name: Install deps
92+
run: npm ci
93+
94+
- name: Build renderer + main
95+
run: npm run build
96+
97+
- name: Package macOS dmg (x64 + arm64)
98+
env:
99+
# Unsigned binaries — skip automatic cert discovery. Users will
100+
# see a Gatekeeper warning; that's acceptable for an open-source
101+
# hobby release.
102+
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
103+
run: npm run dist:mac
104+
105+
- name: Upload build artifacts
106+
uses: actions/upload-artifact@v4
107+
with:
108+
name: tokenwatch-macos-${{ github.sha }}
109+
path: |
110+
release/TokenWatch-*.dmg
111+
release/latest-mac.yml
112+
if-no-files-found: error
113+
114+
- name: Attach to GitHub Release
115+
if: startsWith(github.ref, 'refs/tags/v')
116+
uses: softprops/action-gh-release@v2
117+
with:
118+
files: |
119+
release/TokenWatch-*.dmg
120+
release/latest-mac.yml
121+
draft: false
122+
prerelease: false
123+
# generate_release_notes only needs to run on one job — the
124+
# windows job handles it; here we just append files.
125+
fail_on_unmatched_files: true
126+
127+
linux:
128+
runs-on: ubuntu-latest
129+
steps:
130+
- name: Checkout
131+
uses: actions/checkout@v4
132+
133+
- name: Setup Node
134+
uses: actions/setup-node@v4
135+
with:
136+
node-version: '20'
137+
cache: 'npm'
138+
139+
- name: Install deps
140+
run: npm ci
141+
142+
- name: Build renderer + main
143+
run: npm run build
144+
145+
- name: Package Linux AppImage
146+
run: npm run dist:linux
147+
148+
- name: Upload build artifacts
149+
uses: actions/upload-artifact@v4
150+
with:
151+
name: tokenwatch-linux-${{ github.sha }}
152+
path: |
153+
release/TokenWatch-*.AppImage
154+
release/latest-linux.yml
155+
if-no-files-found: error
156+
157+
- name: Attach to GitHub Release
158+
if: startsWith(github.ref, 'refs/tags/v')
159+
uses: softprops/action-gh-release@v2
160+
with:
161+
files: |
162+
release/TokenWatch-*.AppImage
163+
release/latest-linux.yml
164+
draft: false
165+
prerelease: false
166+
fail_on_unmatched_files: true

assets/icon.icns

-138 KB
Binary file not shown.

assets/icon.png

26.9 KB
Loading

electron-builder.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
},
7373
"linux": {
7474
"target": "AppImage",
75-
"icon": "assets/icon.icns",
75+
"icon": "assets/icon.png",
7676
"category": "Development"
7777
}
7878
}

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tokenwatch",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "TokenWatch — a warm, editorial tray app for real-time Claude Code usage tracking on Windows and macOS",
55
"main": "dist/main.js",
66
"scripts": {
@@ -12,6 +12,7 @@
1212
"dist": "npm run build && electron-builder",
1313
"dist:mac": "npm run build && electron-builder --mac --publish never",
1414
"dist:win": "npm run build && electron-builder --win --publish never",
15+
"dist:linux": "npm run build && electron-builder --linux --publish never",
1516
"make-ico": "node scripts/make-ico.mjs",
1617
"make-icons": "node scripts/make-icons.mjs",
1718
"lint": "biome lint ./src",
@@ -50,6 +51,7 @@
5051
"husky": "^9.1.7",
5152
"patch-package": "^8.0.1",
5253
"png-to-ico": "^3.0.1",
54+
"png2icons": "^2.0.1",
5355
"postcss-loader": "^8.2.0",
5456
"sharp": "^0.34.5",
5557
"style-loader": "^4.0.0",

scripts/make-icons.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'node:fs/promises';
22
import path from 'node:path';
33
import { fileURLToPath } from 'node:url';
4+
import png2icons from 'png2icons';
45
import pngToIco from 'png-to-ico';
56
import sharp from 'sharp';
67

@@ -12,6 +13,8 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
1213
const root = path.resolve(__dirname, '..');
1314
const iconset = path.join(root, 'assets', 'icon.iconset');
1415
const outIco = path.join(root, 'assets', 'icon.ico');
16+
const outIcns = path.join(root, 'assets', 'icon.icns');
17+
const outLinuxPng = path.join(root, 'assets', 'icon.png');
1518
const outTrayPng = path.join(root, 'assets', 'tray.png');
1619
const outTrayIco = path.join(root, 'assets', 'tray.ico');
1720

@@ -135,6 +138,20 @@ async function main() {
135138
const trayPngBuf = await fs.readFile(path.join(iconset, 'icon_32x32.png'));
136139
await fs.writeFile(outTrayPng, trayPngBuf);
137140
console.log(`Wrote ${outTrayPng}`);
141+
142+
// macOS .icns — derived from the 1024×1024 master PNG. png2icons bakes
143+
// in every size Finder / Dock needs. Pure JS, no native toolchain, so
144+
// this runs the same on Windows / Linux CI as it would on macOS.
145+
const masterPng = await fs.readFile(path.join(iconset, 'icon_1024x1024.png'));
146+
const icnsBuf = png2icons.createICNS(masterPng, png2icons.BILINEAR, 0);
147+
if (!icnsBuf) throw new Error('png2icons.createICNS returned null');
148+
await fs.writeFile(outIcns, icnsBuf);
149+
console.log(`Wrote ${outIcns} (${icnsBuf.length} bytes)`);
150+
151+
// Linux AppImage icon — electron-builder expands a single high-res PNG
152+
// into the required freedesktop hicolor sizes at packaging time.
153+
await fs.writeFile(outLinuxPng, masterPng);
154+
console.log(`Wrote ${outLinuxPng} (${masterPng.length} bytes)`);
138155
}
139156

140157
main().catch((err) => {

0 commit comments

Comments
 (0)