Repository navigation
feat(desktop): package the macOS desktop shell as Maka.app - #6208
Conversation
macOS names a process after the bundle its executable is in, so the desktop window showed up as maka-desktop-shell with the generic executable icon. On macOS, build-cli now stages Maka.app beside maka (the shell, the authored app, an Info.plist from the app manifest and an icon from assets/logo.png), maka desktop starts the shell inside it, and the darwin native packages carry bin/Maka.app instead of bin/maka-desktop-shell and bin/app. The archive checks derive their member, directory and cache rules from per-target paths, so the receipt covers the Info.plist and icon and the cache check covers the whole bundle. Linux and Windows keep their layout. Generated-by: Claude Code
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
Post-merge review of 658ea3b7ebee0ebe6fe01a31917d3b35dce690c2. This PR was merged into rust-preview as 30513dc9 at 08:13 UTC on October 21, before this review was posted. Two independent review passes looked at the whole change (merge base c3100120 → head, 17 files, +536/-108). Neither found a P0–P2 defect. The findings below are P3 follow-ups.
What holds up
- Package acceptance (
distribution/archive.rs,target.rs). On darwin, the bundle shell,Info.plist,Maka.icnsand the two app files are required and must be non-empty regular files. Optional files are accepted only underbin/Maka.app/Contents/Resources/app/, using an exact prefix match. Anything else inside the bundle is refused, includingContents/Frameworks/*,_CodeSignature/*and the old darwinbin/app/*layout. Directory entries are only skipped, never created. The bundle shell is treated as the executable and goes through Mach-O validation. We found no way for a malformed or tampered archive to pass. - Cache integrity. The cache key and receipt binding are unchanged.
cached()now walks the wholebin/Maka.apptree, which covers both locations the shell searches for its app. Symlinks and unrecorded files are refused. - Paths agree across
scripts/rust/build-cli.mjs,cli/src/desktop.rsanddistribution/target.rs, and with gpui-shell's lookup inhost/installed.rs. Linux and Windows layouts are unchanged. There is no protocol or epoch change.
P3 follow-ups
- Existing macOS preview installs cannot self-update to the first release with this layout.
maka upgradeand the deployment policy worker validate the new package with the installed binary's rules. Before this PR, those rules requirebin/maka-desktop-shelland accept onlybin/app/*. The new package is therefore refused with "native package contains an invalid, duplicate, or oversized member". No layout satisfies both versions, and the PR body discloses the break. Still, the error does not say why it failed, so the release notes should tell macOS preview users to reinstall withnpm install -g @maka-agent/cli@rust-preview. - The development bundle can go stale. The bundle is a copy. After a Cargo-only
cargo build -p maka-desktop-shell,maka desktopon macOS keeps running the old shell untiljust buildruns again.just buildalso removestarget/*/app, so running the bare shell with no arguments no longer finds an app. Both behaviours are documented in the README. - No CI exercised these changes.
ci.ymlruns only for PRs intomain. The only check on this head was the Websitevalidatejob, and publication was skipped. The changed Rust tests (distribution tests,tests/integration/desktop.rs) have not been executed by CI or by us. We read them by hand and saw nothing that would fail. Please runcargo nextest run -p maka-cliand a manually dispatchednpm-publication.yml(darwin build/pack/install/--version) onrust-preview. - Signing and Gatekeeper are untested. The bundle carries only the linker's ad-hoc signature on the executable, and nothing seals the bundle's resources. That works when
maka desktopspawns the shell, and the author confirmed it on arm64.codesign --verify, Gatekeeper on a quarantined copy, notarization, Dock identity and icon presentation still need a check on macOS. - (Predates this PR, for information.) On Linux and Windows, gpui-shell checks
<entry>/Resources/appbeforebin/app, butcached()walks onlybin/app. An unrecordedResources/app/in a cache entry would therefore load without being detected. The cache directory is private, and the macOS layout added here is not affected.
Validation (Linux)
- The 13 tests in the four related Node build, packaging, release and launcher test files passed with Node 24 and the pinned npm 11.19.0. With a newer local npm,
pack-cli.test.mjsfails, but it fails the same way at the merge base. - We called the real
stageDesktopBundleon the current 69 app files and the product logo. Every file stayed byte-identical. The plist parsed, and its identity, name and version matchgpui-shell.jsonand gpui-shell's own bundler keys. The PNG decodes as 1024×1024, the ICNS payload is a validic10entry, and the shell is 0755. A failed staging run (source symlink) kept the previous bundle and cleaned up its temporary directories. This probe used stand-in shell bytes, so it checks the packaging structure, not a real macOS binary. - The license check, JavaScript and Rust formatting, and
git diff --checkpassed. - A Rust test build was attempted but did not reach the test bodies within a 30-minute budget. The default build lacked host X11/pkg-config tooling, and a
--no-default-featuresbuild then timed out while compiling. Native macOS launch was not tested.
| } else { | ||
| "bin/maka-desktop-shell" | ||
| match self { | ||
| Self::DarwinArm64 | Self::DarwinX64 => "bin/Maka.app/Contents/MacOS/maka-desktop-shell", |
There was a problem hiding this comment.
P3: every pre-PR darwin binary requires bin/maka-desktop-shell and accepts only bin/app/*, so maka upgrade and the policy worker's distribution::fetch will refuse the first package with this layout ("invalid, duplicate, or oversized member"). No layout can satisfy both, and the break is disclosed, but please say in the release notes that macOS preview users need to reinstall through npm.
| await stageDesktopApp(repositoryRoot, join(dirname(binary), 'app')); | ||
| const directory = dirname(binary); | ||
| if (triple.includes('-apple-darwin')) { | ||
| await stageDesktopBundle( |
There was a problem hiding this comment.
P3: the bundle is a copy, so after cargo build -p maka-desktop-shell alone, maka desktop on macOS keeps running the old shell until just build runs again. The README documents this; noting it because before this PR the shell beside maka was the cargo output itself.
On macOS the desktop window showed up as
maka-desktop-shell, with the generic executable icon, in the Dock, the app switcher and the menu bar. macOS names a process after the bundle its executable is in, also when another process starts it directly, so the shell now runs from insideMaka.app. Layout agreed in #6078 (discussioncomment-19089554).macOS layout
build-clistagesMaka.appbesidemaka:Contents/MacOS/maka-desktop-shell,Contents/Resources/app/(the shell already looks for../Resources/app),Contents/Info.plist(name,idand version fromapp/gpui-shell.json, with the keys gpui-shell's ownbundlecommand writes) andContents/Resources/Maka.icns(assets/logo.png, which already has the macOS icon margin, as one 1024-pixel entry that macOS scales). A failed staging leaves the previous bundle in place. Theapp/sidecar besidemakafrom earlier builds is removed; cargo's baremaka-desktop-shellstays.maka desktopstartsMaka.app/Contents/MacOS/maka-desktop-shellbeside itself. Spawning,kill_on_dropand the cancel path are unchanged. Onlyjust buildrefreshes the bundle, so after rebuilding the shell with Cargo alone,just buildis needed again (noted in the desktop-shell README).Maka.appfrom Finder or Spotlight starts the shell without a Host, and the app reportsMAKA_HOST_ENDPOINT is not set.maka desktopremains the way to start it.@maka-agent/cli-darwin-*packages carrybin/makaandbin/Maka.app/instead ofbin/maka-desktop-shellandbin/app/.Package verification
Targetnames the desktop paths per target (desktop_executable,desktop_app,desktop_tree,desktop_members), andarchive.rsderives its rules from them:Info.plistandMaka.icns, so the receipt records them and the cache and import checks verify them.cached()checks the wholeMaka.apptree against the receipt, not only the app, because macOS reads more of a bundle than itsInfo.plist.release-cliandverify-releaserun--versionon the bundled shell, so the macOS jobs innpm-publication.ymlbuild, pack, install and run the bundle.ci.ymlruns on Linux and needs no change.Checked with a packed darwin-arm64 artifact
On macOS arm64, a release build packed with
pack-cli(validated bymaka host fetch) and installed withnpm install --offlineinto a new directory:bin/Maka.app/Contents/MacOS/maka-desktop-shellkept its executable bit.maka desktop --root …started from an unrelated working directory opened the window with the bundled app.lsappinforeports the nameMaka, bundle idorg.apache.maka.desktop, version0.1.0and the bundle path insidenode_modules; the Dock shows the logo.maka desktopended the shell and the Host within about 3 s.