Skip to content

Commit 21dbb53

Browse files
authored
Merge pull request #3 from beautyfree/migration/electron-vite
Migrate from Electrobun to electron-vite
2 parents db43733 + 6a28e09 commit 21dbb53

41 files changed

Lines changed: 2295 additions & 1733 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
name: Release
22

3-
# Triggered by pushing a tag like v0.1.0. Builds the desktop app natively on
4-
# each OS (Electrobun does not cross-compile) and uploads every build straight
5-
# to the GitHub Release — bypassing actions/upload-artifact so the workflow
6-
# keeps working even when the account-wide Actions artifact storage quota is
7-
# full.
3+
# Triggered by pushing a tag like v0.2.0. Builds the Electron app natively on
4+
# each OS (electron-builder + node-gyp native modules don't cross-compile
5+
# cleanly) and uploads every artifact to the GitHub Release directly so the
6+
# workflow keeps working even if the account-wide Actions artifact quota is
7+
# full. electron-updater reads `latest-{mac,linux,win}.yml` from the same
8+
# release to drive auto-updates in production.
89

910
on:
1011
push:
@@ -19,7 +20,6 @@ concurrency:
1920
cancel-in-progress: false
2021

2122
jobs:
22-
# 1. Create a draft release up front so every platform job can append to it.
2323
prepare-release:
2424
name: Prepare draft release
2525
runs-on: ubuntu-latest
@@ -34,14 +34,13 @@ jobs:
3434
body: |
3535
Desktop installers — download the one that matches your OS:
3636
37-
- **macOS (Apple Silicon):** `stable-macos-arm64-Skiller.dmg` (signed + notarized — drag to Applications)
38-
- **Windows (x64):** `stable-win-x64-Skiller-Setup.zip` (extract and run `Skiller.exe`)
39-
- **Linux (x64):** `stable-linux-x64-Skiller-Setup.tar.gz` (extract and run `bin/launcher`)
37+
- **macOS (Apple Silicon):** `Skiller-<version>-macos-arm64.dmg` (signed + notarized — drag to Applications)
38+
- **Windows (x64):** `Skiller-<version>-win-x64.exe` (NSIS installer)
39+
- **Linux (x64):** `Skiller-<version>-linux-x86_64.AppImage` or `.deb`
4040
4141
After the first install, Skiller checks this release on launch and
42-
via **Settings → App Updates**. Updates are downloaded in the
43-
background (delta patches when available) and applied on next
44-
restart — no manual re-install required.
42+
via **Settings → App Updates**. Updates are downloaded on demand
43+
and applied on next restart — powered by `electron-updater`.
4544
draft: true
4645
prerelease: false
4746
generate_release_notes: true
@@ -61,38 +60,43 @@ jobs:
6160
script: dist:mac
6261
- label: windows-x64
6362
runner: windows-latest
64-
script: build:win
63+
script: dist:win
6564
- label: linux-x64
6665
runner: ubuntu-latest
67-
script: build:linux
66+
script: dist:linux
6867
steps:
6968
- uses: actions/checkout@v5
7069

7170
- uses: oven-sh/setup-bun@v2
7271
with:
7372
bun-version: latest
7473

75-
# create-dmg produces the styled, drag-to-Applications DMG that
76-
# replaces Electrobun's default.
74+
# create-dmg builds the styled drag-to-Applications DMG that
75+
# scripts/repack-dmg.sh wraps around electron-builder's signed .app.
7776
- name: Install create-dmg (macOS)
7877
if: runner.os == 'macOS'
7978
run: brew install create-dmg
8079

81-
# Linux deps needed by Electrobun's WebKitGTK webview + system tooling.
80+
# Native module build toolchain for better-sqlite3 under Electron's ABI.
8281
- name: Install Linux deps
8382
if: runner.os == 'Linux'
8483
run: |
8584
sudo apt-get update
8685
sudo apt-get install -y --no-install-recommends \
87-
build-essential pkg-config cmake \
88-
libgtk-3-dev libwebkit2gtk-4.1-dev \
89-
libayatana-appindicator3-dev librsvg2-dev
86+
build-essential pkg-config python3 \
87+
libxss1 libnss3 libasound2t64 \
88+
fakeroot dpkg
9089
9190
- run: bun install --frozen-lockfile
9291

