fix(mac): build-local.sh works on modern SDKs and copies the resource bundle by sm0keyyy · Pull Request #1262 · getagentseal/codeburn · GitHub
Skip to content

fix(mac): build-local.sh works on modern SDKs and copies the resource bundle - #1262

Draft
sm0keyyy wants to merge 1 commit into
getagentseal:mainfrom
sm0keyyy:fix/mac-build-local-script
Draft

fix(mac): build-local.sh works on modern SDKs and copies the resource bundle#1262
sm0keyyy wants to merge 1 commit into
getagentseal:mainfrom
sm0keyyy:fix/mac-build-local-script

Conversation

@sm0keyyy

@sm0keyyy sm0keyyy commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Summary

mac/Scripts/build-local.sh cannot produce a working app on a current macOS toolchain. This pull request corrects 2 defects. Neither is specific to any package manager or host configuration: the first breaks every app the script assembles, and the second stops the script before it compiles anything.

1. The assembled app could not launch, because the resource bundle was never copied

The script copies the product binary and the generated icons into the bundle, but not the SwiftPM resource bundle. Any app it assembled terminated during startup:

CodeBurnMenubar/resource_bundle_accessor.swift:44: Fatal error: unable to find bundle named CodeBurnMenubar_CodeBurnMenubar

Bundle.module resolves that bundle from the app's Contents/Resources. SwiftPM emits it as a sibling of the executable in the build products directory, so it has to be copied in alongside the binary. The script now copies every *.bundle from that directory.

This became reachable when target resources entered Package.swift; the script was never updated to match. It is independent of defect 2 and of any host specifics.

2. The script exited before compiling on any SDK newer than 14.x

Two hard exits made the script unusable on a current toolchain:

  • It required a swift.org toolchain in ~/Library/Developer/Toolchains/ and exited 1 when none was present, even though the swift provided by Xcode or the Command Line Tools is sufficient.
  • It required the active SDK to report 14.x and exited 1 otherwise.

Selection is now capability-driven rather than pinned. The compiler is a swift.org toolchain when one is installed, otherwise swift from PATH. The SDK is Xcode's when /Applications/Xcode.app is present, otherwise whatever xcrun reports. When the SDK is newer than 14.x and Xcode is absent, the script fails with an actionable message instead of a version mismatch.

Preferring Xcode's SDK is not cosmetic. On macOS 15+ SDKs SwiftUI's @State is a macro, and the plugin that expands it, libSwiftUIMacros.dylib, ships only inside Xcode. Command Line Tools 27.0 carries only libObservationMacros.dylib and libSwiftMacros.dylib, so compiling any view against the CLT SDK fails:

error: external macro implementation type 'SwiftUIMacros.StateMacro' could not be found for macro 'State()'; plugin for module 'SwiftUIMacros' not found

An SDK and its macro plugins must be used as a matched pair. Supplying Xcode 26.6's plugin to the CLT 27.0 SDK expands @State into a member that SDK does not declare:

macro expansion @State:1:46: error: type 'State<Value>' has no member '_makeStorage_v0'

Selecting Xcode's own SDK avoids this entirely: there @State is an ordinary property wrapper and no macro plugin participates in the build.

Two consequences follow. The @MainActor source rewriting is now gated to the 14.x SDK it was written for, because later SDKs already carry those annotations; the 14.* branch keeps the original perl rewrite verbatim. And the two-arch build is a single invocation, which routes through xcbuild and emits a fat binary directly, so the separate per-arch builds and the lipo merge that followed them are redundant.

Change evidence

