Skip to content

macOS support, GitHub Releases updates, and a semi-automatic Root wizard (v1.0.7)#4

Merged
Birditch merged 15 commits into
Birditch:mainfrom
backspace135:codex/macos-github-updates
Jul 15, 2026
Merged

macOS support, GitHub Releases updates, and a semi-automatic Root wizard (v1.0.7)#4
Birditch merged 15 commits into
Birditch:mainfrom
backspace135:codex/macos-github-updates

Conversation

@backspace135

@backspace135 backspace135 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

拉取请求 (Pull Request)

摘要 (Summary)

This branch carries three separable bodies of work: macOS support, an update path backed by GitHub
Releases, and a semi-automatic Root wizard. The Root wizard is the one that needs a real decision from
you, because it deliberately changes the project's read-only guarantee — this PR edits AGENTS.md
to carve out one exception.

The exception is narrow: the wizard extracts boot/init_boot from a user-supplied firmware package,
patches it with components taken from the pinned official Magisk APK, and flashes only that
evidence-backed image, after a backup, ADB-to-fastboot identity verification, unlock/layout checks and
an explicit risk acknowledgement. It never unlocks the bootloader and never writes system, vendor,
vbmeta, recovery or super.

What you should weigh: this can brick a phone, and there is no environment-variable kill switch —
the only thing between a user and a real write is the in-app confirmation screen and its checkbox. If
the read-only guarantee is load-bearing for you, this section is a "no" and the other two parts still
stand on their own; say so and they can be split out.