93-
# Import the Developer ID signing cert into a temporary keychain. The
94-
# macOS runner has no signing identity by default; without this,
95-
# `codesign --sign "$ELECTROBUN_DEVELOPER_ID" …` fails with
92+
# Rebuild native modules (better-sqlite3) against the Electron ABI
93+
# bundled by electron-builder. Runs on every OS — electron-builder
94+
# handles the platform-specific node-gyp invocation.
95+
- name: Rebuild native modules
96+
run: bunx electron-builder install-app-deps
97+
98+
# Import the Developer ID signing cert into a temporary keychain.
99+
# Without this, electron-builder's codesign step fails with
96100
# "The specified item could not be found in the keychain."
97101
- name: Import Developer ID certificate (macOS)
98102
if: runner.os == 'macOS'
@@ -114,43 +118,51 @@ jobs:
114118
-P "$MACOS_CERT_P12_PASSWORD" \
115119
-A -t cert -f pkcs12 \
116120
-k "$KEYCHAIN_PATH"
117-
# Allow codesign to use the key without a UI prompt.
118121
security set-key-partition-list -S apple-tool:,apple:,codesign: \
119122
-s -k "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
120-
# Put our keychain first in the search list so codesign finds it.
121123
security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain
122124
123125
rm -f "$CERT_PATH"
124126
125-
# Write the App Store Connect API .p8 key from a secret so notarytool can
126-
# use it. Secret contents should be the raw contents of AuthKey_XXXX.p8.
127+
# notarytool / @electron/notarize needs the .p8 file on disk. Secret
128+
# should be the raw contents of AuthKey_XXXX.p8 (multiline).
127129
- name: Write notarization API key (macOS)
128-
if: runner.os == 'macOS' && env.ELECTROBUN_APPLEAPIKEY_P8 != ''
130+
if: runner.os == 'macOS' && env.APPLE_API_KEY_P8 != ''
129131
env:
130-
ELECTROBUN_APPLEAPIKEY_P8: ${{ secrets.ELECTROBUN_APPLEAPIKEY_P8 }}
132+
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
131133
run: |
132134
KEY_PATH="$RUNNER_TEMP/AuthKey.p8"
133-
printf '%s' "$ELECTROBUN_APPLEAPIKEY_P8" > "$KEY_PATH"
135+
printf '%s' "$APPLE_API_KEY_P8" > "$KEY_PATH"
134136
chmod 600 "$KEY_PATH"
135-
echo "ELECTROBUN_APPLEAPIKEYPATH=$KEY_PATH" >> "$GITHUB_ENV"
137+
echo "APPLE_API_KEY=$KEY_PATH" >> "$GITHUB_ENV"
136138
137139
- name: Build app
138140
env:
139-
# macOS signing + notarization (no-op on other OSes)
140-
ELECTROBUN_DEVELOPER_ID: ${{ secrets.ELECTROBUN_DEVELOPER_ID }}
141-
ELECTROBUN_APPLEAPIISSUER: ${{ secrets.ELECTROBUN_APPLEAPIISSUER }}
142-
ELECTROBUN_APPLEAPIKEY: ${{ secrets.ELECTROBUN_APPLEAPIKEY }}
141+
# electron-builder reads GH_TOKEN for its publish step; we publish
142+
# via softprops below instead but the var being set also unlocks
143+
# electron-builder's release-draft verification.
144+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
145+
# macOS signing + notarization (renamed from ELECTROBUN_* in Phase 5).
146+
CSC_NAME: ${{ secrets.CSC_NAME }}
147+
APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }}
148+
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
143149
run: bun run ${{ matrix.script }}
144150

