From 96faeadebb5247965b387caebd1d6c1ae8a56c9d Mon Sep 17 00:00:00 2001 From: LPFchan Date: Sat, 26 Sep 2026 17:27:46 +0900 Subject: [PATCH 1/3] feat: adopt PermissionFlow for camera permission handling timestamp: 2026-09-26 17-20-42 KST changes: - Add Swift package PermissionFlow (github.com/jaywcjlove/PermissionFlow, from 2.11.2) to Aware.xcodeproj with products PermissionFlow and PermissionFlowCameraStatus, and pin v2.11.2 in Package.resolved - MenuBarController registers the camera status provider, routes the notDetermined system prompt through PermissionFlow's CameraPermissionStatusProvider, and opens the System Settings camera pane via PermissionFlowController.authorize(pane: .camera) after the existing denial alert - AGENTS.md Local Divergence notes the new SwiftPM >= 6.2 (Xcode 26+) build requirement rationale: - Replace hand-rolled camera permission request/settings code paths with PermissionFlow, which reports status and opens the correct privacy pane; camera has no drag panel, so only pane opening and status/request APIs are used - Alert wording, menu UX, and localization stay unchanged; the system prompt is preserved via the provider's requestAuthorization checks: - Verification build of an identical tree against a local v2.11.2 mirror (only swift-tools-version lowered) succeeded; the real pin needs SwiftPM >= 6.2 (Xcode 26) to resolve, newer than this machine's Xcode 16.3 project: aware agent: kimi-code role: worker commit: LOG-20260926-172042-micode --- AGENTS.md | 1 + Aware.xcodeproj/project.pbxproj | 25 +++++++++++++++ .../xcshareddata/swiftpm/Package.resolved | 9 ++++++ Aware/MenuBarController.swift | 32 +++++++++++++------ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 495b22f..b71f1c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,6 +47,7 @@ Repo-agnostic skills (`sharpen-the-tip`, `prototype-mode`, `housekeeping`, `proa ## Local Divergence - Build verification: `xcodebuild -scheme Aware -configuration Debug -derivedDataPath build build` +- PermissionFlow (pinned from 2.11.2) declares `swift-tools-version: 6.2`, so resolving packages requires Xcode 26+ (SwiftPM >= 6.2). Xcode 16.x cannot resolve it, even with the swift.org 6.2 toolchain selected via `TOOLCHAINS`. - Commit provenance setup: `scripts/install-hooks.sh` configures the tracked `commit-msg` hook locally. - Commit provenance checks: `scripts/check-commit-standards.sh ` and `scripts/check-commit-range.sh ` - There is no dedicated automated test suite in the repo today. For runtime changes, use the build plus focused manual validation. diff --git a/Aware.xcodeproj/project.pbxproj b/Aware.xcodeproj/project.pbxproj index a51d1bb..6a2d12c 100644 --- a/Aware.xcodeproj/project.pbxproj +++ b/Aware.xcodeproj/project.pbxproj @@ -18,6 +18,8 @@ A1B2C3D40003 /* PresenceDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D10003 /* PresenceDetector.swift */; }; A1B2C3D40004 /* SleepAssertion.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D10004 /* SleepAssertion.swift */; }; E1F2A3B40000 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = E1F2A3B40002 /* Sparkle */; }; + F5A6B7C80004 /* PermissionFlow in Frameworks */ = {isa = PBXBuildFile; productRef = F5A6B7C80002 /* PermissionFlow */; }; + F5A6B7C80005 /* PermissionFlowCameraStatus in Frameworks */ = {isa = PBXBuildFile; productRef = F5A6B7C80003 /* PermissionFlowCameraStatus */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -41,6 +43,8 @@ buildActionMask = 2147483647; files = ( E1F2A3B40000 /* Sparkle in Frameworks */, + F5A6B7C80004 /* PermissionFlow in Frameworks */, + F5A6B7C80005 /* PermissionFlowCameraStatus in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -123,6 +127,8 @@ name = Aware; packageProductDependencies = ( E1F2A3B40002 /* Sparkle */, + F5A6B7C80002 /* PermissionFlow */, + F5A6B7C80003 /* PermissionFlowCameraStatus */, ); productName = Aware; productReference = A1B2C3D00001 /* Aware.app */; @@ -157,6 +163,7 @@ mainGroup = A1B2C3D30001; packageReferences = ( E1F2A3B40001 /* XCRemoteSwiftPackageReference "Sparkle" */, + F5A6B7C80001 /* XCRemoteSwiftPackageReference "PermissionFlow" */, ); productRefGroup = A1B2C3D30003 /* Products */; projectDirPath = ""; @@ -350,6 +357,14 @@ minimumVersion = 2.7.0; }; }; + F5A6B7C80001 /* XCRemoteSwiftPackageReference "PermissionFlow" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/jaywcjlove/PermissionFlow"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.11.2; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -358,6 +373,16 @@ package = E1F2A3B40001 /* XCRemoteSwiftPackageReference "Sparkle" */; productName = Sparkle; }; + F5A6B7C80002 /* PermissionFlow */ = { + isa = XCSwiftPackageProductDependency; + package = F5A6B7C80001 /* XCRemoteSwiftPackageReference "PermissionFlow" */; + productName = PermissionFlow; + }; + F5A6B7C80003 /* PermissionFlowCameraStatus */ = { + isa = XCSwiftPackageProductDependency; + package = F5A6B7C80001 /* XCRemoteSwiftPackageReference "PermissionFlow" */; + productName = PermissionFlowCameraStatus; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = A1B2C3D20006 /* Project object */; diff --git a/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6e450d9..066a6c8 100644 --- a/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,15 @@ { "originHash" : "e721da7f9826abdffcb6185e886155efa2514bd6234475f1afa893e29eb258d6", "pins" : [ + { + "identity" : "permissionflow", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jaywcjlove/PermissionFlow", + "state" : { + "revision" : "2f2a4b76b1eb2ff7ab815b977be8229853f10bf8", + "version" : "2.11.2" + } + }, { "identity" : "sparkle", "kind" : "remoteSourceControl", diff --git a/Aware/MenuBarController.swift b/Aware/MenuBarController.swift index 0d1d8be..7b9b294 100644 --- a/Aware/MenuBarController.swift +++ b/Aware/MenuBarController.swift @@ -9,6 +9,8 @@ import AppKit import AVFoundation import CoreGraphics +import PermissionFlow +import PermissionFlowCameraStatus import ServiceManagement private enum MenuItemTag: Int { @@ -63,6 +65,9 @@ final class MenuBarController: NSObject { private let sleepAssertion = SleepAssertion() private let checkForUpdatesTarget: AnyObject? private let checkForUpdatesAction: Selector? + /// Opens the System Settings camera pane when access has been denied. + /// Created lazily on the main actor, where menu actions and alerts run. + private var permissionController: PermissionFlowController? private var pollingTimer: DispatchSourceTimer? private let timerQueue = DispatchQueue(label: "com.aware.timer", qos: .userInitiated) @@ -93,6 +98,9 @@ final class MenuBarController: NSObject { self.checkForUpdatesTarget = checkForUpdatesTarget self.checkForUpdatesAction = checkForUpdatesAction super.init() + MainActor.assumeIsolated { + PermissionFlowCameraStatus.register() + } #if DEBUG debugLog("MenuBarController init started") #endif @@ -349,6 +357,14 @@ final class MenuBarController: NSObject { alert.alertStyle = .warning alert.addButton(withTitle: String(localized: "alert.ok")) alert.runModal() + // Camera uses the system toggle list (no drag panel), so this just + // opens System Settings > Privacy & Security > Camera. + MainActor.assumeIsolated { + if permissionController == nil { + permissionController = PermissionFlow.makeController() + } + permissionController?.authorize(pane: .camera) + } } @objc private func handleDisplaySleep() { @@ -369,20 +385,18 @@ final class MenuBarController: NSObject { if isEnabled { isEnabled = false } else { - let status = AVCaptureDevice.authorizationStatus(for: .video) - switch status { - case .authorized: + let cameraPermission = CameraPermissionStatusProvider() + if cameraPermission.authorizationState() == .granted { isEnabled = true - case .notDetermined: - AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in + } else if AVCaptureDevice.authorizationStatus(for: .video) == .notDetermined { + // System prompt via PermissionFlow's camera status provider. + cameraPermission.requestAuthorization { [weak self] state in DispatchQueue.main.async { - self?.isEnabled = granted + self?.isEnabled = (state == .granted) } } - case .denied, .restricted: + } else { showCameraDeniedAlert() - @unknown default: - break } } } From ba4e081b16b884502b0e2ffdf2cbf768683bd8d8 Mon Sep 17 00:00:00 2001 From: LPFchan Date: Sat, 26 Sep 2026 17:40:17 +0900 Subject: [PATCH 2/3] Use the Swift 6.1 PermissionFlow fork timestamp: 2026-09-26 17-40-16 KST changes: - PermissionFlow now comes from LPFchan/PermissionFlow at exact version 2.11.2-swift6.1 (upstream v2.11.2 with swift-tools-version 6.1); Package.resolved re-resolved - AGENTS.md Local Divergence note updated to match rationale: - every upstream PermissionFlow tag declares swift-tools-version 6.2, which needs Xcode 26; this machine and the repo's tooling are on Xcode 16.3 checks: - xcodebuild resolved the fork tag and built the Aware scheme (Debug) on Xcode 16.3 project: aware agent: claude-code role: worker commit: LOG-20260926-174016-decode --- AGENTS.md | 2 +- Aware.xcodeproj/project.pbxproj | 6 +++--- .../xcshareddata/swiftpm/Package.resolved | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b71f1c9..76d9c19 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,7 +47,7 @@ Repo-agnostic skills (`sharpen-the-tip`, `prototype-mode`, `housekeeping`, `proa ## Local Divergence - Build verification: `xcodebuild -scheme Aware -configuration Debug -derivedDataPath build build` -- PermissionFlow (pinned from 2.11.2) declares `swift-tools-version: 6.2`, so resolving packages requires Xcode 26+ (SwiftPM >= 6.2). Xcode 16.x cannot resolve it, even with the swift.org 6.2 toolchain selected via `TOOLCHAINS`. +- PermissionFlow comes from the LPFchan/PermissionFlow fork, pinned to `2.11.2-swift6.1`: upstream v2.11.2 with `swift-tools-version` lowered to 6.1 so Xcode 16.3+ can build it. Move to a new fork tag when upstream updates. - Commit provenance setup: `scripts/install-hooks.sh` configures the tracked `commit-msg` hook locally. - Commit provenance checks: `scripts/check-commit-standards.sh ` and `scripts/check-commit-range.sh ` - There is no dedicated automated test suite in the repo today. For runtime changes, use the build plus focused manual validation. diff --git a/Aware.xcodeproj/project.pbxproj b/Aware.xcodeproj/project.pbxproj index 6a2d12c..0ef6521 100644 --- a/Aware.xcodeproj/project.pbxproj +++ b/Aware.xcodeproj/project.pbxproj @@ -359,10 +359,10 @@ }; F5A6B7C80001 /* XCRemoteSwiftPackageReference "PermissionFlow" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/jaywcjlove/PermissionFlow"; + repositoryURL = "https://github.com/LPFchan/PermissionFlow"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.11.2; + kind = exactVersion; + version = "2.11.2-swift6.1"; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 066a6c8..5e0c3b4 100644 --- a/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Aware.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "e721da7f9826abdffcb6185e886155efa2514bd6234475f1afa893e29eb258d6", + "originHash" : "af57ec271e51d6743d8d5de17d0378c5c593331081bd3c110c5ca46764ecc95b", "pins" : [ { "identity" : "permissionflow", "kind" : "remoteSourceControl", - "location" : "https://github.com/jaywcjlove/PermissionFlow", + "location" : "https://github.com/LPFchan/PermissionFlow", "state" : { - "revision" : "2f2a4b76b1eb2ff7ab815b977be8229853f10bf8", - "version" : "2.11.2" + "revision" : "4ceff2a83937f4c039fc4cf1b31eb18587c38459", + "version" : "2.11.2-swift6.1" } }, { @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/sparkle-project/Sparkle", "state" : { - "revision" : "21d8df80440b1ca3b65fa82e40782f1e5a9e6ba2", - "version" : "2.9.0" + "revision" : "eef1a539a373c1f1a320624b1130fc5de7b2e100", + "version" : "2.10.0" } } ], From dcc859bab423585e8fcd2026eb3e79ba6b59492b Mon Sep 17 00:00:00 2001 From: LPFchan Date: Sat, 26 Sep 2026 17:49:00 +0900 Subject: [PATCH 3/3] Build on macos-15 with Xcode 16 for the PermissionFlow fork timestamp: 2026-09-26 17-48-59 KST changes: - build, release and publish-appcast macOS jobs run on macos-15 and select Xcode 16 (latest 16.x, Swift 6.1+) via setup-xcode rationale: - Codex review on #1: the PermissionFlow fork declares swift-tools-version 6.1, which macos-14's Xcode can't resolve; the PR's Build run failed on it checks: - the PR's Build workflow reruns on this push project: aware agent: claude-code role: worker commit: LOG-20260926-174859-decode --- .github/workflows/build.yml | 7 ++++++- .github/workflows/publish-appcast.yml | 7 ++++++- .github/workflows/release.yml | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d708e7e..3bb54b5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,10 +8,15 @@ on: jobs: build: - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 + - name: Select Xcode 16 (Swift 6.1 for PermissionFlow) + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '16' + - name: Build Aware run: | xcodebuild -scheme Aware -configuration Debug -derivedDataPath build \ diff --git a/.github/workflows/publish-appcast.yml b/.github/workflows/publish-appcast.yml index ef7a190..44de1f1 100644 --- a/.github/workflows/publish-appcast.yml +++ b/.github/workflows/publish-appcast.yml @@ -15,10 +15,15 @@ permissions: jobs: build-appcast: - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 + - name: Select Xcode 16 (Swift 6.1 for PermissionFlow) + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '16' + - name: Resolve Sparkle tools run: | xcodebuild -resolvePackageDependencies -project Aware.xcodeproj -scheme Aware -derivedDataPath build -quiet diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de0733b..083120c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,13 +15,13 @@ env: jobs: build: - runs-on: macos-14 + runs-on: macos-15 outputs: sparkle_enabled: ${{ steps.sparkle_settings.outputs.enabled }} steps: - uses: actions/checkout@v4 - - name: Select Xcode 16 (Swift 6 for DMGMaker) + - name: Select Xcode 16 (Swift 6 for DMGMaker, 6.1 for PermissionFlow) uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: '16'