From 5b799a3dd284d268d25069a3b474f83611bb3a64 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 11 Jun 2026 11:39:03 +0800
Subject: [PATCH] Spike macOS 14 compatibility target

---
 src/build.sh                                     |    7 ++
 src/Scripts/quick_search_system_app_qa.sh        |    4 +
 src/Apptag/Info.plist                            |    2 
 src/Scripts/quick_search_app_name_qa.sh          |    4 +
 src/Scripts/macos14_availability_typecheck_qa.sh |   56 ++++++++++++++++++
 src/Scripts/macos14_build_metadata_qa.sh         |   62 ++++++++++++++++++++
 6 files changed, 131 insertions(+), 4 deletions(-)

diff --git a/src/Apptag/Info.plist b/src/Apptag/Info.plist
index dbe7ddb..ce09179 100644
--- a/src/Apptag/Info.plist
+++ b/src/Apptag/Info.plist
@@ -25,7 +25,7 @@
 	<key>LSApplicationCategoryType</key>
 	<string>public.app-category.utilities</string>
 	<key>LSMinimumSystemVersion</key>
-	<string>15.0</string>
+	<string>14.0</string>
 	<key>LSMultipleInstancesProhibited</key>
 	<true/>
 	<key>LSUIElement</key>
diff --git a/src/Scripts/macos14_availability_typecheck_qa.sh b/src/Scripts/macos14_availability_typecheck_qa.sh
new file mode 100755
index 0000000..a756e9c
--- /dev/null
+++ b/src/Scripts/macos14_availability_typecheck_qa.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+SWIFT_DIR="$ROOT_DIR/Apptag"
+MACOS_DEPLOYMENT_TARGET="${MACOS_DEPLOYMENT_TARGET:-14.0}"
+TARGET_ARCHES_RAW="${TARGET_ARCHES:-arm64}"
+
+if [[ ! "$MACOS_DEPLOYMENT_TARGET" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
+  echo "FAIL: invalid MACOS_DEPLOYMENT_TARGET: $MACOS_DEPLOYMENT_TARGET" >&2
+  exit 1
+fi
+
+SDK_PATH="$(xcrun --sdk macosx --show-sdk-path)"
+MODULE_CACHE_DIR="${MODULE_CACHE_DIR:-${TMPDIR:-/tmp}/taglauncher-macos14-typecheck-cache}"
+mkdir -p "$MODULE_CACHE_DIR"
+
+SWIFT_FILES=()
+while IFS= read -r file; do
+  SWIFT_FILES+=("$file")
+done < <(find "$SWIFT_DIR" -name '*.swift' -print | sort)
+
+if [[ "${#SWIFT_FILES[@]}" -eq 0 ]]; then
+  echo "FAIL: no Swift files found under $SWIFT_DIR" >&2
+  exit 1
+fi
+
+TARGET_ARCHES=()
+while IFS= read -r arch; do
+  [[ -n "$arch" ]] && TARGET_ARCHES+=("$arch")
+done < <(tr ',' '\n' <<<"$TARGET_ARCHES_RAW" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+
+for arch in "${TARGET_ARCHES[@]}"; do
+  case "$arch" in
+    arm64|x86_64) ;;
+    *)
+      echo "FAIL: unsupported target arch: $arch" >&2
+      exit 1
+      ;;
+  esac
+
+  target="${arch}-apple-macosx${MACOS_DEPLOYMENT_TARGET}"
+  echo "==> Typechecking for $target"
+  swiftc -typecheck \
+    -framework AppKit \
+    -framework SwiftUI \
+    -framework Carbon \
+    -framework CoreServices \
+    -lcompression \
+    -sdk "$SDK_PATH" \
+    -target "$target" \
+    -module-cache-path "$MODULE_CACHE_DIR" \
+    "${SWIFT_FILES[@]}"
+done
+
+echo "PASS macOS $MACOS_DEPLOYMENT_TARGET availability typecheck: ${TARGET_ARCHES[*]}"
diff --git a/src/Scripts/macos14_build_metadata_qa.sh b/src/Scripts/macos14_build_metadata_qa.sh
new file mode 100755
index 0000000..77b5af7
--- /dev/null
+++ b/src/Scripts/macos14_build_metadata_qa.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+APP_BUNDLE="${1:-$ROOT_DIR/build/TagLauncher.app}"
+EXPECTED_MINIMUM_SYSTEM="${MACOS_DEPLOYMENT_TARGET:-14.0}"
+EXPECTED_ARCHES_RAW="${EXPECTED_ARCHES:-arm64}"
+INFO_PLIST="$APP_BUNDLE/Contents/Info.plist"
+EXECUTABLE="$APP_BUNDLE/Contents/MacOS/TagLauncher"
+
+fail() {
+  echo "FAIL: $*" >&2
+  exit 1
+}
+
+[[ -d "$APP_BUNDLE" ]] || fail "app bundle not found: $APP_BUNDLE"
+[[ -f "$INFO_PLIST" ]] || fail "Info.plist not found: $INFO_PLIST"
+[[ -x "$EXECUTABLE" ]] || fail "executable not found or not executable: $EXECUTABLE"
+
+actual_minimum_system="$(/usr/libexec/PlistBuddy -c 'Print :LSMinimumSystemVersion' "$INFO_PLIST")"
+if [[ "$actual_minimum_system" != "$EXPECTED_MINIMUM_SYSTEM" ]]; then
+  fail "LSMinimumSystemVersion expected $EXPECTED_MINIMUM_SYSTEM, got $actual_minimum_system"
+fi
+
+EXPECTED_ARCHES=()
+while IFS= read -r arch; do
+  [[ -n "$arch" ]] && EXPECTED_ARCHES+=("$arch")
+done < <(tr ',' '\n' <<<"$EXPECTED_ARCHES_RAW" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+
+[[ "${#EXPECTED_ARCHES[@]}" -gt 0 ]] || fail "no EXPECTED_ARCHES configured"
+
+actual_arches="$(lipo -archs "$EXECUTABLE")"
+for expected_arch in "${EXPECTED_ARCHES[@]}"; do
+  case "$expected_arch" in
+    arm64|x86_64) ;;
+    *) fail "unsupported expected arch: $expected_arch" ;;
+  esac
+  if ! grep -Eq "(^|[[:space:]])${expected_arch}($|[[:space:]])" <<<"$actual_arches"; then
+    fail "missing architecture $expected_arch; actual arches: $actual_arches"
+  fi
+done
+
+for actual_arch in $actual_arches; do
+  matched=false
+  for expected_arch in "${EXPECTED_ARCHES[@]}"; do
+    if [[ "$actual_arch" == "$expected_arch" ]]; then
+      matched=true
+      break
+    fi
+  done
+  [[ "$matched" == true ]] || fail "unexpected architecture $actual_arch; expected: ${EXPECTED_ARCHES[*]}"
+done
+
+for arch in "${EXPECTED_ARCHES[@]}"; do
+  build_info="$(vtool -arch "$arch" -show-build "$EXECUTABLE")"
+  minos="$(awk '/minos/{print $2; exit}' <<<"$build_info")"
+  [[ "$minos" == "$EXPECTED_MINIMUM_SYSTEM" ]] || fail "$arch LC_BUILD_VERSION minos expected $EXPECTED_MINIMUM_SYSTEM, got $minos"
+done
+
+codesign --verify --deep --strict "$APP_BUNDLE"
+
+echo "PASS build metadata: LSMinimumSystemVersion=$actual_minimum_system minos=$EXPECTED_MINIMUM_SYSTEM arches=$actual_arches"
diff --git a/src/Scripts/quick_search_app_name_qa.sh b/src/Scripts/quick_search_app_name_qa.sh
index f3da8c8..cd601c6 100755
--- a/src/Scripts/quick_search_app_name_qa.sh
+++ b/src/Scripts/quick_search_app_name_qa.sh
@@ -5,6 +5,8 @@
 DATA_LAYER="$ROOT_DIR/Apptag/DataLayer.swift"
 QUICK_SEARCH="$ROOT_DIR/Apptag/QuickSearch.swift"
 SUNLOGIN_APP="${1:-/Applications/贝锐向日葵被控.app}"