Change Why Receipt
Copy every *.bundle from the products directory into Contents/Resources Without it, every app the script assembles dies during startup. Reproduced the pre-fix failure by launching the assembled bundle's executable directly: resource_bundle_accessor.swift:44: Fatal error: unable to find bundle named CodeBurnMenubar_CodeBurnMenubar, process exit code -5, no child process spawned. After the change, Contents/Resources lists AppIcon.icns, CodeBurnMenubar_CodeBurnMenubar.bundle, menubar-logo.png, and the same launch stays alive and spawns its codeburn serve --stdio child, confirmed by pgrep -P <app pid> reporting a matching ppid.
Capability-driven compiler and SDK selection The script exited 1 without compiling on a machine holding no swift.org toolchain and an SDK newer than 14.x. Ran mac/Scripts/build-local.sh dev-nixfix end to end: rc 0 in 41 s. Output records Toolchain : Apple Swift version 6.4 (swiftlang-6.4.0.33.1 clang-2100.3.33.1) and SDK : /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk (26.5), then ✓ Installed. Before the change the same invocation exited 1 at the toolchain probe on this host, having compiled nothing.
Unchanged universal output and deployment target Selection changes must not alter what ships. lipo -info on the assembled binary reports x86_64 arm64. vtool -show-build reports minos 14.0. Both match the script's prior contract.
Single two-arch invocation instead of per-arch builds plus lipo One invocation already emits a fat binary, leaving nothing to merge. swift build -c release --arch arm64 --arch x86_64 returned rc 0 in 38 s and lipo -info on the product reported x86_64 arm64, with no lipo -create step involved. --show-bin-path under the same flags resolves to .build/out/Products/Release, which is also where the resource bundle is emitted, so one query locates both copy sources.
@MainActor rewriting gated to the 14.x SDK The rewrite exists for an SDK whose SwiftUI lacks those annotations; running it elsewhere edits staged sources for no reason. The successful run above printed SDK 26.5 already annotates SwiftUI, skipping @MainActor patch and still produced a launchable app, so the rewrite is not required on the newer SDK. The 14.* branch retains the original perl invocation unchanged, so the legacy path is untouched.
No impact on the TypeScript surface The change set touches only mac/, so the existing suite must stay green. Ran npm test: 272 test files passed, 2 skipped; 3738 tests passed, 5 skipped, 0 failed; duration 34.30 s. Ran npm run build: rc 0, emitting dist/main.js (2.29 MB), dist/parse-worker.js (864.47 KB), and the dash bundle.

Environment

Verified on macOS 27.0, Apple Silicon, with no swift.org toolchain installed.

Fact Value
xcode-select -p /Library/Developer/CommandLineTools
Command Line Tools com.apple.pkg.CLTools_Executables version 27.0.0.0.1787197235
CLT host plugins libObservationMacros.dylib, libSwiftMacros.dylib only; no libSwiftUIMacros.dylib anywhere under CLT or its SDK
Xcode 26.6 (17F113), bundled SDK macOS 26.5, platform plugins include libSwiftUIMacros.dylib
~/Library/Developer/Toolchains absent

Note that xcode-select still points at the Command Line Tools in the verified run. The script selects Xcode's SDK explicitly, so a global xcode-select switch is not required and neither is sudo xcodebuild -license accept.

Notes

The script's header comment is unchanged and still describes the Sonoma case it was written for; the 14.x path behaves exactly as before.

The x86_64 slice was cross-compiled and not executed; only the arm64 slice was run.

Companion pull request #1263 fixes a separate runtime defect in CodeburnCLI.swift. The two do not overlap in files. This one is a prerequisite for building and verifying that change locally on a modern toolchain, so it should land first.

Testing

  • I have tested this locally against real data (not just unit tests)
  • npm test passes
  • npm run build succeeds

Real-data check: the app the fixed script assembles was installed to ~/Applications/CodeBurnMenubar.app, launched, and rendered a flame icon with a live dollar figure in the menu bar against the local corpus, with its codeburn serve --stdio child confirmed alive by ppid.

Files (1)

  • mac/Scripts/build-local.sh [MODIFIED] (+56 -28)

… bundle

The script copied the product binary and icons into the bundle but never the
SwiftPM resource bundle, so every app it assembled died at startup with
'unable to find bundle named CodeBurnMenubar_CodeBurnMenubar'.

It also exited 1 before compiling on any SDK newer than 14.x, and required a
swift.org toolchain that is unnecessary when Xcode or the Command Line Tools
provide swift. Selection is now capability-driven, preferring Xcode's SDK
because libSwiftUIMacros.dylib, which expands SwiftUI's @State macro on
macOS 15+ SDKs, ships only inside Xcode.

Gates the @mainactor rewrite to the 14.x SDK it was written for, and drops the
redundant per-arch builds plus lipo merge in favour of one two-arch build.
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.

1 participant