Files
miniSCP/docs/build-and-release.md
T
jgamboaandClaude 2bac7678ca Remove the Windows 7 (7.css) skin
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>
2026-09-23 16:17:38 +02:00

8.8 KiB
Raw Blame History

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 for the runtime flow.

  • Backend (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): requests checkForUpdate / downloadUpdate / applyUpdate (handlers in rpc-handlers.ts call the electrobun Updater); push message updateStatus.
  • UI: UpdaterService (ui/src/app/core/updater.service.ts) holds signals (state/version/progress); the tab-bar "update pill" (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) 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).