+MODULE_CACHE_DIR="${MODULE_CACHE_DIR:-${TMPDIR:-/tmp}/taglauncher-quick-search-qa-cache}"
+mkdir -p "$MODULE_CACHE_DIR"
 
 rg -Fq 'AppDisplayNameResolver.displayName' "$DATA_LAYER"
 rg -Fq 'systemDisplayNames' "$DATA_LAYER"
@@ -16,7 +18,7 @@
 rg -Fq 'AppDisplayNameResolver.searchAliases' "$QUICK_SEARCH"
 rg -Fq 'AppIndexer.isInternalHelperAppPath($0.path)' "$QUICK_SEARCH"
 
-swift - "$SUNLOGIN_APP" <<'SWIFT'
+swift -module-cache-path "$MODULE_CACHE_DIR" - "$SUNLOGIN_APP" <<'SWIFT'
 import Foundation
 import CoreServices
 
diff --git a/src/Scripts/quick_search_system_app_qa.sh b/src/Scripts/quick_search_system_app_qa.sh
index 08e75a1..315d309 100755
--- a/src/Scripts/quick_search_system_app_qa.sh
+++ b/src/Scripts/quick_search_system_app_qa.sh
@@ -4,11 +4,13 @@
 ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
 DATA_LAYER="$ROOT_DIR/Apptag/DataLayer.swift"
 KEYCHAIN_APP="/System/Library/CoreServices/Applications/Keychain Access.app"