145-
# Upload every artifact directly to the draft Release. This avoids
146-
# actions/upload-artifact entirely — no Actions storage quota involved.
151+
# Upload every artifact (including latest-*.yml and .blockmap files —
152+
# electron-updater needs them alongside the binaries).
147153
- name: Upload build outputs to Release
148154
uses: softprops/action-gh-release@v2
149155
with:
150156
tag_name: ${{ github.ref_name }}
151157
draft: true
152-
files: artifacts/*
153-
fail_on_unmatched_files: true
158+
files: |
159+
artifacts/*.dmg
160+
artifacts/*.exe
161+
artifacts/*.AppImage
162+
artifacts/*.deb
163+
artifacts/*.yml
164+
artifacts/*.blockmap
165+
fail_on_unmatched_files: false
154166
env:
155167
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
156168

@@ -161,7 +173,6 @@ jobs:
161173
steps:
162174
- uses: actions/checkout@v5
163175

164-
# Flip the draft to published once every platform job succeeded.
165176
- name: Publish release
166177
uses: softprops/action-gh-release@v2
167178
with:

.gitignore

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,16 @@ node_modules
1111
dist
1212
dist-ssr
1313
build
14+
out
1415
artifacts
16+
17+
# TypeScript project references incremental build output
18+
*.tsbuildinfo
19+
# Emitted by `tsc --build` for root config files (kept as side-effects)
20+
/vite.config.d.ts
21+
/vite.config.js
22+
/electron.vite.config.d.ts
23+
/electron.vite.config.js
1524
*.local
1625
.playwright-mcp
1726

@@ -37,5 +46,3 @@ artifacts
3746
# OS files
3847
Thumbs.db
3948

40-
# Built on macOS (bun run build:native-effects)
41-
src/bun/libMacWindowEffects.dylib

CLAUDE.md

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
# Skiller — agent guidance
22

3-
Skiller is a **cross-platform desktop app** (Electrobun) for installing, syncing, and editing **AI agent skills** across many agents (Claude Code, Cursor, Copilot CLI, etc.). Bundle ID: `com.beautyfree.skiller`.
3+
Skiller is a **cross-platform desktop app** (Electron) for installing, syncing, and editing **AI agent skills** across many agents (Claude Code, Cursor, Copilot CLI, etc.). Bundle ID: `com.beautyfree.skiller`.
44

55
## Stack
66

77
| Layer | Tech |
88
| --- | --- |
9-
| Main / native | **Bun** + **Electrobun** (`src/bun/index.ts`) |
9+
| Main / native | **Electron** (`src/electron-main/index.ts`), Node 20 |
1010
| UI | **React 19**, **Vite 7** (root `src/mainview`), **Tailwind CSS 4**, **react-router-dom** |
11-
| API | **tRPC** (`@trpc/server` in Bun, `@trpc/client` + TanStack Query in the webview) |
12-
| Config | `electrobun.config.ts` (loads `.env` for signing vars) |
11+
| API | **tRPC** over HTTP on 127.0.0.1 + `ipcMain` push channel for main→renderer events |
12+
| Build | **electron-vite** (dev + bundling) + **electron-builder** (packaging, signing, auto-updates) |
13+
| Updater | **electron-updater** (GitHub Releases, `latest-*.yml` + blockmaps) |
1314

1415
## Repository layout
1516

1617
| Path | Role |
1718
| --- | --- |
18-
| `src/bun/` | Electrobun main process: `BrowserWindow`, tray, updater wiring, tRPC HTTP server, skill watcher |
19+
| `src/electron-main/` | Electron main process: `BrowserWindow`, tray, tRPC server, macOS vibrancy, platform adapter |
20+
| `src/preload/` | `contextBridge` — exposes `window.api.{invoke,on,platform}` to the renderer |
21+
| `src/main/` | Platform-agnostic main-side code: skill watcher, tRPC router, marketplace cache, app-updater wrapper, settings, scanner |
1922
| `src/mainview/` | Vite app: `App.tsx`, pages, components, `index.html`, CSS tokens |
20-
| `src/shared/` | Types / RPC schema shared between Bun and webview (import from both sides as needed) |
21-
| `src/main/` | Node-agnostic skill watcher and related main-side helpers |
22-
| `agents/` | Bundled agent metadata (copied into app via `electrobun.config.ts` `copy`) |
23+
| `src/shared/` | Types / RPC schema shared between main and renderer (including `AppPlatform` interface) |
24+
| `agents/` | Bundled agent metadata (copied into the app via `electron-builder.yml` `extraResources`) |
2325
| `assets/icons/` | **Runtime icons**: `AppIcon.iconset/`, `app.icns`, `app.ico`, `app/icon-512.png` |
2426
| `assets/icons/Skiller.icon/` | **Source only** (Icon Composer): `scripts/build-app-icons.py` reads `Assets/Image.png` via `icon.json` |
25-
| `scripts/` | `build-app-icons.py`, `normalize-skiller-icon-layer.py`, `repack-dmg.sh`, native build helpers |
27+
| `build-resources/` | `entitlements.mac.plist` for Hardened Runtime |
28+
| `scripts/` | `build-app-icons.py`, `normalize-skiller-icon-layer.py`, `repack-dmg.sh`, `notarize.mjs` |
2629
| `docs/DEVELOPMENT.md` | Setup, HMR, signing, CI, DMG repack — **read before changing release/signing** |
2730
| `DESIGN.md` | UI tokens and product design notes |
2831

@@ -36,21 +39,24 @@ bun install
3639

3740
**Development**
3841

39-
- `bun run dev` — Electrobun dev + watch (runs `build:native-effects` first on macOS).
40-
- `bun run dev:hmr` — Concurrent Vite (port **5180**) + `electrobun dev` for UI hot reload.
41-
- `bun run dev:debug` — Same as HMR path with webview DevTools (`AGENTSKILLS_DEVTOOLS=1`).
42+
- `bun run dev` — electron-vite dev: watches main + preload, spawns Vite on port **5180** for the renderer with HMR. Opens an Electron window loading the Vite URL.
43+
- `bun run dev:debug` — Same as `dev` with `AGENTSKILLS_DEVTOOLS=1` (renderer DevTools on-open).
4244

4345
**Checks**
4446

45-
- `bunx tsc --noEmit` — typecheck (also part of `bun run build`).
47+
- `bun run typecheck``tsc --noEmit` for renderer + `tsc -p tsconfig.node.json --noEmit` for main/preload.
4648

47-
**Production web bundle**
49+
**Production bundle (web + main + preload)**
4850

49-
- `bun run build``build:native-effects` + `tsc` + `vite build``dist/` (then copied into the app bundle per `electrobun.config.ts`).
51+
- `bun run build``electron-vite build``out/{main,preload,renderer}/`. Consumed by `electron-builder`.
5052

51-
**Platform installers** (run **on the target OS**; Electrobun does not cross-compile)
53+
**Platform installers** (run **on the target OS**; electron-builder doesn't cross-compile native modules)
5254

53-
- `bun run dist:mac` / `dist:win` / `dist:linux` — see `docs/DEVELOPMENT.md` for artifacts and secrets.
55+
- `bun run dist:mac``electron-vite build && electron-builder --mac && bash scripts/repack-dmg.sh`
56+
- `bun run dist:win``electron-vite build && electron-builder --win`
57+
- `bun run dist:linux``electron-vite build && electron-builder --linux`
58+
59+
See `docs/DEVELOPMENT.md` for signing env vars and artifact locations.
5460

5561
## Icons
5662

@@ -61,19 +67,21 @@ bun install
6167

6268
## Conventions for agents
6369

64-
- Prefer **Bun** for scripts and local runs (`bun`, `bunx`).
70+
- Prefer **Bun** for scripts and local runs (`bun`, `bunx`). Electron main itself runs on Node (Electron's bundled Node 20) — use Node-compatible APIs only.
6571
- **UI strings** for user-facing copy: add keys under `src/mainview/i18n/` (English in `en.ts`); keep code comments in **English**.
66-
- Match existing patterns: `@/` imports from `src/mainview` (see `vite.config.ts` / `tsconfig.json`).
72+
- Match existing patterns: `@/` imports from `src/mainview` (see `electron.vite.config.ts` / `tsconfig.json`).
6773
- Avoid scope creep: do not change `node_modules/` or unrelated marketing-only paths unless the task requires it.
68-
- After RPC or shared-type changes, ensure **both** Bun handlers and webview callers stay aligned (`src/shared/` or local schema modules).
74+
- After RPC or shared-type changes, ensure **both** main handlers (`src/main/rpc-handlers.ts`) and renderer callers stay aligned (`src/shared/` or local schema modules).
75+
- Native Node modules (`better-sqlite3`) need `electron-builder install-app-deps` to rebuild against Electron's ABI. `bun install` on its own won't do it.
6976

7077
## Environment variables (non-exhaustive)
7178

7279
| Variable | Purpose |
7380
| --- | --- |
74-
| `AGENTSKILLS_TRPC_PORT` | tRPC HTTP port (default `17888`) |
75-
| `AGENTSKILLS_DEVTOOLS` / `ELECTROBUN_OPEN_DEVTOOLS` | Open webview DevTools |
76-
| `ELECTROBUN_*` | Signing, notarization, update base URL — see `docs/DEVELOPMENT.md` and `electrobun.config.ts` |
81+
| `AGENTSKILLS_TRPC_PORT` | tRPC HTTP port (default `17888`; falls through to +48 on conflict) |
82+
| `AGENTSKILLS_DEVTOOLS` | Auto-open renderer DevTools on launch (dev only) |
83+
| `AGENTSKILLS_DISABLE_WINDOW_BLUR` | `1` → force vibrancy off on macOS even if settings say on |
84+
| `CSC_NAME`, `APPLE_API_KEY_*`, `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, `APPLE_TEAM_ID` | macOS signing + notarization. See `docs/DEVELOPMENT.md`. |
7785

7886
## Further reading
7987

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,23 @@ Grab the installer for your OS from the [**latest release**](https://github.com/
7979

8080
| OS | File | Notes |
8181
| --- | --- | --- |
82-
| macOS (Apple Silicon) | `stable-macos-arm64-Skiller.dmg` | Signed + notarized — opens with no Gatekeeper warnings. Open the DMG and drag Skiller to Applications. |
83-
| Windows (x64) | `stable-win-x64-Skiller-Setup.zip` | Extract and run `Skiller.exe`. SmartScreen may show a one-time warning — click "More info" → "Run anyway". |
84-
| Linux (x64) | `stable-linux-x64-Skiller-Setup.tar.gz` | Extract and run `bin/launcher` from the resulting folder. |
82+
| macOS (Apple Silicon) | `Skiller-<version>-macos-arm64.dmg` | Signed + notarized. Open the DMG and drag Skiller to Applications. |
83+
| Windows (x64) | `Skiller-<version>-win-x64.exe` | NSIS installer. SmartScreen may show a one-time warning — click "More info" → "Run anyway". |
84+
| Linux (x64) | `Skiller-<version>-linux-x86_64.AppImage` or `.deb` | AppImage is self-contained (`chmod +x`, run). Deb for Ubuntu/Debian package managers. |
8585

8686
Every release is built and published by the CI matrix in `.github/workflows/release.yml` — tagging `vX.Y.Z` produces all three platforms automatically.
8787

88+
> **If you had an older `stable-*-Skiller.*` build:** those were produced by a previous Electrobun-based packaging pipeline and can't auto-update to the current Electron-based builds. Grab the new installer above; your local data in `~/Library/Application Support/com.beautyfree.skiller/` (or the Windows/Linux equivalent) stays intact.
89+
8890
## Auto-updates
8991

9092
Once installed, Skiller keeps itself current:
9193

9294
- Checks for new versions on launch, then every 6 hours in the background.
93-
- Downloads delta patches (~14 KB typical) when available; falls back to the full bundle if the patch chain breaks.
94-
- Shows status and a one-click **Restart & install** button in **Settings → App Updates**.
95+
- Downloads the full updated bundle on demand (click **Download update** in Settings → App Updates).
96+
- Shows status and a one-click **Restart & install** button once ready.
9597

96-
The updater points at `github.com/.../releases/latest/download`, so every tagged release on GitHub automatically becomes the next update for existing installs.
98+
Powered by [`electron-updater`](https://www.electron.build/auto-update) reading from this repo's GitHub Releases.
9799

98100
## For Developers
99101

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<!--
6+
Hardened Runtime + notarization minimum entitlements for an Electron app.
7+
- allow-jit: Chromium V8 JIT
8+
- allow-unsigned-executable-memory: Chromium/V8 writes executable pages
9+
- disable-library-validation: loads better-sqlite3.node at runtime
10+
- cs.allow-dyld-environment-variables: Electron's helper process needs
11+
DYLD_* env vars under hardened runtime
12+
13+
Do not add entitlements beyond what's listed unless the feature explicitly
14+
needs them — every addition widens the notarization attack surface.
15+
-->
16+
<key>com.apple.security.cs.allow-jit</key>
17+
<true/>
18+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
19+
<true/>
20+
<key>com.apple.security.cs.disable-library-validation</key>
21+
<true/>
22+
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
23+
<true/>
24+
</dict>
25+
</plist>

0 commit comments

Comments
 (0)