Self-contained, no-JS landing page (tinygrad-minimal) that doubles as the artifact download host, served by Caddy on an internal :80 box. - site/index.html: static page, "Same tool, only a little different", feature highlights (remote->remote, symmetric panels, ssh_config awareness, edit-in- place, self-copy guard, ...), fixed stable download links, FAQ (unsigned notes). - site/Caddyfile: one flat /dl/ folder with browse + range requests and per-type Cache-Control (patches immutable, update.json no-cache, installers short). - site/deploy.sh: drop a build's artifacts/stable-* into /dl/ (renames the win portable zip to a stable name). - Flat folder matches electrobun's artifacts/ layout, so it's also the future updater baseUrl; per-build folders/symlink dropped in favor of it. - docs/build-and-release.md: document the download host + deploy flow. Verified: caddy validate + live smoke test (links, cache headers, 206 range, 404 fallback, deploy.sh copy/rename) against a temp root. Co-Authored-By: Claude <noreply@anthropic.com>
6.3 KiB
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: startsng serve(HMR) andelectrobun dev --watch, withDEV_SERVER_URLpointing 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 viabunfig.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] (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=stableis mandatory for releases — the CLI defaults to the dev channel (different app nameminiSCP-dev, no distributable artifacts).- No OS cross-compile. The CLI builds for its host (its
targetsconfig 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-x64on a non-Windows host errors out. - mac-x64 from the arm64 Mac (Rosetta): the script downloads electrobun's
x64 CLI binary once (
electrobun-cli-darwin-x64.tar.gzfrom the GitHub release matching the installed version, cached at~/.cache/miniscp/electrobun-cli-x64-<ver>/) and runs it directly — Rosetta translates it, the CLI seesprocess.arch === "x64", downloads thedist-macos-x64core into the electrobun package dir on first use, and packages a genuine x64 app. Note: Bun'sfetch→Bun.writestreaming hung on the GitHub redirect chain; the script usescurl -fsSLdeliberately. - Core binary downloads: the installed npm package ships mac-arm64
binaries only; other
dist-<os>-<arch>cores are fetched fromgithub.com/blackboardsh/electrobun/releasesat 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 underbuild/stable-win-x64/(layout to confirm on the first real Windows build — the step warns instead of failing). - 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 insite/assets/.site/Caddyfile— one flat/dl/*folder withfile_server browse+ range requests, and per-typeCache-Control:*.patchimmutable (unique hashed names),*update.jsonno-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) updaterbaseUrl. Publishing = drop this machine'sartifacts/stable-*into/dl/; installers overwrite in place,.patchfiles 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 afterscripts/release.ts; copiesartifacts/stable-*and renames the build-numbered win portable zip to the stablestable-win-x64-miniSCP-portable.zip.MINISCP_DL_DIRoverrides the target (stage locally, then rsync to the server).- Future updater (not wired yet): set
release.baseUrl = http://<host>/dl/inelectrobun.config.ts(currently unset) → builds start emitting.patchfiles thatdeploy.shalready ships. Then call the electrobunUpdaterAPI on launch/interval/tray.
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).