Installer Builder
Build a beginner-proof, one-click installer that drops a fully-configured stack onto a clean machine: an Electron GUI with checkbox component selection that silently installs third-party apps (editors, runtimes, CLIs, VPN), deploys a config from GitHub, and installs language deps. Supports full offline (everything bundled) or online bootstrapper (downloads at install).
This skill is the map + the non-obvious lessons; готового репозитория-образца пак не несёт. Структура и все нетривиальные куски кода — в references/blueprint.md, их хватает, чтобы собрать инсталлятор с нуля.
Read first
references/gotchas.md — read it before writing any code. Every entry cost hours on a real build. Most are silent-until-clean-machine failures (BOM, PowerShell stderr, Store-python stub, Cursor -Wait, GitHub 100MB). Skipping it guarantees re-discovering them.
references/blueprint.md — architecture, file layout, the component/pack model, offline-vendor design, the offline-first install-script pattern, IPC, dry-run, next-step screen.
references/ci-and-platforms.md — Windows portable+admin packaging, the GitHub Actions macOS .dmg build (build a Mac version without owning a Mac), code signing reality.
Core architecture (decide up front)
- One product → two platform builds. No single binary runs on Win+Mac. Ship
Setup-Windows.exe and Setup-Mac.dmg from one Electron codebase. A download page detects OS.
- Don't install "the installer". Use a portable Windows exe (runs the GUI directly, no install-then-launch) with admin elevation; macOS ships a
.dmg.
- Offline vs online — pick per project:
- Full offline: a build-time
fetch-vendor script downloads every installer/wheel/browser into vendor/; electron-builder bundles it; install scripts install from vendor/ (no internet). ~800MB-1.2GB. Versions freeze at build → rebuild to refresh.
- Online bootstrapper: small (~70MB), downloads components at install via winget/brew/direct. Always latest, needs internet.
- Hybrid: bundle the cheap/yours-anyway parts (your config), download heavy apps online.
- Config-driven:
components.json (checkbox items + dependency graph), packs.json (human-readable bundles that filter which sub-items install), config.json (URLs, endpoints, flags). Editing JSON + rebuild = patch.
Workflow
- Scope — list components (apps, runtimes, CLIs, the config, language deps, VPN) and decide offline level. Confirm with the user: offline level, code-signing budget, any server endpoints, the config repo URL.
- Scaffold the Electron app (main process runs platform scripts via IPC and streams output; preload exposes a safe bridge; renderer = checkbox UI + log + finish screen). See
blueprint.md.
- Write per-component install scripts —
scripts/windows/*.ps1 + scripts/macos/*.sh, one per component, idempotent + offline-first (if bundled → install local; elif winget/brew → ; else download). Follow the script rules in gotchas.md exactly.
- Build-time vendor fetch (if offline) —
tools/fetch-vendor.ps1 (Win) / fetch-vendor-mac.sh (Mac runner): download apps, language wheels (pin to the bundled runtime version), browser engines, npm cache.
- Package —
electron-builder --win (portable, requestExecutionLevel admin) and --mac (dmg). See ci-and-platforms.md.
- Verify — there is no clean machine here. Use: AST/
bash -n syntax checks, a HM_DRY_RUN flag that prints "WOULD install X" without mutating, a config-deploy E2E into a sandbox $HOME, an offline pip --dry-run in a fresh venv, and a boot smoke. Then a real clean-machine run (or GitHub Actions) is the only true proof.
- Polish — a "What's next" finish screen (open editor button + auto-open checkbox, open-keys-file, return-to-bot link, video link, retry-failed), all driven by
config.json.
Hard rules (from real failures — do not skip)
- Windows
.ps1 with non-ASCII MUST be UTF-8 with BOM, else powershell.exe mis-reads it and the script won't parse. Re-apply BOM after every edit.
- Install scripts:
$ErrorActionPreference='Continue', not Stop — native tools (npm/pip/python) write notices to stderr; under Stop that becomes a fatal NativeCommandError. Use explicit exit 0/1 + final verification for honest status.
- Never
git add/commit the built .exe/.dmg — GitHub rejects files >100MB. Gitignore *.exe *.dmg release/ release-mac/ vendor/ node_modules/.
.gitattributes: *.sh text eol=lf (CRLF breaks the shebang on Mac).
- A
.dmg can be built only on macOS → use the GitHub Actions mac runner (ci-and-platforms.md).
After creating or changing the skill, register it (routing.md row + CLAUDE.md count). The reference project is the source of truth for code — prefer reading/adapting it over writing from scratch.
1---2name: installer-builder3description: One-click инсталляторы Windows .exe + macOS .dmg на Electron (без Mac, GitHub Actions). Триггеры: «сделай инсталлятор», «вшить ПО в один установщик».4---56# Installer Builder78Build a beginner-proof, one-click installer that drops a fully-configured stack onto a clean machine: an Electron GUI with checkbox component selection that silently installs third-party apps (editors, runtimes, CLIs, VPN), deploys a config from GitHub, and installs language deps. Supports **full offline** (everything bundled) or **online bootstrapper** (downloads at install).910This skill is the map + the non-obvious lessons; готового репозитория-образца пак не несёт. Структура и все нетривиальные куски кода — в `references/blueprint.md`, их хватает, чтобы собрать инсталлятор с нуля.1112## Read first1314**`references/gotchas.md` — read it before writing any code.** Every entry cost hours on a real build. Most are silent-until-clean-machine failures (BOM, PowerShell stderr, Store-python stub, Cursor `-Wait`, GitHub 100MB). Skipping it guarantees re-discovering them.1516- `references/blueprint.md` — architecture, file layout, the component/pack model, offline-vendor design, the offline-first install-script pattern, IPC, dry-run, next-step screen.17- `references/ci-and-platforms.md` — Windows portable+admin packaging, the GitHub Actions macOS `.dmg` build (build a Mac version without owning a Mac), code signing reality.1819## Core architecture (decide up front)20211. **One product → two platform builds.** No single binary runs on Win+Mac. Ship `Setup-Windows.exe` and `Setup-Mac.dmg` from one Electron codebase. A download page detects OS.222. **Don't install "the installer".** Use a **portable** Windows exe (runs the GUI directly, no install-then-launch) with admin elevation; macOS ships a `.dmg`.233. **Offline vs online — pick per project:**24 - **Full offline**: a build-time `fetch-vendor` script downloads every installer/wheel/browser into `vendor/`; electron-builder bundles it; install scripts install from `vendor/` (no internet). ~800MB-1.2GB. Versions freeze at build → rebuild to refresh.25 - **Online bootstrapper**: small (~70MB), downloads components at install via winget/brew/direct. Always latest, needs internet.26 - **Hybrid**: bundle the cheap/yours-anyway parts (your config), download heavy apps online.274. **Config-driven**: `components.json` (checkbox items + dependency graph), `packs.json` (human-readable bundles that filter which sub-items install), `config.json` (URLs, endpoints, flags). Editing JSON + rebuild = patch.2829## Workflow30311. **Scope** — list components (apps, runtimes, CLIs, the config, language deps, VPN) and decide offline level. Confirm with the user: offline level, code-signing budget, any server endpoints, the config repo URL.322. **Scaffold** the Electron app (main process runs platform scripts via IPC and streams output; preload exposes a safe bridge; renderer = checkbox UI + log + finish screen). See `blueprint.md`.333. **Write per-component install scripts** — `scripts/windows/*.ps1` + `scripts/macos/*.sh`, one per component, **idempotent + offline-first** (`if bundled → install local; elif winget/brew → ; else download`). Follow the script rules in `gotchas.md` exactly.344. **Build-time vendor fetch** (if offline) — `tools/fetch-vendor.ps1` (Win) / `fetch-vendor-mac.sh` (Mac runner): download apps, language wheels (pin to the bundled runtime version), browser engines, npm cache.355. **Package** — `electron-builder --win` (portable, requestExecutionLevel admin) and `--mac` (dmg). See `ci-and-platforms.md`.366. **Verify** — there is no clean machine here. Use: AST/`bash -n` syntax checks, a `HM_DRY_RUN` flag that prints "WOULD install X" without mutating, a config-deploy E2E into a sandbox `$HOME`, an offline `pip --dry-run` in a fresh venv, and a boot smoke. Then a real clean-machine run (or GitHub Actions) is the only true proof.377. **Polish** — a "What's next" finish screen (open editor button + auto-open checkbox, open-keys-file, return-to-bot link, video link, **retry-failed**), all driven by `config.json`.3839## Hard rules (from real failures — do not skip)4041- **Windows `.ps1` with non-ASCII MUST be UTF-8 with BOM**, else `powershell.exe` mis-reads it and the script won't parse. Re-apply BOM after every edit.42- **Install scripts: `$ErrorActionPreference='Continue'`, not `Stop`** — native tools (npm/pip/python) write notices to stderr; under `Stop` that becomes a fatal `NativeCommandError`. Use explicit `exit 0/1` + final verification for honest status.43- **Never `git add`/commit the built `.exe`/`.dmg`** — GitHub rejects files >100MB. Gitignore `*.exe *.dmg release/ release-mac/ vendor/ node_modules/`.44- **`.gitattributes`: `*.sh text eol=lf`** (CRLF breaks the shebang on Mac).45- A `.dmg` can be built **only on macOS** → use the GitHub Actions mac runner (`ci-and-platforms.md`).4647After creating or changing the skill, register it (routing.md row + CLAUDE.md count). The reference project is the source of truth for code — prefer reading/adapting it over writing from scratch.