SIGN 声明 (SIGN Declaration)

  • SIGN: 我确认我有权提交这些改动,并同意它们按本仓库许可证发布。
    (I certify that I have the right to submit this work and agree it is provided under this repository's license.)

类型 (Type)

  • 缺陷修复 (Bug fix)
  • 新功能 (Feature)
  • 文档 (Documentation)
  • 重构 (Refactor)
  • 测试 (Test)
  • 维护 (Maintenance)

细节 (Details)

1. Root wizard — validated end-to-end on real hardware

Verified on a real Redmi Note 9 5G (cannon, MT6853, Android 12 / MIUI 14): extract → patch → flash →
boot. The device boots normally and is rooted — magisk -c reports 30.7:MAGISK:R (30700), i.e. the
daemon is live, which only happens if the patched boot actually booted.

Getting there surfaced the bug worth reviewing carefully. boot_patch.sh silently defaults a missing
flag to false and ends in a bare true, so its exit code proves nothing. The first implementation
invoked it with no environment at all. On a system-as-root device KEEPVERITY=false strips logical
and first_stage_mount off the /system fstab entry:

official: system /system ext4 ro wait,,avb=vbmeta_system,logical,first_stage_mount,avb_keys=...
ours:     system /system ext4 ro wait,

First-stage init then cannot mount the root filesystem — a guaranteed bootloop, which is exactly what
happened on the first real flash. Note this is not the AOSP "no avb, mount directly" fallback: the
entry loses first_stage_mount entirely, so first-stage never considers it.

The fix runs official Magisk's own app_init probe (app_functions.sh) on the device and passes the
derived flags to boot_patch.sh. Measured against the official Magisk app's output for the same
boot.img:

SHA-256
without the probed flags 992692fb…
with the probed flags 61d9c187…
official Magisk app 61d9c187…

Byte-for-byte identical to what the official app produces.

As defence in depth, the patched image's own config is read back out of the ramdisk and compared to
the probed flags before the image can reach the flash step. Neither an exit code nor a header check
can catch a wrongly-flagged image — it is structurally valid. With the fix reverted, this gate rejects
the image with the exact diagnostic, before any write.

Deliberately not done: no vbmeta flashing. Official Magisk flashes a single partition, this device
reports PATCHVBMETAFLAG=false, and upstream documents fastboot flash vbmeta --disable-verity as
optional and data-wiping. Keeping vbmeta out of scope is correct.

2. macOS support

CLI terminal fix, app bundle icon with safe-area padding, signed .app bundles, and a Mini.Mac
Avalonia variant.

3. Updates via GitHub Releases

Replaces the previous private HTTP index (NekoIndexUpdateService, pointing at a hard-coded LAN
address) with GitHubUpdateService reading GitHub Releases, plus SHA-256 verification of assets.

安全影响 (Security Impact)

  • 未修改 GitHub Actions、发布脚本、打包脚本或二进制产物。
    (No GitHub Actions, release scripts, packaging scripts, or binary artifacts were changed.)
  • 如修改了上述敏感区域,我已在摘要或细节中说明原因。
    (If sensitive areas were changed, I explained why in the summary or details.)

Sensitive areas changed, and why:

  • .github/workflows/publish.yml — verifies the Root tool pins, and asserts Mini ZIPs contain no
    root-tools/ (Root tooling is App-only).
  • build/AndroidTreeView.RootTools.targets (new) — downloads the pinned Magisk APK and
    payload-dumper-go, each SHA-256 verified at build time.
  • build/AndroidTreeView.Scrcpy.targets — pins platform-tools to an explicit version + SHA-256
    instead of -latest, and folds in a SHA-256-verified fastboot.
  • tools/verify-roottools-latest.ps1 (new) — mirrors the existing scrcpy pin check for Root tools.
  • packaging/build-update-zip.ps1, packaging/build-msi.ps1, packaging/*.wxs — version bump only.

No third-party binary is committed to the repository; every bundled tool is fetched at build time from
its official release URL and checked against a pinned SHA-256.

验证 (Verification)

  • dotnet build -c Release 通过 (build succeeds).
  • dotnet test -c Release 通过 (tests pass). — 419 tests, 0 failures.
  • 已运行 dotnet format --verify-no-changes(或已格式化)(code is formatted).
  • 行为或 API 变化时,我已更新文档与本地化文案 (updated docs and localization strings when behavior or API changed).
  • 我已考虑无障碍、性能和兼容性影响 (I considered accessibility, performance, and compatibility impact).

On the format box — left unchecked on purpose. dotnet format --verify-no-changes currently fails
repo-wide with ~7028 ENDOFLINE errors, including files this PR never touches (AppInfo.cs,
Mini/Program.cs, GitHubUpdateService.cs, …). The tree stores CRLF while .editorconfig
(end_of_line = lf) and .gitattributes (* text=auto eol=lf) both specify LF. That is a
pre-existing condition; renormalizing the whole repo would bury this PR under an unrelated diff, so it
is left alone. Worth a separate cleanup — note AGENTS.md also documents "CRLF line endings", which
contradicts both config files.

Also built and verified all four release ZIPs at 1.0.7 (App/Mini × win-x64/osx-arm64), and bumped every
field in docs/app-contract.md's alignment list.

Fixes a pre-existing broken README image link on the way past: it pointed at
docs/images/product-devices-v1.0.6.png, which was never added to the repo. Now points at v1.0.5,
which exists.

关联 Issue (Related Issues)

🤖 Generated with Claude Code

backspace135 and others added 13 commits July 9, 2026 15:43
- CliLauncher: branch by platform. macOS now writes an equivalent .command
  shell script with the same numbered menu and opens it in Terminal.app;
  previously it hardcoded cmd.exe + .bat and failed silently on macOS.
- Surface launch failures via Notifier (toast) instead of only logging.
- Add cli.unsupported / cli.launchFailed strings to both ResX files.
- Packaging: generate AppIcon.icns from atv-icon.png (sips + iconutil) and
  set CFBundleIconFile so the macOS .app shows an icon in Dock/Finder.
Sync version across AppInfo, App/Mini/Mini.Mac project metadata,
app.manifest, packaging scripts, wix, docs, and README.
- Platform badge Windows -> Windows + macOS
- Describe as cross-platform (Windows + macOS Apple Silicon), not Windows-only
- Generalize the usage section and add a macOS subsection (Terminal.app CLI,
  drag to /Applications, Gatekeeper). English README already covered this.
分步向导:上传刷机包→提取 boot.img→手机端官方 Magisk 修补→进 bootloader→flash boot,写操作前强制确认+自动备份原始 boot。双平台(Windows/macOS)。
- 构建时打包固定版 Magisk APK(SHA-256 校验),运行时 adb install
- 修补改用已装 App 自带的 boot_patch.sh + native 组件,不再桌面侧拆各 ABI 二进制
- 同步 §1.1/§2/§3/§4/§5.1/§6.2/§7/§8/§10/§11/§13
- 保留第 4 步实机验证警告(已装 App 脚本能否被 adb shell 直接调到仍待验证)
…con' into fix/macos-cli-terminal-and-app-icon

# Conflicts:
#	CLAUDE.md
Adds the semi-automatic Root wizard: extract boot/init_boot from a
user-supplied firmware package, patch it with components taken from the
pinned official Magisk APK, and flash it after backup, ADB-to-fastboot
identity verification, unlock/layout checks and explicit confirmation.

This is a deliberate exception to the read-only stance: the wizard writes
only an evidence-backed boot / init_boot image. It never unlocks the
bootloader and never touches system, vendor, vbmeta, recovery or super.

Patch flags are probed on the device with official Magisk's own app_init
(app_functions.sh) and passed to boot_patch.sh as environment variables.
This is not optional: boot_patch.sh silently defaults a missing flag to
false and ends in a bare `true`, so its exit code proves nothing. On a
system-as-root device KEEPVERITY=false strips `logical` and
`first_stage_mount` off the /system fstab entry, leaving first-stage init
unable to mount the root filesystem — a guaranteed bootloop. Verified on
a real Redmi Note 9 5G (cannon, MT6853, Android 12/MIUI 14): with the
probed flags the patcher reproduces the official Magisk app's output
byte-for-byte; without them it does not.

As defence in depth, the patched image's own config is read back out of
the ramdisk and compared against the probed flags before the image is
allowed anywhere near the flash step. Neither the exit code nor a header
check can catch a wrongly-flagged image — it is structurally valid.

Bumps every aligned version field to 1.0.7 and points the README device
screenshot at the image that actually exists (v1.0.5); it had referenced
a v1.0.6 file that was never added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@backspace135
backspace135 requested a review from Birditch as a code owner July 15, 2026 05:15
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

ChatGPT PR 初审

我会先对改动里最容易影响发布和真实设备写入的部分做针对性检查:打包脚本、Root 写入门控、更新解析和 CI 校验。重点只放在能明确导致构建/发布失败或用户设备风险的证据上。
当前 PR 面很大,单靠摘要不足以判断阻塞项。我会直接查看工作区里的相关文件,优先确认是否有确定性的构建或发布问题。
我会读取关键文件而不是逐项展开所有新增代码,这样可以把评审集中在高风险路径上:Root 工具目标、发布 ZIP 脚本、服务注册和写入流程。
先看发布脚本和目标文件是否一致,尤其是 macOS/Windows 路径和 Root tools 隔离,这类问题一旦错了会直接破坏 release。
我现在检查本地文件内容和 diff 中没有展开的部分,确认是否存在高置信度问题。
我会并行读取几个关键文件,减少来回等待。
先从 RootWizardServiceRootFastbootServicebuild-update-zip.ps1 和项目文件入手。
如果这些文件没有明显问题,再抽查更新服务和测试覆盖,不会把风格或拆分建议当成阻塞。

结论

建议通过。基于提供的 diff,未发现高置信度的构建、CI、发布、安全或真实用户必现故障阻塞项。Root 向导确实改变项目原本的只读边界,但 PR 已明确披露风险,并在代码/文档层面加入备份、身份校验、目标分区限制、确认门控和打包隔离,是否接受该产品方向属于维护者决策,不应作为自动评审阻塞。

阻塞问题

非阻塞建议

  • Root 向导涉及真实刷写 boot / init_boot,建议维护者在合并前明确接受 AGENTS.md 中新增的只读例外;如果项目仍坚持绝对只读,可要求作者拆分 macOS 支持和 GitHub Releases 更新部分。
  • 建议在发布前跑一次完整 Publish workflow,尤其确认 root-tools/ 只进入 App 包、Mini 包不包含 Root 工具,以及 macOS ZIP 中 payload-dumper-go 保留可执行位。
  • docs/roadmap-features.md 中仍提到“environment override / default flash gate”的表述,与 PR 正文“没有环境变量 kill switch”的描述可能让后续维护者困惑,建议后续清理为当前实际门控模型。

这是自动初审建议,不代表维护者正式批准。第三方 PR 的代码没有在此 workflow 中执行。

backspace135 and others added 2 commits July 15, 2026 13:28
`tools/verify-scrcpy-latest.ps1` asserts the pin equals the latest upstream
release, so the Publish workflow started failing the moment scrcpy 4.1 shipped
on 2026-07-12. Unrelated to anything else in this branch.

Verified by running the packaged binary, not by trusting the pin: the rebuilt
osx-arm64 bundle reports `scrcpy 4.1`.

Worth knowing for the next bump: `Get-ScrcpyRoot` in build-update-zip.ps1 caches
at artifacts/tools/scrcpy/<rid> and keys the cache on whether the executable
exists, not on its version. A local rebuild after a version bump therefore keeps
the old binary and silently produces a stale package — CI is unaffected because
it always starts from a clean tree. Delete artifacts/tools/scrcpy to force it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The macOS packaging job died with "/usr/bin/test is not recognized". `test`
lives at /bin/test on macOS; /usr/bin/test is a Linux path. Only the App
osx-arm64 job reached this branch, so it was the only one to fail.

Uses System.IO.File.GetUnixFileMode instead of shelling out, which needs no
external binary and no assumption about its path.

Reproduced the failure and verified the fix locally under pwsh on macOS,
including stripping the exec bit to confirm the check still rejects a
non-executable payload-dumper-go.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Birditch
Birditch merged commit 61d135e into Birditch:main Jul 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants