diff --git a/Makefile b/Makefile index a8103b38..b2aef475 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,10 @@ VERSION ?= BUILD ?= XCODEBUILD_FLAGS ?= FORMAT_BASE_REF ?= origin/main +DEBUG_PRODUCT_NAME ?= Prowl Debug +DEBUG_BUNDLE_IDENTIFIER ?= com.onevcat.prowl.debug +DEBUG_SIGNING_IDENTITY ?= +DEBUG_APP_NAME := $(DEBUG_PRODUCT_NAME).app # Release-only analytics/crash credentials. Included from Config/Secrets.env if present, # or overridable from the environment (e.g. CI). Debug builds skip SDK init regardless. @@ -165,8 +169,22 @@ run-app: build-app # Build then launch (Debug) with log streaming app_path="$$build_dir/$$product/Contents/MacOS/$$exec_name"; \ "$$app_path" -install-dev-build: build-app # install dev build to /Applications +install-dev-build: build-app # Build Debug and install to /Applications/Prowl Debug.app @set -euo pipefail; \ + signing_identity="$(DEBUG_SIGNING_IDENTITY)"; \ + if [ -z "$$signing_identity" ]; then \ + signing_identity="$$(security find-identity -v -p codesigning 2>/dev/null | awk -F'"' ' \ + /Apple Development/ { print $$2; found=1; exit } \ + /Developer ID Application/ && fallback == "" { fallback=$$2 } \ + END { if (!found && fallback != "") print fallback } \ + ')"; \ + fi; \ + if [ -z "$$signing_identity" ]; then \ + echo "error: no Apple Development or Developer ID Application signing identity found"; \ + echo "Install a development signing certificate, or pass DEBUG_SIGNING_IDENTITY explicitly."; \ + exit 1; \ + fi; \ + echo "debug install signing identity: $$signing_identity"; \ settings="$$(xcodebuild -project supacode.xcodeproj -scheme supacode -configuration Debug -showBuildSettings -json 2>/dev/null)"; \ build_dir="$$(echo "$$settings" | jq -er '.[0].buildSettings.BUILT_PRODUCTS_DIR')"; \ product="$$(echo "$$settings" | jq -er '.[0].buildSettings.FULL_PRODUCT_NAME')"; \ @@ -183,7 +201,7 @@ install-dev-build: build-app # install dev build to /Applications exit 1; \ fi; \ src="$$build_dir/$$product"; \ - dst="/Applications/$$product"; \ + dst="/Applications/$(DEBUG_APP_NAME)"; \ dst_parent="$$(cd "$$(dirname "$$dst")" && pwd -P)"; \ if [ "$$dst_parent" != "/Applications" ]; then \ echo "error: refusing to install outside /Applications: $$dst"; \ @@ -218,7 +236,13 @@ install-dev-build: build-app # install dev build to /Applications trash "$$dst"; \ fi; \ ditto "$$src" "$$dst"; \ - echo "installed $$dst" + /usr/libexec/PlistBuddy -c 'Set :CFBundleName $(DEBUG_PRODUCT_NAME)' "$$dst/Contents/Info.plist"; \ + /usr/libexec/PlistBuddy -c 'Set :CFBundleDisplayName $(DEBUG_PRODUCT_NAME)' "$$dst/Contents/Info.plist" 2>/dev/null \ + || /usr/libexec/PlistBuddy -c 'Add :CFBundleDisplayName string $(DEBUG_PRODUCT_NAME)' "$$dst/Contents/Info.plist"; \ + /usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier $(DEBUG_BUNDLE_IDENTIFIER)' "$$dst/Contents/Info.plist"; \ + codesign -f --deep -s "$$signing_identity" --timestamp=none "$$dst"; \ + echo "installed $$dst"; \ + codesign -dv --verbose=4 "$$dst" 2>&1 | sed -n -E '/Identifier=|Authority=|TeamIdentifier=|Signature=|Info.plist=/p' install-release: build-ghostty-xcframework # Build Release, sign locally, install to /Applications @set -euo pipefail; \ -- 2.51.2 From a8796130ee0eb9016de30caff26176a9120fa16b Mon Sep 17 00:00:00 2001 From: onevcat Date: Fri, 19 Jun 2026 21:32:43 +0900 Subject: [PATCH 2/3] Separate Debug and Release app identity at the Xcode project level Move Debug bundle identifier and product name into the Xcode project (Debug configuration only) so builds natively produce "Prowl Debug" with com.onevcat.prowl.debug. This eliminates the need for post-build PlistBuddy patching and codesign re-signing, preserving entitlements and hardened runtime flags that the Makefile workaround would strip. Also update TEST_HOST for the Debug test configuration and simplify install-dev-build back to a plain copy. Co-authored-by: MikotoZero --- Makefile | 30 +++--------------------------- supacode.xcodeproj/project.pbxproj | 8 +++++--- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index b2aef475..627931d8 100644 --- a/Makefile +++ b/Makefile @@ -28,10 +28,6 @@ VERSION ?= BUILD ?= XCODEBUILD_FLAGS ?= FORMAT_BASE_REF ?= origin/main -DEBUG_PRODUCT_NAME ?= Prowl Debug -DEBUG_BUNDLE_IDENTIFIER ?= com.onevcat.prowl.debug -DEBUG_SIGNING_IDENTITY ?= -DEBUG_APP_NAME := $(DEBUG_PRODUCT_NAME).app # Release-only analytics/crash credentials. Included from Config/Secrets.env if present, # or overridable from the environment (e.g. CI). Debug builds skip SDK init regardless. @@ -169,22 +165,8 @@ run-app: build-app # Build then launch (Debug) with log streaming app_path="$$build_dir/$$product/Contents/MacOS/$$exec_name"; \ "$$app_path" -install-dev-build: build-app # Build Debug and install to /Applications/Prowl Debug.app +install-dev-build: build-app # Build Debug and install to /Applications @set -euo pipefail; \ - signing_identity="$(DEBUG_SIGNING_IDENTITY)"; \ - if [ -z "$$signing_identity" ]; then \ - signing_identity="$$(security find-identity -v -p codesigning 2>/dev/null | awk -F'"' ' \ - /Apple Development/ { print $$2; found=1; exit } \ - /Developer ID Application/ && fallback == "" { fallback=$$2 } \ - END { if (!found && fallback != "") print fallback } \ - ')"; \ - fi; \ - if [ -z "$$signing_identity" ]; then \ - echo "error: no Apple Development or Developer ID Application signing identity found"; \ - echo "Install a development signing certificate, or pass DEBUG_SIGNING_IDENTITY explicitly."; \ - exit 1; \ - fi; \ - echo "debug install signing identity: $$signing_identity"; \ settings="$$(xcodebuild -project supacode.xcodeproj -scheme supacode -configuration Debug -showBuildSettings -json 2>/dev/null)"; \ build_dir="$$(echo "$$settings" | jq -er '.[0].buildSettings.BUILT_PRODUCTS_DIR')"; \ product="$$(echo "$$settings" | jq -er '.[0].buildSettings.FULL_PRODUCT_NAME')"; \ @@ -201,7 +183,7 @@ install-dev-build: build-app # Build Debug and install to /Applications/Prowl De exit 1; \ fi; \ src="$$build_dir/$$product"; \ - dst="/Applications/$(DEBUG_APP_NAME)"; \ + dst="/Applications/$$product"; \ dst_parent="$$(cd "$$(dirname "$$dst")" && pwd -P)"; \ if [ "$$dst_parent" != "/Applications" ]; then \ echo "error: refusing to install outside /Applications: $$dst"; \ @@ -236,13 +218,7 @@ install-dev-build: build-app # Build Debug and install to /Applications/Prowl De trash "$$dst"; \ fi; \ ditto "$$src" "$$dst"; \ - /usr/libexec/PlistBuddy -c 'Set :CFBundleName $(DEBUG_PRODUCT_NAME)' "$$dst/Contents/Info.plist"; \ - /usr/libexec/PlistBuddy -c 'Set :CFBundleDisplayName $(DEBUG_PRODUCT_NAME)' "$$dst/Contents/Info.plist" 2>/dev/null \ - || /usr/libexec/PlistBuddy -c 'Add :CFBundleDisplayName string $(DEBUG_PRODUCT_NAME)' "$$dst/Contents/Info.plist"; \ - /usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier $(DEBUG_BUNDLE_IDENTIFIER)' "$$dst/Contents/Info.plist"; \ - codesign -f --deep -s "$$signing_identity" --timestamp=none "$$dst"; \ - echo "installed $$dst"; \ - codesign -dv --verbose=4 "$$dst" 2>&1 | sed -n -E '/Identifier=|Authority=|TeamIdentifier=|Signature=|Info.plist=/p' + echo "installed $$dst" install-release: build-ghostty-xcframework # Build Release, sign locally, install to /Applications @set -euo pipefail; \ diff --git a/supacode.xcodeproj/project.pbxproj b/supacode.xcodeproj/project.pbxproj index d6d60894..5d826d16 100644 --- a/supacode.xcodeproj/project.pbxproj +++ b/supacode.xcodeproj/project.pbxproj @@ -475,6 +475,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; ENABLE_APP_SANDBOX = NO; + ENABLE_DEBUG_DYLIB = NO; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = YES; @@ -487,6 +488,7 @@ EXECUTABLE_NAME = ProwlApp; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = supacode/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Prowl Debug"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -499,9 +501,9 @@ "-lc++", ); OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -Wno-incomplete-umbrella"; - PRODUCT_BUNDLE_IDENTIFIER = com.onevcat.prowl; + PRODUCT_BUNDLE_IDENTIFIER = com.onevcat.prowl.debug; PRODUCT_MODULE_NAME = supacode; - PRODUCT_NAME = Prowl; + PRODUCT_NAME = "Prowl Debug"; REGISTER_APP_GROUPS = YES; RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO; RUNTIME_EXCEPTION_ALLOW_JIT = NO; @@ -594,7 +596,7 @@ SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 6.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Prowl.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ProwlApp"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Prowl Debug.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ProwlApp"; }; name = Debug; }; -- 2.51.2 From 7f8e38e617d4b78ceaa873171058f7029f68fb4a Mon Sep 17 00:00:00 2001 From: onevcat Date: Fri, 19 Jun 2026 21:54:30 +0900 Subject: [PATCH 3/3] Recognize Debug app bundle in CLI launcher --- ProwlCLI/AppLauncher.swift | 12 +++++++++++- ProwlCLITests/AppLauncherTests.swift | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 ProwlCLITests/AppLauncherTests.swift diff --git a/ProwlCLI/AppLauncher.swift b/ProwlCLI/AppLauncher.swift index b47ef705..b969cbf5 100644 --- a/ProwlCLI/AppLauncher.swift +++ b/ProwlCLI/AppLauncher.swift @@ -13,6 +13,11 @@ import ProwlCLIShared #endif enum AppLauncher { + private static let prowlAppBundleIdentifiers: Set = [ + "com.onevcat.prowl", + "com.onevcat.prowl.debug", + ] + /// Maximum time to wait for the socket after launching the app. private static let socketTimeoutSeconds: TimeInterval = 15 /// Interval between socket availability checks. @@ -59,10 +64,15 @@ enum AppLauncher { /// Check whether a Prowl app instance is currently running. private static func isAppProcessRunning() -> Bool { NSWorkspace.shared.runningApplications.contains { application in - application.bundleIdentifier == "com.onevcat.prowl" + isProwlAppBundleIdentifier(application.bundleIdentifier) } } + static func isProwlAppBundleIdentifier(_ bundleIdentifier: String?) -> Bool { + guard let bundleIdentifier else { return false } + return prowlAppBundleIdentifiers.contains(bundleIdentifier) + } + // MARK: - App launch private static func launchApp() throws { diff --git a/ProwlCLITests/AppLauncherTests.swift b/ProwlCLITests/AppLauncherTests.swift new file mode 100644 index 00000000..79d3d29c --- /dev/null +++ b/ProwlCLITests/AppLauncherTests.swift @@ -0,0 +1,11 @@ +@testable import prowl +import XCTest + +final class AppLauncherTests: XCTestCase { + func testProwlBundleIdentifierMatchingIncludesDebugBuild() { + XCTAssertTrue(AppLauncher.isProwlAppBundleIdentifier("com.onevcat.prowl")) + XCTAssertTrue(AppLauncher.isProwlAppBundleIdentifier("com.onevcat.prowl.debug")) + XCTAssertFalse(AppLauncher.isProwlAppBundleIdentifier("com.example.Prowl")) + XCTAssertFalse(AppLauncher.isProwlAppBundleIdentifier(nil)) + } +}