@@ -29,6 +29,7 @@ const config: ForgeConfig = {
2929 icon : './public/icon' , // Electron Forge will append .icns, .ico, .png automatically
3030 extraResource : [
3131 './public' ,
32+ './runtime/llama' ,
3233 ] ,
3334 // Code signing configuration (uses .env locally, CI environment variables in automation)
3435 osxSign : ( isMAS ? {
@@ -74,83 +75,116 @@ const config: ForgeConfig = {
7475 // Hooks for post-processing after packaging
7576 hooks : {
7677 postPackage : async ( _config , options ) => {
77- // Only run for MAS builds on macOS
78- if ( ! isMAS || options . platform !== 'mas' ) {
78+ const isMacBuild = options . platform === 'darwin' || options . platform === 'mas' ;
79+ if ( ! isMacBuild ) {
7980 return ;
8081 }
8182
82- console . log ( '[postPackage] Re-signing helper apps with correct entitlements for MAS...' ) ;
83-
8483 const outputDir = options . outputPaths [ 0 ] ;
85- const identity = process . env . SIGNING_IDENTITY_APPSTORE || 'Apple Distribution' ;
86- const childEntitlements = path . resolve ( 'entitlements.child.plist' ) ;
87- const mainEntitlements = path . resolve ( 'entitlements.mas.plist' ) ;
88- const teamId = process . env . APPLE_TEAM_ID || '' ;
89- const bundleId = ( _config as any ) . packagerConfig . appBundleId || 'com.grabtaxi.klever' ;
90-
91- // Find the .app bundle inside the output directory
9284 const items = fs . readdirSync ( outputDir ) ;
9385 const appBundle = items . find ( item => item . endsWith ( '.app' ) ) ;
94-
9586 if ( ! appBundle ) {
96- console . log ( '[postPackage] No .app bundle found in output directory, skipping' ) ;
97- return ;
87+ throw new Error ( '[postPackage] No .app bundle found in output directory' ) ;
9888 }
9989
10090 const appPath = path . join ( outputDir , appBundle ) ;
10191 const frameworksPath = path . join ( appPath , 'Contents' , 'Frameworks' ) ;
92+ const runtimeRoot = path . join ( appPath , 'Contents' , 'Resources' , 'llama' , 'bin' ) ;
10293
103- console . log ( `[postPackage] App bundle: ${ appPath } ` ) ;
104- console . log ( `[postPackage] Frameworks path: ${ frameworksPath } ` ) ;
94+ const runtimeArtifacts = fs . existsSync ( runtimeRoot )
95+ ? fs . readdirSync ( runtimeRoot )
96+ . flatMap ( ( platformDir ) => {
97+ const platformDirPath = path . join ( runtimeRoot , platformDir ) ;
98+ if ( ! fs . existsSync ( platformDirPath ) || ! fs . statSync ( platformDirPath ) . isDirectory ( ) ) {
99+ return [ ] ;
100+ }
105101
106- if ( ! fs . existsSync ( frameworksPath ) ) {
107- console . log ( '[postPackage] No Frameworks directory found, skipping helper re-signing' ) ;
108- return ;
102+ return fs . readdirSync ( platformDirPath )
103+ . map ( ( entry ) => path . join ( platformDirPath , entry ) )
104+ . filter ( ( artifactPath ) => {
105+ if ( ! fs . existsSync ( artifactPath ) ) {
106+ return false ;
107+ }
108+ const stat = fs . lstatSync ( artifactPath ) ;
109+ if ( ! stat . isFile ( ) ) {
110+ return false ;
111+ }
112+
113+ const lowerName = path . basename ( artifactPath ) . toLowerCase ( ) ;
114+ return lowerName === 'llama-server'
115+ || lowerName === 'llama-server.exe'
116+ || lowerName . endsWith ( '.dylib' )
117+ || lowerName . endsWith ( '.so' ) ;
118+ } ) ;
119+ } )
120+ : [ ] ;
121+
122+ if ( runtimeArtifacts . length === 0 ) {
123+ throw new Error ( '[postPackage] Bundled llama runtime artifacts were not found in app package' ) ;
109124 }
110125
111- // Find all helper apps
112- const frameworkItems = fs . readdirSync ( frameworksPath ) ;
113- const helperApps = frameworkItems . filter ( item => item . endsWith ( '.app' ) ) ;
126+ const runtimeDynamicLibraries = runtimeArtifacts . filter ( ( artifactPath ) => {
127+ const lowerName = path . basename ( artifactPath ) . toLowerCase ( ) ;
128+ return lowerName . endsWith ( '.dylib' ) || lowerName . endsWith ( '.so' ) ;
129+ } ) ;
130+ if ( runtimeDynamicLibraries . length === 0 ) {
131+ throw new Error ( '[postPackage] Bundled llama runtime dynamic libraries were not found in app package' ) ;
132+ }
114133
115- console . log ( `[postPackage] Found ${ helperApps . length } helper apps to re-sign` ) ;
134+ if ( isMAS && options . platform === 'mas' ) {
135+ console . log ( '[postPackage] Re-signing helper apps and bundled runtime for MAS...' ) ;
136+ const identity = process . env . SIGNING_IDENTITY_APPSTORE || 'Apple Distribution' ;
137+ const childEntitlements = path . resolve ( 'entitlements.child.plist' ) ;
138+ const mainEntitlements = path . resolve ( 'entitlements.mas.plist' ) ;
139+ const teamId = process . env . APPLE_TEAM_ID || '' ;
140+ const bundleId = ( _config as any ) . packagerConfig . appBundleId || 'com.grabtaxi.klever' ;
116141
117- for ( const helperApp of helperApps ) {
118- const helperPath = path . join ( frameworksPath , helperApp ) ;
119- console . log ( `[postPackage] Re-signing helper: ${ helperApp } ` ) ;
142+ console . log ( `[postPackage] App bundle: ${ appPath } ` ) ;
143+ console . log ( `[postPackage] Frameworks path: ${ frameworksPath } ` ) ;
120144
121- try {
122- // Re-sign the helper app with child entitlements (inherit only)
145+ if ( ! fs . existsSync ( frameworksPath ) ) {
146+ console . log ( '[postPackage] No Frameworks directory found, skipping helper re-signing' ) ;
147+ } else {
148+ // Find all helper apps
149+ const frameworkItems = fs . readdirSync ( frameworksPath ) ;
150+ const helperApps = frameworkItems . filter ( item => item . endsWith ( '.app' ) ) ;
151+
152+ console . log ( `[postPackage] Found ${ helperApps . length } helper apps to re-sign` ) ;
153+
154+ for ( const helperApp of helperApps ) {
155+ const helperPath = path . join ( frameworksPath , helperApp ) ;
156+ console . log ( `[postPackage] Re-signing helper: ${ helperApp } ` ) ;
157+
158+ try {
159+ // Re-sign the helper app with child entitlements (inherit only)
160+ execSync (
161+ `codesign --force --sign "${ identity } " --entitlements "${ childEntitlements } " --timestamp=none "${ helperPath } "` ,
162+ { stdio : 'inherit' }
163+ ) ;
164+ console . log ( `[postPackage] ✅ Successfully re-signed: ${ helperApp } ` ) ;
165+ } catch ( error ) {
166+ console . error ( `[postPackage] ❌ Failed to re-sign ${ helperApp } :` , error ) ;
167+ throw error ;
168+ }
169+ }
170+ }
171+
172+ for ( const runtimeBinaryPath of runtimeArtifacts ) {
173+ console . log ( `[postPackage] Re-signing bundled runtime artifact: ${ runtimeBinaryPath } ` ) ;
123174 execSync (
124- `codesign --force --sign "${ identity } " --entitlements "${ childEntitlements } " --timestamp=none "${ helperPath } "` ,
175+ `codesign --force --sign "${ identity } " --entitlements "${ childEntitlements } " --timestamp=none "${ runtimeBinaryPath } "` ,
125176 { stdio : 'inherit' }
126177 ) ;
127- console . log ( `[postPackage] ✅ Successfully re-signed: ${ helperApp } ` ) ;
128-
129- // Verify the entitlements were applied
130- try {
131- const verifyOutput = execSync (
132- `codesign -d --entitlements - "${ helperPath } " 2>&1` ,
133- { encoding : 'utf8' }
134- ) ;
135- console . log ( `[postPackage] Verifying entitlements for ${ helperApp } :` ) ;
136- console . log ( verifyOutput ) ;
137- } catch ( verifyError ) {
138- console . error ( `[postPackage] ⚠️ Failed to verify entitlements for ${ helperApp } :` , verifyError ) ;
139- }
140- } catch ( error ) {
141- console . error ( `[postPackage] ❌ Failed to re-sign ${ helperApp } :` , error ) ;
142- throw error ;
143178 }
144- }
145179
146- // Re-sign the main app to update the seal after helper modifications
147- console . log ( '[postPackage] Re-signing main app to update seal...' ) ;
148- try {
149- // Create enhanced entitlements with application identifier for TestFlight
150- const mainEntitlementsContent = fs . readFileSync ( mainEntitlements , 'utf8' ) ;
151- const enhancedEntitlements = mainEntitlementsContent . replace (
152- '</dict>' ,
153- ` <!-- Required for TestFlight distribution -->
180+ // Re-sign the main app to update the seal after helper/runtime modifications
181+ console . log ( '[postPackage] Re-signing main app to update seal...' ) ;
182+ try {
183+ // Create enhanced entitlements with application identifier for TestFlight
184+ const mainEntitlementsContent = fs . readFileSync ( mainEntitlements , 'utf8' ) ;
185+ const enhancedEntitlements = mainEntitlementsContent . replace (
186+ '</dict>' ,
187+ ` <!-- Required for TestFlight distribution -->
154188 <key>com.apple.application-identifier</key>
155189 <string>${ teamId } .${ bundleId } </string>
156190 <key>com.apple.developer.team-identifier</key>
@@ -160,26 +194,32 @@ const config: ForgeConfig = {
160194 <string>${ teamId } .${ bundleId } </string>
161195 </array>
162196</dict>`
163- ) ;
197+ ) ;
164198
165- const tempEntitlements = path . join ( outputDir , 'temp-entitlements.plist' ) ;
166- fs . writeFileSync ( tempEntitlements , enhancedEntitlements ) ;
199+ const tempEntitlements = path . join ( outputDir , 'temp-entitlements.plist' ) ;
200+ fs . writeFileSync ( tempEntitlements , enhancedEntitlements ) ;
167201
168- execSync (
169- `codesign --force --sign "${ identity } " --entitlements "${ tempEntitlements } " --timestamp=none "${ appPath } "` ,
170- { stdio : 'inherit' }
171- ) ;
202+ execSync (
203+ `codesign --force --sign "${ identity } " --entitlements "${ tempEntitlements } " --timestamp=none "${ appPath } "` ,
204+ { stdio : 'inherit' }
205+ ) ;
172206
173- // Clean up temp file
174- fs . unlinkSync ( tempEntitlements ) ;
207+ // Clean up temp file
208+ fs . unlinkSync ( tempEntitlements ) ;
209+
210+ console . log ( '[postPackage] ✅ Successfully re-signed main app' ) ;
211+ } catch ( error ) {
212+ console . error ( '[postPackage] ❌ Failed to re-sign main app:' , error ) ;
213+ throw error ;
214+ }
215+ }
175216
176- console . log ( '[postPackage] ✅ Successfully re-signed main app' ) ;
177- } catch ( error ) {
178- console . error ( '[postPackage] ❌ Failed to re-sign main app:' , error ) ;
179- throw error ;
217+ for ( const runtimeBinaryPath of runtimeArtifacts ) {
218+ console . log ( `[postPackage] Verifying bundled runtime signature: ${ runtimeBinaryPath } ` ) ;
219+ execSync ( `codesign --verify --verbose=2 "${ runtimeBinaryPath } "` , { stdio : 'inherit' } ) ;
180220 }
181221
182- console . log ( '[postPackage] Helper re-signing complete' ) ;
222+ console . log ( '[postPackage] Bundled runtime verification complete' ) ;
183223 } ,
184224 } ,
185225 makers : [
0 commit comments