@@ -272,18 +272,30 @@ def package_platform(platform, arch, output_dir):
272272 platform_dir .mkdir (parents = True , exist_ok = True )
273273
274274 # Copy executable if it exists
275- executable_name = "Jumperless"
276- if platform == "windows" :
277- executable_name + = ".exe "
278-
279- executable_path = Path ( f"dist/ { platform } / { executable_name } " )
280- if executable_path . exists ():
281- shutil .copy2 ( executable_path , platform_dir )
282- if platform != "windows" :
283- os . chmod ( platform_dir / executable_name , 0o755 )
284- print (f"Copied executable : { executable_name } " )
275+ if platform == "macos" :
276+ # Handle .app bundle for macOS
277+ app_bundle_name = "Jumperless.app "
278+ app_bundle_path = Path ( f"dist/ { platform } / { app_bundle_name } " )
279+ if app_bundle_path . exists ():
280+ # Copy the entire .app bundle
281+ shutil .copytree ( app_bundle_path , platform_dir / app_bundle_name , dirs_exist_ok = True )
282+ print ( f"Copied .app bundle: { app_bundle_name } " )
283+ else :
284+ print (f"Warning: .app bundle not found : { app_bundle_path } " )
285285 else :
286- print (f"Warning: Executable not found: { executable_path } " )
286+ # Handle regular executable for Windows/Linux
287+ executable_name = "Jumperless"
288+ if platform == "windows" :
289+ executable_name += ".exe"
290+
291+ executable_path = Path (f"dist/{ platform } /{ executable_name } " )
292+ if executable_path .exists ():
293+ shutil .copy2 (executable_path , platform_dir )
294+ if platform != "windows" :
295+ os .chmod (platform_dir / executable_name , 0o755 )
296+ print (f"Copied executable: { executable_name } " )
297+ else :
298+ print (f"Warning: Executable not found: { executable_path } " )
287299
288300 # Create Python fallback
289301 create_python_fallback (platform , arch , platform_dir )
@@ -318,25 +330,55 @@ def create_macos_dmg(macos_dir, arch):
318330 temp_dir .mkdir ()
319331
320332 try :
321- # Copy contents to temp directory with simpler names
333+ # Copy contents to temp directory
334+ python_fallback_dir = None
322335 for item in macos_dir .iterdir ():
323336 if item .is_dir ():
324- # Rename directories with spaces
325- safe_name = item .name .replace (" " , "_" )
326- shutil .copytree (item , temp_dir / safe_name )
337+ if "Python" in item .name :
338+ # Keep track of Python fallback directory
339+ python_fallback_dir = item .name
340+ shutil .copytree (item , temp_dir / item .name )
341+ else :
342+ shutil .copytree (item , temp_dir / item .name )
327343 else :
328344 shutil .copy2 (item , temp_dir )
329345
330- # Basic DMG creation with simpler arguments
346+ # Copy DMG assets if they exist
347+ icon_path = Path ("assets/icons/icon.icns" )
348+ background_path = Path ("JumperlessWokwiDMGwindow4x.png" )
349+
350+ if icon_path .exists ():
351+ shutil .copy2 (icon_path , temp_dir / "icon.icns" )
352+ if background_path .exists ():
353+ shutil .copy2 (background_path , temp_dir / "JumperlessWokwiDMGwindow4x.png" )
354+
355+ # Build DMG creation command
331356 cmd = [
332- "create-dmg" ,
333- "--volname" , "Jumperless" ,
357+ "create-dmg" ,
358+ "--volname" , "Jumperless" ,
334359 "--window-size" , "600" , "400" ,
335- "--icon-size" , "100" ,
336- dmg_name ,
337- str (temp_dir )
360+ "--icon-size" , "100" ,
361+ "--app-drop-link" , "450" , "200" ,
338362 ]
339-
363+
364+ # Add optional parameters if assets exist
365+ if (temp_dir / "icon.icns" ).exists ():
366+ cmd .extend (["--volicon" , str (temp_dir / "icon.icns" )])
367+ if (temp_dir / "JumperlessWokwiDMGwindow4x.png" ).exists ():
368+ cmd .extend (["--background" , str (temp_dir / "JumperlessWokwiDMGwindow4x.png" )])
369+
370+ # Add app icon positioning if .app bundle exists
371+ if (temp_dir / "Jumperless.app" ).exists ():
372+ cmd .extend (["--icon" , "Jumperless.app" , "150" , "200" ])
373+ cmd .extend (["--hide-extension" , "Jumperless.app" ])
374+
375+ # Add Python fallback folder if it exists
376+ if python_fallback_dir and (temp_dir / python_fallback_dir ).exists ():
377+ cmd .extend (["--add-folder" , python_fallback_dir , python_fallback_dir , "150" , "320" ])
378+
379+ # Add DMG name and source directory
380+ cmd .extend ([dmg_name , str (temp_dir )])
381+
340382 subprocess .run (cmd , check = True )
341383 print (f"DMG created: { dmg_name } " )
342384
@@ -375,11 +417,12 @@ def create_platform_readme(platform_dir, platform):
375417'''
376418 elif platform == "macos" :
377419 readme_content += '''
420+ Double-click `Jumperless.app` in Finder to run.
421+
422+ Or open from Terminal:
378423```bash
379- ./ Jumperless
424+ open Jumperless.app
380425```
381-
382- Or double-click the executable in Finder.
383426'''
384427 elif platform == "windows" :
385428 readme_content += '''
@@ -399,7 +442,7 @@ def create_platform_readme(platform_dir, platform):
399442
400443## Package Contents
401444
402- - `Jumperless''' + ('.exe' if platform == 'windows' else '' ) + '''` - Native executable
445+ - `Jumperless''' + ('.app' if platform == 'macos' else '. exe' if platform == 'windows' else '' ) + '''` - Native executable
403446- `Jumperless Python/` - Python source code fallback
404447- `README.md` - This file
405448
0 commit comments