根因(拿到的真实证据,不是猜的):v0.2.2(run 42322062879 / job 128248713926)与 v0.2.3 (run 42429017002 / job 128573547829)两份 check-run 注解逐字一致 —— 失败步骤是第 6 步 `Windows ARM64 工具链体检`,第 7 步 `cargo build` 状态 skipped。也就是说 v0.2.1~v0.2.3 五轮 全红都红在一个**编译前的启发式探针**上,真正的编译器/链接器一次都没说话。该探针的结论还与它 自己打印的快照矛盾:`SDK Lib 版本→um 架构: 10.0.22621.0→um:[arm,arm64,x64,x86,]` 明明在,却 同时报 `kernel32=缺失`(同一个 `find -path` 模式在本地合成目录树上命中)。runner 实况是 Windows 11 Arm64 + Visual Studio 2026 镜像,`VC.Tools.ARM64` 与 `Windows11SDK.22621/26100` 都装好了,M142 的 `setup.exe modify` 反倒返回非 0。 改: - release-build.yml:探针降级为「只取证」——vswhere 组件查询 + 各目录 `.lib` 计数 + arm64 `link.exe` 候选,一条 `::error::` 都不写、永不 exit 1;不再自动补装 VS。红绿只由 cargo/链接/静态 CRT 导入表门禁决定。cargo build 步给 arm64 显式备齐工具链: `rustup target add aarch64-pc-windows-msvc`、`vcvarsall.bat arm64` 取 `LIB`/`INCLUDE`、 vswhere 定位 arm64 `link.exe` 后导出 `CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER` (顺序不能反:只给链接器不给 LIB ⇒ LNK1181 kernel32.lib)。 - 新增 packaging/check_publish_slots.py(344 行,零依赖):名单 ⇄ 产物**两个方向**。 声明了缺 GUI/CLI ⇒ `::error::` + exit 1;有产物没声明 ⇒ `::warning::` 明说未发布(M142 之后 这个方向是静默的,裁剪步只 echo 一行 drop:)。另有源码级断言(名单每项必须存在且 mode=ci、 运行期名单必须等于文件里那行)与 8 条 `--self-test` 注入回归。 - release-publish.yml:裁剪前插一步跑那个守卫,原来内联的齐全性循环搬进脚本(一套判据一处实现); 重算 SHA256SUMS 的步骤只负责重算。 - release-guard.yml:PR 阶段跑守卫自测 + 源码级断言。 - 文档同步:release.yml / release-publish.yml / release-build.yml 头注释、packaging/README §12、 §1 矩阵、§3 构建与发布、§9 支持矩阵、§7.5 arm64 取证、release-notes.md、README/README.zh-CN 的产物矩阵与说明。口径统一为「arm64 构建取证中、未发布」,不写成已支持。 没做的(按 tower 裁决「方案乙」):`PUBLISH_SLOTS` 本轮**不加回** arm64。arm64 从未产出过 PE、 本机也证不了,写进名单就等于拿 x64 的发布去赌它(M142 移出名单正是为避免这个事故)。下一 tag 的 CI 真出包后翻一行即可,守卫与 SHA256SUMS 自动跟着扩。 验证:workflow YAML 全部可被 PyYAML 解析;所有 `run:` 块过 `bash -n`;探针步在本机(无 VS/SDK) 实跑 exit 0 并打出实况注解;守卫 `--self-test` 8 条全绿、正反两个方向都在合成 dist 上实测过; check_release_semantics.py(含 --self-mutation)/ release_marker / make_manifest 自检全绿; cargo metadata 正常。**arm64 产物从未被构建过、也从未在真机跑过**——本机 `rustc --target aarch64-pc-windows-msvc` 直接撞上没有 MSVC 链接器(git-bash 的 GNU `link` 被当成 link.exe), `cargo check --workspace --target aarch64-pc-windows-msvc` 也死在 aws-lc-sys 的 cc-rs 阶段 (GNU host 上没有该 target 的 C 编译器)。真实结论只能等下一 tag 的 CI。
10 KiB
Unlucky Launcher {{VERSION}}
Rust-native single-file Minecraft launcher: iced 0.14 + Material 3 Expressive UI, built-in AI agent (chat / setting edits / crash diagnosis) and an MCP server other agent tools can attach to. No WebView, no bundled runtime, no JRE download needed to start the launcher itself.
What's new in {{VERSION}}
- {{VERSION}} is the first release published as a stable release. GitHub only points
releases/latestat the newest non-prerelease release, so0.2.2— kept as a historical pre-release, untouched — never appeared there. A pushed tag now creates a stable release by default; a pre-release has to be asked for explicitly (workflow_dispatchwithprerelease=true). - Self-update works end to end.
ull update check/ull update applyand the settings panel's Update group share one core (crates/core/src/update/): manifest, version and channel admission, length + SHA256 verification, and an atomic rename-based swap that rolls back on failure. Only the stable channel is published today. - Online content library (Modrinth, anonymous). Search, project details and version lists come from Modrinth's v2 API with facets derived from the target instance, and a known hash completes a remote entry. Being offline is reported as "not connected", never as "no matching content".
- Per-file decisions when importing a modpack. The pre-import scan lists every conflicting file in pages of 40, and you choose keep-all, overwrite-all, or per item; files that do not conflict are never rewritten, and the report names every conflict afterwards.
- Per-instance launch arguments. JVM arguments, game arguments, memory, the Java executable and the
graphics backend (
default/opengl/vulkan) are set per instance, each field falling back on its own to the global setting and then the factory default. The CLI reads the same resolved values.
Downloads
Asset names are <name>_<version>_<platform>_<arch>, underscore separated — the rule
packaging/make_artifacts.py::asset_stem() applies:
| Platform | Asset | Notes |
|---|---|---|
| Windows 10/11 x64 | unlucky-launcher_{{VERSION}}_windows_x64.exe |
single exe, double-click to run; this is also what you run on ARM64 Windows (x64 emulation) |
Windows ARM64 is not part of this release. CI still builds it on a native windows-11-arm runner (Windows 11
Arm64 with Visual Studio 2026), but the build has not delivered an artifact yet, so
unlucky-launcher_{{VERSION}}_windows_arm64.exe is deliberately kept out of the download list and out of
SHA256SUMS.txt instead of handing out a build nobody has verified. Worth stating plainly: every ARM64 failure
so far happened in a pre-build toolchain probe that guessed whether the SDK's ARM64 import libraries were
present and aborted before cargo build ever ran — the compiler and linker have not been heard from yet. That
probe is now evidence-only (it prints what it sees and never decides the job), so the next CI run is the first
one that can actually answer the question. windows-x64 is the only published slot; ARM64 rejoins this table as
soon as a run produces its artifact (one line in the workflow's PUBLISH_SLOTS, guarded on both sides by
packaging/check_publish_slots.py).
This release ships Windows only, and CI builds Windows only. The Linux (x64 / arm64) and macOS
(Apple Silicon / Intel) slots are not built by the release workflow at all — they have not been verified
on real machines yet, so nothing unverified is handed out and no build minutes are spent on them. They
stay out of the download list and out of SHA256SUMS.txt until that verification happens; a manual
workflow run can build all six slots for that purpose, but the four extra slots are never published. The
support matrix below marks those slots accordingly.
The Windows asset is a bare .exe, so LICENSE, NOTICE and README.md are attached to this release
next to it: the license terms travel with every download. Slots that ship an archive (Linux / macOS, once
published) unpack to one top-level directory of the same name holding the binary plus those three
documents.
Command line
Each published slot also ships the command line as its own small bare asset,
ull_{{VERSION}}_<platform>_<arch> (.exe on Windows):
.\ull_{{VERSION}}_windows_x64.exe instances list # servers and CI: no graphics stack needed
ull runs instances, install, pack import, launch, accounts, sessions, logs, diag,
config, java and agent, and links no graphics library at all. The GUI binary accepts the same set
before it ever opens a window, so a desktop machine does not need ull.
Updating
The launcher reads releases/latest/download/manifest.json on startup (switchable: update.auto_check)
and shows four distinct outcomes: up to date, an update is available, a newer version exists but ships no
artifact for this platform, or the check itself failed. ull update check prints the same verdict, and
ull update apply downloads, verifies SHA256 and swaps the binary atomically, rolling back if the swap
fails. Nothing installs without you asking for it.
Support matrix
Published = shipped as a download of this release, listed in SHA256SUMS.txt.
| Platform | Status in this release | Level | Runtime requirements |
|---|---|---|---|
| Windows 10/11 x64 | published | first class | nothing beyond the OS (UCRT is part of Win10+) |
| Windows 11 ARM64 | not published (build evidence only) | first class (launcher artifact) | nothing extra; the launcher runs natively, the game itself runs through the OS x64 emulation layer with an x64 JDK |
| macOS 12+ Apple Silicon | not built (unverified) | first class (unverified) | nothing; unsigned build, needs the Gatekeeper workaround |
| macOS 12+ Intel | not built (unverified) | first class (unverified) | same as above |
| Linux x64, X11 | not built (unverified) | first class (unverified) | libxkbcommon, fontconfig, libGL (or software renderer), libxcb |
| Linux x64, Wayland | not built (unverified) | supported (unverified) | wayland-client, libxkbcommon, plus the X11 set for XWayland apps |
| Linux arm64, X11 | not built (unverified) | first class (unverified) | glibc 2.35+, libxkbcommon, fontconfig, libGL, libxcb |
| Linux arm64, Wayland | not built (unverified) | supported (unverified) | the above plus wayland-client |
| Windows 8.1/8/7 | not built | unsupported | the baseline is Windows 10 |
| Android — Termux + X11 | not built (no CI slot) | experimental, not promised | CLI and GUI from source only; GUI verified on-device twice: CPU software rendering and self-built Mesa/turnip GPU acceleration (see packaging/docs/termux-glibc-build.md and README.termux.md) |
windows-x64 is the only published slot this release; Windows ARM64 stays out until a CI run actually produces
its artifact (see Downloads above — so far every ARM64 failure was the pre-build probe, never the compiler).
Both arm64 rows are formal matrix slots, not the experimental Termux path, and Linux arm64 is not built by
default — someone has to run it on real hardware (via a manual all-slots run) before it joins this list. The
rows above and the matrix table in packaging/docs/compliance-support-boundaries.md §9 are the same list —
change one, change the other.
Install
Windows — put the .exe anywhere and run it. _windows_x64.exe is the only Windows asset in this
release, and it is also what you run on ARM64 Windows (the OS runs it through its x64 emulation layer).
The first run creates .ULL/ and .minecraft/ next to the exe (portable is the default data mode); the
per-user %APPDATA%\ULL plus %APPDATA%\.minecraft, or a custom root, are selectable instead.
Linux / macOS are not part of this release; their asset names are already fixed by the same rule
(unlucky-launcher_{{VERSION}}_linux_x64.tar.gz, _linux_arm64, _macos_arm64, _macos_x64) so the
links will not change shape when those slots open.
No GPU? Software renderer
The UI renders through wgpu (GPU) and falls back to the tiny-skia CPU rasteriser when no usable
adapter is present; --software-renderer (or its equivalent --renderer=cpu) forces that path.
Verify the download
SHA256SUMS.txt lists exactly the assets attached to this release (Windows only), and sha256sum -c
checks the ones you actually downloaded:
sha256sum -c SHA256SUMS.txt --ignore-missing # Linux / WSL
shasum -a 256 -c SHA256SUMS.txt # macOS (sha256sum is not bundled)
Get-FileHash .\unlucky-launcher_{{VERSION}}_windows_x64.exe -Algorithm SHA256 # Windows PowerShell
{{SUMS}}
Known limitations of this build
- Microsoft (MSA) sign-in works out of the box: this build carries the Azure public client id it needs
(a public client id, not a credential — it ships inside the binary), so there is nothing to configure
before signing in. Setting
ULL_MSA_CLIENT_ID=<id>before launching still overrides it; the variable is read at startup, so restart the launcher after changing it. A build with no id anywhere stops before any network call, and the GUI banner says so plainly: the title "Microsoft sign-in is not configured", a body namingULL_MSA_CLIENT_ID=<id>(set it, or build with it, then restart) andCode: msa_not_configured, with no Retry button. Every other sign-in failure keeps the generic banner plus its ownCode:line, with the full reason only in the launcher log.ull accounts add msaprints the same fix on the command line. Offline profiles and authlib-injector servers need no id. - Binaries are not code-signed / notarized yet: Windows SmartScreen and macOS Gatekeeper warn on first launch. The checksums above are the integrity reference for now.
- When the macOS slot ships it is the bare binary (single-file promise), not a
.appbundle: no Dock icon or Finder double-click — launch it from a terminal.
License
Apache-2.0, third-party notices in NOTICE. Not affiliated with Mojang or Microsoft; no game files ship.
UI framework in this build
Every asset here is built from the iced UI (crates/app-iced, iced 0.14, MIT); no other UI framework is
linked into it.