Release 2.7.1: fix macOS DMG launch, cores path and naive download.

Use UDZO DMG via hdiutil, store cores under Application Support, and match new naiveproxy mac asset names.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
M4
2026-07-29 16:31:37 +03:00
co-authored by Cursor
parent 2d4a797eb1
commit 53eb845d04
16 changed files with 182 additions and 34 deletions
+83 -12
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
@@ -45,6 +46,9 @@ func run(binPath, outDir, version, arch string) error {
if err := writeAppBundle(appRoot, binPath, version, arch); err != nil {
return err
}
if err := signAppBundle(appRoot); err != nil {
return err
}
readme := filepath.Join(stage, "README.txt")
if err := os.WriteFile(readme, []byte(readmeText(version, arch)), 0o644); err != nil {
return err
@@ -67,18 +71,58 @@ func run(binPath, outDir, version, arch string) error {
fmt.Println("wrote", zipPath)
dmgPath := filepath.Join(outDir, "Navis.dmg")
dmgFiles := []dmgEntry{{appRoot, "/Navis.app"}}
if warnName != "" {
dmgFiles = append(dmgFiles, dmgEntry{filepath.Join(stage, warnName), "/" + warnName})
}
dmgFiles = append(dmgFiles, dmgEntry{readme, "/README.txt"})
if err := writeDMG(dmgPath, dmgFiles, "Navis-"+arch); err != nil {
if err := writeNativeOrISODmg(dmgPath, stage, "Navis-"+arch); err != nil {
return fmt.Errorf("dmg: %w", err)
}
fmt.Println("wrote", dmgPath)
return nil
}
// writeNativeOrISODmg prefers hdiutil (real UDIF DMG) on macOS; ISO9660 breaks .app launch.
func writeNativeOrISODmg(dmgPath, stageDir, volume string) error {
if _, err := exec.LookPath("hdiutil"); err == nil {
return writeHdiutilDMG(dmgPath, stageDir, volume)
}
entries := []dmgEntry{}
_ = filepath.Walk(stageDir, func(path string, info os.FileInfo, err error) error {
if err != nil || info == nil {
return err
}
rel, err := filepath.Rel(stageDir, path)
if err != nil || rel == "." {
return err
}
// Only top-level items for ISO packer.
if strings.Contains(rel, string(os.PathSeparator)) {
return nil
}
dst := "/" + filepath.ToSlash(rel)
entries = append(entries, dmgEntry{path, dst})
return nil
})
return writeDMG(dmgPath, entries, volume)
}
func writeHdiutilDMG(dmgPath, stageDir, volume string) error {
_ = os.Remove(dmgPath)
vol := sanitizeVol(volume)
cmd := exec.Command("hdiutil", "create",
"-volname", vol,
"-srcfolder", stageDir,
"-ov",
"-format", "UDZO",
dmgPath,
)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("hdiutil: %w: %s", err, strings.TrimSpace(string(out)))
}
// Re-sign after packaging is unnecessary for UDZO copy of already-signed .app,
// but clear quarantine on the dmg itself if present.
_ = exec.Command("xattr", "-cr", dmgPath).Run()
return nil
}
func writeAppBundle(appRoot, binPath, version, arch string) error {
macOSDir := filepath.Join(appRoot, "Contents", "MacOS")
if err := os.MkdirAll(macOSDir, 0o755); err != nil {
@@ -92,10 +136,12 @@ func writeAppBundle(appRoot, binPath, version, arch string) error {
<key>CFBundleExecutable</key><string>Navis</string>
<key>CFBundleIdentifier</key><string>win.evilfox.navis</string>
<key>CFBundleName</key><string>Navis</string>
<key>CFBundleDisplayName</key><string>Navis</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleShortVersionString</key><string>%s</string>
<key>CFBundleVersion</key><string>%s</string>
<key>LSMinimumSystemVersion</key><string>11.0</string>
<key>NSHighResolutionCapable</key><true/>
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>%s
</dict>
</plist>
@@ -103,6 +149,9 @@ func writeAppBundle(appRoot, binPath, version, arch string) error {
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "Info.plist"), []byte(plist), 0o644); err != nil {
return err
}
if err := os.WriteFile(filepath.Join(appRoot, "Contents", "PkgInfo"), []byte("APPL????"), 0o644); err != nil {
return err
}
dest := filepath.Join(macOSDir, "Navis")
if err := copyFile(binPath, dest, 0o755); err != nil {
return err
@@ -110,6 +159,25 @@ func writeAppBundle(appRoot, binPath, version, arch string) error {
return nil
}
func signAppBundle(appRoot string) error {
if _, err := exec.LookPath("codesign"); err != nil {
return nil
}
// Fresh ad-hoc signature; entitlements not required for local/dev builds.
cmd := exec.Command("codesign", "-s", "-", "--force", "--deep", "--options", "runtime", appRoot)
out, err := cmd.CombinedOutput()
if err != nil {
// --options runtime can fail without a real Developer ID; retry plain ad-hoc.
cmd = exec.Command("codesign", "-s", "-", "--force", "--deep", appRoot)
out, err = cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("codesign %s: %w: %s", appRoot, err, strings.TrimSpace(string(out)))
}
}
_ = exec.Command("xattr", "-cr", appRoot).Run()
return nil
}
type dmgEntry struct {
srcPath string
dstPath string
@@ -368,16 +436,17 @@ func sanitizeVol(s string) string {
func readmeText(version, arch string) string {
switch arch {
case "universal":
return fmt.Sprintf(`Navis %s for macOS (универсальная GUI-сборка)
return fmt.Sprintf(`Navis %s for macOS (универсальная сборка)
Подходит для Apple Silicon (M1/M2/M3/M4) и Intel Mac.
1) Перетащите Navis.app в Программы (Applications)
2) При блокировке:
2) При первом запуске, если macOS блокирует:
xattr -dr com.apple.quarantine /Applications/Navis.app
3) Запустите Navis — откроется окно как на Windows
(Chrome/Edge/Brave в режиме приложения, иначе браузер)
4) CLI (ядро/connect из терминала): рядом на git файл Navis-cli
3) В Терминале:
/Applications/Navis.app/Contents/MacOS/Navis init
/Applications/Navis.app/Contents/MacOS/Navis install-core
/Applications/Navis.app/Contents/MacOS/Navis connect
Магазин: https://evilfox.win/
`, version)
@@ -467,7 +536,9 @@ func architecturePriorityXML(arch string) string {
case "arm64":
return `
<key>LSArchitecturePriority</key>
<array><string>arm64</string></array>`
<array><string>arm64</string></array>
<key>LSRequiresNativeExecution</key>
<true/>`
case "amd64":
return `
<key>LSArchitecturePriority</key>