The win7 skin is dropped. Everything else the branch built stays: Linux support and the HTML context menus, the workspace-tab menu, the continuous interface scale (rem everywhere, stepper, Ctrl/Cmd +/-/0) and the core/ service layer. The modern tree already carried all of them, and nothing outside skins/7like/ imported the win7 tree except main.ts and styles.css. Removed: the skins/7like/ tree (5.1k lines, fonts), the 7.css dependency, the skin setting and its options row + strings in all 7 locales, the frameless-window plumbing (window-control RPCs, windowState push, trackMaximizeState, the synthesized resize grip and its postinstall watchdog), the session-skin pinning in buildPreload/chromeOptions, the skin/skinfix cascade layers, and the win7-only probes and screenshot harness (the harness cannot render the modern tree: plain Firefox has no RPC bridge). chromeOptions() stays as the one shared frame decision. Fixed on the way out: - index.html's per-theme pre-paint background is restored. The branch had replaced it with a win7-only transparent rule, so modern dark windows had silently lost one of the three flash guards. - editor-windows.ts wrote its window-key separator as a literal NUL byte, which made git and grep treat the file as binary; it is `\0` now (same string at runtime). No settings migration: a stale "skin" key is carried harmlessly by the store's spread-merge and dropped on the next save. UI bundle: 616.7 kB -> 405.4 kB, back under the 500 kB budget. Docs: architecture, gotchas and platform-notes lose the win7 material but keep what stays true (construction-time preloads/frames, drag regions ignoring preventDefault, electrobun's missing resize/maximize primitives); flash-prevention, dev-URL and Bun-panic notes move back under Electrobun; stale context-menu/tab-bar links fixed; README documents the scale keys. Co-Authored-By: Claude <noreply@anthropic.com>
145 lines
8.8 KiB
Markdown
145 lines
8.8 KiB
Markdown
# Build & release
|
||
|
||
## Versioning — "Build n"
|
||
|
||
Sublime-style: the version IS the commit count. `scripts/gen-version.ts` runs
|
||
`git rev-list --count HEAD` + `git rev-parse --short HEAD` and writes the
|
||
**gitignored** `src/shared/version.gen.ts` (`BUILD = {number, commit, date,
|
||
electrobun}`). It is regenerated by `postinstall` and at the start of every
|
||
`dev`/`build`/`start`/`release` script; committing it would bump the count it
|
||
records, hence gitignored. Fresh checkouts fail `tsc` until `bun install` has
|
||
run once (postinstall creates the file). `BRANDING.version` stays
|
||
semver-shaped (`0.1.<n>`) for electrobun's config/updater; `BRANDING.buildLabel`
|
||
("Build n") is what humans see (About box, options popover).
|
||
|
||
## Dev loop
|
||
|
||
- `bun run dev` — gen-version → scripts/dev.ts: starts `ng serve` (HMR) and
|
||
`electrobun dev --watch`, with `DEV_SERVER_URL` pointing the webviews at the
|
||
dev server (only honored on the dev channel and only if the server answers).
|
||
- `bun run build` — gen-version → Angular build → `electrobun build`
|
||
(**dev channel** — fine for boot checks, NOT a release).
|
||
- `scripts/node-version-shim.ts` (preloaded via `bunfig.toml`, root AND ui/)
|
||
fakes a Node version the Angular CLI accepts under Bun. Both preloads are
|
||
load-bearing.
|
||
|
||
## Release builds
|
||
|
||
`bun scripts/release.ts [--target mac-arm64|mac-x64|win-x64|linux-x64]`
|
||
(default: host).
|
||
Steps: gen-version → gen-icons → Angular build → `electrobun build
|
||
--env=stable` → copy/rename artifacts into
|
||
`release/<target>/miniSCP-Build<n>-<target>.*`.
|
||
|
||
Facts the script encodes:
|
||
|
||
- **`--env=stable` is mandatory for releases** — the CLI defaults to the dev
|
||
channel (different app name `miniSCP-dev`, no distributable artifacts).
|
||
- **No OS cross-compile.** The CLI builds for its host (its `targets` config
|
||
field is unread in 1.18.1); packaging needs host tools (codesign/hdiutil on
|
||
macOS, rcedit/PowerShell on Windows). Hence one script run per artifact, on
|
||
the matching machine; `win-x64` on a non-Windows host and `linux-x64` on a
|
||
non-Linux host both error out.
|
||
- **mac-x64 from the arm64 Mac (Rosetta)**: the script downloads electrobun's
|
||
x64 CLI binary once (`electrobun-cli-darwin-x64.tar.gz` from the GitHub
|
||
release matching the installed version, cached at
|
||
`~/.cache/miniscp/electrobun-cli-x64-<ver>/`) and runs it directly —
|
||
Rosetta translates it, the CLI sees `process.arch === "x64"`, downloads the
|
||
`dist-macos-x64` core into the electrobun package dir on first use, and
|
||
packages a genuine x64 app. Note: Bun's `fetch`→`Bun.write` streaming hung
|
||
on the GitHub redirect chain; the script uses `curl -fsSL` deliberately.
|
||
- **Core binary downloads**: the installed npm package ships mac-arm64
|
||
binaries only; other `dist-<os>-<arch>` cores are fetched from
|
||
`github.com/blackboardsh/electrobun/releases` at build time — network to
|
||
GitHub is a build-time requirement on every fresh machine/runner.
|
||
- **Artifact shapes** (stable channel, in `artifacts/`): macOS →
|
||
`stable-macos-<arch>-miniSCP.dmg` + `.app.tar.zst` + `update.json`
|
||
(updater feed); Windows → `stable-win-x64-miniSCP-Setup.zip`
|
||
(self-extracting installer → `%LOCALAPPDATA%`) plus the script's own
|
||
**portable zip** made from the assembled app folder under
|
||
`build/stable-win-x64/` (layout to confirm on the first real Windows build —
|
||
the step warns instead of failing); Linux → only
|
||
`stable-linux-x64-miniSCP.tar.zst` + `update.json`, i.e. the updater feed and
|
||
nothing installable, so the script's **`.tar.gz` of the assembled app folder**
|
||
under `build/stable-linux-x64/` IS the release artifact (same best-effort
|
||
warn). No AppImage/.deb/.desktop — unpack and run the `miniSCP.sh` wrapper the
|
||
script writes beside `bin/launcher` (it applies the NVIDIA/DMABUF workaround,
|
||
which the app cannot set for itself — see gotchas.md).
|
||
- **Linux builds need the AppIndicator dev libraries present to RUN** (not to
|
||
build) — see platform-notes.md; a packaged tarball started on a machine
|
||
without them dies at `dlopen`.
|
||
- The script filters artifacts by app name, so stale artifacts from older
|
||
brandings don't get collected.
|
||
|
||
## CI (Gitea Actions)
|
||
|
||
`.gitea/workflows/release.yml` — tag-triggered (`build-*`), macos + windows
|
||
runner matrix, each running the same release script; inert until act_runners
|
||
with those labels are registered. Needs `fetch-depth: 0` (the build number is
|
||
the commit count). Runner prereqs are commented in the workflow file.
|
||
|
||
## Download host (`site/` + Caddy)
|
||
|
||
`site/` is a self-contained landing page **and** download host, served by Caddy on an
|
||
internal box (plain HTTP `:80`, no domain/TLS). Deploys to `/srv/miniscp/`.
|
||
|
||
- `site/index.html` — pure static, no JS, tinygrad-minimal. Download buttons link to **fixed
|
||
stable filenames** (`/dl/stable-macos-arm64-miniSCP.dmg`, …) so the page never changes per
|
||
release. Logo/screenshot `<img>` slots are commented in, images live in `site/assets/`.
|
||
- `site/Caddyfile` — one flat `/dl/*` folder with `file_server browse` + range requests, and
|
||
per-type `Cache-Control`: `*.patch` immutable (unique hashed names), `*update.json` `no-cache`
|
||
(updater must see new versions), installers (`*.dmg *.zip *.tar.zst`) `max-age=300` (stable
|
||
names overwritten each release). Landing page has **no** SPA fallback → unknown paths 404.
|
||
Path matcher gotcha: use suffix globs like `*update.json`, not `*/*update.json`.
|
||
- **One flat folder, no per-build dirs** — this layout IS electrobun's `artifacts/` feed, so it
|
||
doubles as the (future) updater `baseUrl`. Publishing = drop this machine's `artifacts/stable-*`
|
||
into `/dl/`; installers overwrite in place, `.patch` files accumulate (never delete them, or
|
||
older installs lose their incremental-update trail). **Tradeoff:** only the latest full
|
||
installer is downloadable; old full versions are overwritten.
|
||
- `site/deploy.sh` — run per build machine after `scripts/release.ts`; copies `artifacts/stable-*`
|
||
and renames the build-numbered win portable zip to the stable `stable-win-x64-miniSCP-portable.zip`.
|
||
`MINISCP_DL_DIR` overrides the target (stage locally, then rsync to the server).
|
||
- `release.baseUrl = https://miniscp.com/dl` is set in `electrobun.config.ts`; `miniscp.com` is
|
||
fronted by an external proxy for TLS (Caddy itself stays on `:80` behind it). The value is baked
|
||
into `version.json` at build time, so only builds made after it was added check for updates.
|
||
With `generatePatch` (default true), release builds now need **build-time network to
|
||
`miniscp.com/dl`** so electrobun can fetch the currently-published version to diff a `.patch`
|
||
(the first build after enabling it has nothing to diff and just ships the full artifacts).
|
||
|
||
## Auto-updater (app side)
|
||
|
||
Wired on top of the download host above. See the "Auto-updater" section in
|
||
[architecture.md](architecture.md) for the runtime flow.
|
||
|
||
- **Backend** ([src/bun/index.ts](../src/bun/index.ts)): `Updater.checkForUpdate()` runs ~5s after launch and
|
||
every 6h; on `updateAvailable` it pushes `rpc.send.updateStatus({phase:"available",…})`.
|
||
`Updater.onStatusChange` streams `download-progress` (0–100) → `updateStatus{downloading}`.
|
||
`checkForUpdate` self-guards the `dev` channel, so `bun run dev` never shows the pill.
|
||
- **RPC** ([src/shared/rpc.ts](../src/shared/rpc.ts)): requests `checkForUpdate` / `downloadUpdate` /
|
||
`applyUpdate` (handlers in [rpc-handlers.ts](../src/bun/rpc-handlers.ts) call the electrobun `Updater`);
|
||
push message `updateStatus`.
|
||
- **UI**: `UpdaterService` ([ui/src/app/core/updater.service.ts](../ui/src/app/core/updater.service.ts)) holds signals
|
||
(`state`/`version`/`progress`); the tab-bar "update pill" ([tab-bar.ts](../ui/src/app/skins/shadlike/tab-bar/tab-bar.ts))
|
||
is one accent (`bg-primary`) control that announces → fills as a progress bar while downloading →
|
||
"Restart to apply". `state` is `available → downloading → ready` (ready derived from the
|
||
`downloadUpdate` response). App-menu "Check for Updates…" ([menu.ts](../src/bun/menu.ts)) routes a
|
||
`check-for-updates` menu action into `UpdaterService.check()`.
|
||
- **Unsigned is fine:** `applyUpdate()` strips the macOS quarantine xattr before relaunch, so the
|
||
swapped bundle isn't Gatekeeper-blocked.
|
||
|
||
## Icons
|
||
|
||
`scripts/gen-icons.ts` (resvg, dev-time): renders `assets/logo.svg` into the
|
||
macOS iconset + `icon.png`, a multi-size `assets/icon.ico` (Windows installer/
|
||
taskbar, wired via `electrobun.config.ts win.icon`), the macOS tray template
|
||
PNG from `assets/tray/tray-glyph.svg`, and a small colored Windows tray PNG.
|
||
Rerun after touching either SVG; outputs are committed (build inputs).
|
||
|
||
## electrobun config notes
|
||
|
||
`electrobun.config.ts`: app identity comes from `BRANDING`; `build.bun.external`
|
||
must keep `["cpu-features", "*.node"]` (ssh2's optional native accelerators —
|
||
bundling them breaks the build; runtime falls back to pure JS);
|
||
`build.copy` ships the Angular dist and tray assets into `views://`;
|
||
`bundleCEF: false` everywhere (system WebKit / WebView2).
|