+MODULE_CACHE_DIR="${MODULE_CACHE_DIR:-${TMPDIR:-/tmp}/taglauncher-quick-search-qa-cache}"
+mkdir -p "$MODULE_CACHE_DIR"
 
 rg -Fq 'URL(fileURLWithPath: "/System/Library/CoreServices/Applications")' "$DATA_LAYER"
 rg -Fq '"/System/Library/CoreServices/Applications/"' "$DATA_LAYER"
 
-swift - "$KEYCHAIN_APP" <<'SWIFT'
+swift -module-cache-path "$MODULE_CACHE_DIR" - "$KEYCHAIN_APP" <<'SWIFT'
 import Foundation
 import CoreServices
 
diff --git a/src/build.sh b/src/build.sh
index 1ab51d8..60dcda1 100644
--- a/src/build.sh
+++ b/src/build.sh
@@ -10,9 +10,12 @@
 RESOURCES_DIR="$APP_BUNDLE/Contents/Resources"
 SWIFT_DIR="$PROJECT_DIR/Apptag"
 INFO_PLIST="$SWIFT_DIR/Info.plist"
+MODULE_CACHE_DIR="${MODULE_CACHE_DIR:-$BUILD_DIR/ModuleCache}"
 
 SDK_PATH=$(xcrun --sdk macosx --show-sdk-path)
-TARGET="arm64-apple-macosx15.0"
+MACOS_DEPLOYMENT_TARGET="${MACOS_DEPLOYMENT_TARGET:-14.0}"
+TARGET_ARCH="${TARGET_ARCH:-arm64}"
+TARGET="${TARGET_ARCH}-apple-macosx${MACOS_DEPLOYMENT_TARGET}"
 
 APP_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST")
 APP_BUILD="${APP_BUILD:-$(date '+%Y%m%d.%H%M')}"
@@ -48,6 +51,7 @@
 echo "==> Creating bundle structure..."
 mkdir -p "$MACOS_DIR"
 mkdir -p "$RESOURCES_DIR"
+mkdir -p "$MODULE_CACHE_DIR"
 
 echo "==> Compiling Swift files..."
 SWIFT_FILES=()
@@ -63,6 +67,7 @@
     -lcompression \
     -sdk "$SDK_PATH" \
     -target "$TARGET" \
+    -module-cache-path "$MODULE_CACHE_DIR" \
     -Osize \
     "${SWIFT_FILES[@]}"
 

--
Gitblit v1.9.3