Add cross-platform packaging, icons, and Claude Code config discovery
- Auto-discovers Claude Code (~/.claude/settings.json) alongside Claude Desktop - Generated icons/app.icns (macOS) and icons/app.ico (Windows) from rounded PNGs - bcc.spec: PyInstaller spec for all platforms (.app on macOS, onefile on Windows/Linux) - .github/workflows/release.yml: builds and publishes GitHub Release on version tags - scripts/build_icons.py: regenerates icon files from source PNGs - requirements-dev.txt: adds pyinstaller and pillow for building - CLAUDE.md: initial repo guidance for Claude Code Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate icons/app.ico (Windows) and icons/app.icns (macOS) from the
|
||||
rounded PNG source files in icons/twin-gears/rounded/.
|
||||
|
||||
Run from the repo root:
|
||||
python scripts/build_icons.py
|
||||
|
||||
Requirements:
|
||||
pip install pillow # for .ico
|
||||
iconutil # built into macOS; for .icns
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent
|
||||
SRC = ROOT / "icons" / "twin-gears" / "rounded"
|
||||
OUT = ROOT / "icons"
|
||||
|
||||
|
||||
def build_ico():
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
print("Pillow not installed — skipping .ico generation (pip install pillow)")
|
||||
return
|
||||
|
||||
sizes = [16, 32, 48, 64, 128, 256]
|
||||
imgs = []
|
||||
for s in sizes:
|
||||
p = SRC / f"icon-{s}.png"
|
||||
if not p.exists():
|
||||
print(f" Missing {p.name}, skipping")
|
||||
continue
|
||||
imgs.append(Image.open(p).convert("RGBA"))
|
||||
|
||||
if not imgs:
|
||||
print(" No source PNGs found — cannot build .ico")
|
||||
return
|
||||
|
||||
dest = OUT / "app.ico"
|
||||
imgs[-1].save(dest, format="ICO", append_images=imgs[:-1])
|
||||
print(f" Generated {dest.relative_to(ROOT)} ({dest.stat().st_size // 1024 + 1} KB)")
|
||||
|
||||
|
||||
def build_icns():
|
||||
if shutil.which("iconutil") is None:
|
||||
print(" iconutil not found (macOS-only) — skipping .icns generation")
|
||||
return
|
||||
|
||||
iconset = Path(tempfile.mkdtemp()) / "app.iconset"
|
||||
iconset.mkdir()
|
||||
mapping = {
|
||||
"icon_16x16.png": "icon-16.png",
|
||||
"icon_16x16@2x.png": "icon-32.png",
|
||||
"icon_32x32.png": "icon-32.png",
|
||||
"icon_32x32@2x.png": "icon-64.png",
|
||||
"icon_128x128.png": "icon-128.png",
|
||||
"icon_128x128@2x.png": "icon-256.png",
|
||||
"icon_256x256.png": "icon-256.png",
|
||||
"icon_256x256@2x.png": "icon-512.png",
|
||||
"icon_512x512.png": "icon-512.png",
|
||||
"icon_512x512@2x.png": "icon-1024.png",
|
||||
}
|
||||
for dst_name, src_name in mapping.items():
|
||||
src = SRC / src_name
|
||||
if src.exists():
|
||||
shutil.copy2(src, iconset / dst_name)
|
||||
else:
|
||||
print(f" Missing {src_name}, skipping {dst_name}")
|
||||
|
||||
dest = OUT / "app.icns"
|
||||
subprocess.run(
|
||||
["iconutil", "-c", "icns", str(iconset), "-o", str(dest)],
|
||||
check=True,
|
||||
)
|
||||
shutil.rmtree(iconset.parent)
|
||||
print(f" Generated {dest.relative_to(ROOT)} ({dest.stat().st_size // 1024} KB)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Building icons/app.ico ...")
|
||||
build_ico()
|
||||
print("Building icons/app.icns ...")
|
||||
build_icns()
|
||||
print("Done.")
|
||||
Reference in New Issue
Block a user