@@ -113,6 +113,62 @@ describe("package-mac-dist plist validation", () => {
113113 expect ( script ) . not . toContain ( 'canonical_sparkle_build "$VERSION" 2>/dev/null || true' ) ;
114114 } ) ;
115115
116+ it ( "checks Swift before Sparkle metadata or dependency bootstrap work" , ( ) => {
117+ const script = readFileSync ( scriptPath , "utf8" ) ;
118+ const swiftIndex = script . indexOf ( "\nrequire_swift_toolchain\n" ) ;
119+ const versionIndex = script . indexOf ( 'if [[ -z "$APP_VERSION_INPUT" ]]' ) ;
120+ const appBuildIndex = script . indexOf (
121+ 'if [[ -z "${APP_BUILD:-}" && "$BUILD_CONFIG" == "release" ]]' ,
122+ ) ;
123+ const packageAppIndex = script . indexOf ( '"$ROOT_DIR/scripts/package-mac-app.sh"' ) ;
124+ const preSwiftBlock = script . slice ( 0 , swiftIndex ) ;
125+
126+ expect ( script ) . toContain ( 'source "$ROOT_DIR/scripts/lib/swift-toolchain.sh"' ) ;
127+ expect ( swiftIndex ) . toBeGreaterThanOrEqual ( 0 ) ;
128+ expect ( versionIndex ) . toBeGreaterThan ( swiftIndex ) ;
129+ expect ( appBuildIndex ) . toBeGreaterThan ( versionIndex ) ;
130+ expect ( packageAppIndex ) . toBeGreaterThan ( appBuildIndex ) ;
131+ expect ( preSwiftBlock ) . not . toContain ( "node -p" ) ;
132+ } ) ;
133+
134+ it ( "fails on old Swift before reading package metadata" , ( ) => {
135+ const toolsDir = mkdtempSync ( path . join ( tmpdir ( ) , "openclaw-dist-swift-tools-" ) ) ;
136+ tempDirs . push ( toolsDir ) ;
137+
138+ writeFileSync (
139+ path . join ( toolsDir , "swift" ) ,
140+ [
141+ "#!/usr/bin/env bash" ,
142+ "echo 'swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)'" ,
143+ "" ,
144+ ] . join ( "\n" ) ,
145+ "utf8" ,
146+ ) ;
147+ chmodSync ( path . join ( toolsDir , "swift" ) , 0o755 ) ;
148+ writeFileSync (
149+ path . join ( toolsDir , "node" ) ,
150+ [
151+ "#!/usr/bin/env bash" ,
152+ "echo 'node should not run before Swift preflight' >&2" ,
153+ "exit 42" ,
154+ "" ,
155+ ] . join ( "\n" ) ,
156+ "utf8" ,
157+ ) ;
158+ chmodSync ( path . join ( toolsDir , "node" ) , 0o755 ) ;
159+
160+ const result = runHelper ( `
161+ set -euo pipefail
162+ PATH=${ JSON . stringify ( `${ toolsDir } :/usr/bin:/bin` ) }
163+ BUILD_CONFIG=release bash ${ scriptPath }
164+ ` ) ;
165+
166+ expect ( result . status ) . toBe ( 1 ) ;
167+ expect ( result . stderr ) . toContain ( "OpenClaw macOS app packaging requires Swift tools 6.2+" ) ;
168+ expect ( result . stderr ) . toContain ( "Current Swift is 6.0" ) ;
169+ expect ( result . stderr ) . not . toContain ( "node should not run before Swift preflight" ) ;
170+ } ) ;
171+
116172 it ( "prefers repo Corepack pnpm over a global pnpm shim" , ( ) => {
117173 const helperBlock = getPackageManagerHelperBlock ( ) ;
118174 const tempRoot = mkdtempSync ( path . join ( tmpdir ( ) , "openclaw-dist-pnpm-root-" ) ) ;
0 commit comments