Ariver
2026-05-31 6f3ed4f3b8eb45734ca77916b4c96fab937cb2e2
Prepare 7.8.7 dock policy release
6 files modified
4 files added
240 ■■■■■ changed files
Apptag/ApptagApp.swift 56 ●●●● patch | view | raw | blame | history
Apptag/Info.plist 4 ●●●● patch | view | raw | blame | history
Apptag/OverlayWindowController.swift 8 ●●●●● patch | view | raw | blame | history
Apptag/ProcessSingleton.swift 3 ●●●●● patch | view | raw | blame | history
CHANGELOG.md 8 ●●●●● patch | view | raw | blame | history
Release/AppStore-7.8.7-20260531.0252/APP_STORE_ASSET_INVENTORY.md 17 ●●●●● patch | view | raw | blame | history
Release/AppStore-7.8.7-20260531.0252/Archive/TagLauncher-7.8.7-20260531.0252-local-QA.dmg patch | view | raw | blame | history
Release/AppStore-7.8.7-20260531.0252/QA_RELEASE_EVIDENCE.md 39 ●●●●● patch | view | raw | blame | history
Release/AppStore-7.8.7-20260531.0252/README.md 32 ●●●●● patch | view | raw | blame | history
Scripts/window_logic_qa.sh 73 ●●●●● patch | view | raw | blame | history
Apptag/ApptagApp.swift
@@ -38,6 +38,7 @@
    private static let downloadHelpMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherDownloadHelpMenuItem")
    private static let externalActivationNotification = Notification.Name("TagLauncherExternalActivationRequested")
    private static let externalActivationObject = AppIdentity.bundleIdentifier
    private static let duplicateLaunchSuppressReopenKey = "duplicateLaunchSuppressReopenAt"
    private static let launcherOverlayLevel = NSWindow.Level(rawValue: NSWindow.Level.mainMenu.rawValue - 1)
    private static let overlayDefaultLevel = launcherOverlayLevel
    private static let overlayTextInputLevel = launcherOverlayLevel
@@ -208,11 +209,39 @@
        configureApplicationMenuWhenAvailable(retries: 12)
    }
    /// Reopening the already-running app must not implicitly show App Grid.
    /// App Grid is only opened by explicit launcher commands: main hotkey or status item/menu.
    /// Dock icon reopen is an explicit App Grid entry only when the user chooses to show the Dock icon.
    /// Duplicate-instance handoff suppresses this path so repeated launches do not show App Grid.
    func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
        guard Date() >= suppressReopenUntil else { return false }
        let lastDuplicateLaunch = UserDefaults.standard.double(forKey: Self.duplicateLaunchSuppressReopenKey)
        if lastDuplicateLaunch > 0,
           Date().timeIntervalSince1970 - lastDuplicateLaunch < 2.0 {
            suppressReopenUntil = Date().addingTimeInterval(1.0)
            return false
        }
        guard UserDefaults.standard.bool(forKey: Self.showDockIconKey) else { return false }
        guard isPointerNearDockArea() else { return false }
        showOrFocusOverlay()
        return false  // Suppress default "unhide all windows" behavior
    }
    private func isPointerNearDockArea() -> Bool {
        let mouse = NSEvent.mouseLocation
        return NSScreen.screens.contains { screen in
            let frame = screen.frame
            let visible = screen.visibleFrame
            guard NSMouseInRect(mouse, frame, false) else { return false }
            let bottomDock = visible.minY > frame.minY
                && mouse.y >= frame.minY
                && mouse.y <= visible.minY + 24
            let leftDock = visible.minX > frame.minX
                && mouse.x >= frame.minX
                && mouse.x <= visible.minX + 24
            let rightDock = visible.maxX < frame.maxX
                && mouse.x <= frame.maxX
                && mouse.x >= visible.maxX - 24
            return bottomDock || leftDock || rightDock
        }
    }
    func applicationWillTerminate(_ notification: Notification) {
@@ -272,11 +301,17 @@
    }
    private func beginLauncherForegroundOwnership(activate: Bool = true, keyWindow: NSWindow? = nil) {
        if NSApp.activationPolicy() != .regular {
            NSApp.setActivationPolicy(.regular)
        let showDock = UserDefaults.standard.bool(forKey: Self.showDockIconKey)
        let desiredPolicy: NSApplication.ActivationPolicy = showDock ? .regular : .accessory
        if NSApp.activationPolicy() != desiredPolicy {
            NSApp.setActivationPolicy(desiredPolicy)
        }
        if activate {
        if activate, showDock {
            claimLauncherForeground(keyWindow: keyWindow)
        } else if activate {
            NSApp.activate(ignoringOtherApps: true)
            keyWindow?.makeKeyAndOrderFront(nil)
            keyWindow?.orderFrontRegardless()
        }
    }
@@ -335,15 +370,18 @@
        let shouldStayAccessoryForCurrentFullscreenSpace = isOverlayVisible
            && (avoidSpaceSwitch || overlayAvoidsSpaceSwitch)
        let shouldStayAccessoryForHiddenDockChrome = requiresForegroundOwnership
            && !showDock
        let shouldStayAccessoryForQuickOnlySearch = isOverlayVisible
            && quickSearchOnlyOverlaySession
            && !showDock
        let desiredPolicy: NSApplication.ActivationPolicy = shouldStayAccessoryForCurrentFullscreenSpace
            ? .accessory
            : (shouldStayAccessoryForHiddenDockChrome ? .accessory
            : (shouldStayAccessoryForQuickOnlySearch ? .accessory
            : (requiresForegroundOwnership
            ? .regular
            : (showDock ? .regular : .accessory)))
            : (showDock ? .regular : .accessory))))
        if NSApp.activationPolicy() != desiredPolicy {
            NSApp.setActivationPolicy(desiredPolicy)
        }
@@ -355,6 +393,7 @@
        if activate && requiresForegroundOwnership
            && !shouldStayAccessoryForCurrentFullscreenSpace
            && !shouldStayAccessoryForHiddenDockChrome
            && !shouldStayAccessoryForQuickOnlySearch {
            let keyWindow = isSettingsVisible ? settingsWindow : (isOverlayVisible ? overlayWindow : nil)
            claimLauncherForeground(
@@ -1478,7 +1517,10 @@
    @objc private func handleExternalActivationRequest(_ notification: Notification) {
        let shouldShowOverlay = notification.userInfo?["showOverlay"] as? Bool ?? false
        guard shouldShowOverlay else { return }
        guard shouldShowOverlay else {
            suppressReopenUntil = Date().addingTimeInterval(1.0)
            return
        }
        showOrFocusOverlay()
    }
Apptag/Info.plist
@@ -19,9 +19,9 @@
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>7.8.6</string>
    <string>7.8.7</string>
    <key>CFBundleVersion</key>
    <string>20260531.0146</string>
    <string>20260531.0252</string>
    <key>LSApplicationCategoryType</key>
    <string>public.app-category.utilities</string>
    <key>LSMinimumSystemVersion</key>
Apptag/OverlayWindowController.swift
@@ -154,6 +154,14 @@
                newWindow.setFrame(placementFrame, display: true)
                self.orderFront(newWindow)
            }
            for delay in [0.2, 0.5] {
                DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self, weak newWindow] in
                    guard let self, let newWindow, self.window === newWindow else { return }
                    guard newWindow.frame != placementFrame else { return }
                    newWindow.setFrame(placementFrame, display: true)
                    self.orderFront(newWindow)
                }
            }
            if let settingsWindow = self.dependencies.settingsWindow(), settingsWindow.isVisible {
                self.dependencies.prepareSettingsWindow(settingsWindow)
            }
Apptag/ProcessSingleton.swift
@@ -6,6 +6,7 @@
    private static let lockURL = AppIdentity.applicationSupportDirectory
        .appendingPathComponent("TagLauncher.lock")
    private static let activationNotification = Notification.Name("TagLauncherExternalActivationRequested")
    private static let duplicateLaunchSuppressReopenKey = "duplicateLaunchSuppressReopenAt"
    static func acquireOrHandOffAndExit() -> FileHandle {
        do {
@@ -34,6 +35,8 @@
        let arguments = CommandLine.arguments.dropFirst()
        let shouldShowOverlay = arguments.contains("--show-overlay")
        if !shouldShowOverlay {
            UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: duplicateLaunchSuppressReopenKey)
            UserDefaults.standard.synchronize()
            NSApplication.shared.setActivationPolicy(.accessory)
        }
        let ownerInstance = NSRunningApplication
CHANGELOG.md
@@ -1,5 +1,13 @@
# TagLauncher Changelog
## [7.8.7] — 2026-05-31
- 修复关闭“Show in Dock”后用主快捷键打开 App Grid 时 TagLauncher Dock 图标仍会闪现的问题;隐藏 Dock 图标设置现在严格生效
- 恢复“Show in Dock”开启时点击 Dock 图标打开 App Grid 的交互,同时继续阻止程序化重复启动误唤出 App Grid
- 加固 overlay 显示后的窗口 frame 复核,避免隐藏 Dock / 多屏 / 全屏场景下系统坐标变化导致 overlay 偏移
- 窗口 QA 增加 Dock 点击、隐藏 Dock 主快捷键、重复启动不弹 App Grid 的组合回归
- 版本号更新为 `7.8.7`,Build 更新为 `20260531.0252`
## [7.8.6] — 2026-05-31
- 修复未按主快捷键时 App Grid 可能被重复启动或外部激活路径误唤出的问题;App Grid 现在只由主快捷键或状态栏显式命令打开
Release/AppStore-7.8.7-20260531.0252/APP_STORE_ASSET_INVENTORY.md
New file
@@ -0,0 +1,17 @@
# App Store Asset Inventory
This release pack freezes TagLauncher `7.8.7` build `20260531.0252`.
## Included
- `Archive/TagLauncher-7.8.7-20260531.0252-local-QA.dmg`
- `README.md`
- `QA_RELEASE_EVIDENCE.md`
- `APP_STORE_ASSET_INVENTORY.md`
## External Items Still Required For App Store Upload
- Apple Developer Bundle ID selection/confirmation in App Store Connect.
- Mac App Store signing certificate and provisioning profile.
- Final App Store screenshots and metadata review before submission.
Release/AppStore-7.8.7-20260531.0252/Archive/TagLauncher-7.8.7-20260531.0252-local-QA.dmg
Binary files differ
Release/AppStore-7.8.7-20260531.0252/QA_RELEASE_EVIDENCE.md
New file
@@ -0,0 +1,39 @@
# QA Release Evidence
## Build Under Test
- Version: `7.8.7`
- Build: `20260531.0252`
- App: `/Users/ar/Projects/Taglauncher/build/TagLauncher.app`
- DMG: `/Users/ar/Projects/Taglauncher/build/TagLauncher.dmg`
- Archived DMG: `Archive/TagLauncher-7.8.7-20260531.0252-local-QA.dmg`
- DMG SHA-256: `51cb2861eaf9194dc717cf00b96d3adca490ba89b16438c530b24939a25a94ae`
## Checks
- Version metadata:
  - `CFBundleShortVersionString = 7.8.7`
  - `CFBundleVersion = 20260531.0252`
  - `LSUIElement = true`
- Code signing:
  - `codesign --verify --deep --strict --verbose=2 build/TagLauncher.app`
  - Result: passed
- Disk image:
  - `hdiutil verify build/TagLauncher.dmg`
  - Result: passed
- Window logic:
  - `APP_BUILD=20260531.0252 Scripts/window_logic_qa.sh`
  - Result: `ALL WINDOW LOGIC QA PASSED`
## Targeted Fix Coverage
- `Show in Dock = false`, main hotkey:
  - Expected: App Grid appears and no TagLauncher Dock tile appears.
  - Result: passed
- `Show in Dock = true`, Dock icon click:
  - Expected: App Grid appears.
  - Result: passed
- Duplicate launches:
  - Expected: one Dock tile and no unexpected App Grid.
  - Result: passed
Release/AppStore-7.8.7-20260531.0252/README.md
New file
@@ -0,0 +1,32 @@
# TagLauncher 7.8.7 Release Pack
This folder freezes TagLauncher `7.8.7` build `20260531.0252` for local QA distribution and Mac App Store submission preparation.
## Release Identity
- Product: `TagLauncher`
- Version: `7.8.7`
- Build: `20260531.0252`
- Branch: `codex/fix-quick-search-focus-routing`
- Local QA DMG: `Archive/TagLauncher-7.8.7-20260531.0252-local-QA.dmg`
- DMG SHA-256: `51cb2861eaf9194dc717cf00b96d3adca490ba89b16438c530b24939a25a94ae`
## Changes Since 7.8.6
- Hidden-Dock mode no longer flashes the TagLauncher Dock icon when opening App Grid with the main hotkey.
- Dock icon click opens App Grid when `Show in Dock` is enabled.
- Programmatic duplicate launches remain blocked from opening App Grid.
- Overlay frame is rechecked after show-time system coordinate changes to reduce fullscreen/multi-display drift.
## Verification
- App version metadata verified: `7.8.7 (20260531.0252)`
- `LSUIElement = true`
- `codesign --verify --deep --strict --verbose=2 build/TagLauncher.app`: passed
- `hdiutil verify build/TagLauncher.dmg`: passed
- `Scripts/window_logic_qa.sh`: passed
- Targeted checks:
  - `showDockIcon=false` + main hotkey: App Grid appears, no TagLauncher Dock tile.
  - `showDockIcon=true` + Dock click: App Grid appears.
  - repeated launches: one Dock tile, no unexpected App Grid.
Scripts/window_logic_qa.sh
@@ -278,6 +278,61 @@
  log "PASS Dock tile count: $names"
}
assert_no_dock_tile() {
  local output count names
  output="$(osascript <<'OSA'
tell application "System Events"
  tell process "Dock"
    set tagCount to 0
    set tagNames to {}
    repeat with itemRef in UI elements of list 1
      try
        set itemName to name of itemRef as text
        if itemName is "TagLauncher" then
          set tagCount to tagCount + 1
          set end of tagNames to itemName
        end if
      end try
    end repeat
    return (tagCount as text) & "|" & (tagNames as text)
  end tell
end tell
OSA
)"
  count="${output%%|*}"
  names="${output#*|}"
  if [[ "$count" != "0" ]]; then
    echo "FAIL: expected no TagLauncher Dock tile, got $count ($names)" >&2
    return 1
  fi
  log "PASS no TagLauncher Dock tile"
}
click_taglauncher_dock_tile() {
  local coords x y
  coords="$(osascript <<'OSA'
tell application "System Events"
  tell process "Dock"
    repeat with itemRef in UI elements of list 1
      try
        if (name of itemRef as text) is "TagLauncher" then
          set itemPosition to position of itemRef
          set itemSize to size of itemRef
          set centerX to (item 1 of itemPosition) + ((item 1 of itemSize) / 2)
          set centerY to (item 2 of itemPosition) + ((item 2 of itemSize) / 2)
          return (centerX as integer as text) & " " & (centerY as integer as text)
        end if
      end try
    end repeat
    error "TagLauncher Dock tile not found"
  end tell
end tell
OSA
)"
  read -r x y <<<"$coords"
  click_xy "$x" "$y"
}
assert_frontmost_taglauncher() {
  local frontmost
  frontmost="$(osascript -e 'tell application "System Events" to get name of first application process whose frontmost is true')"
@@ -1071,6 +1126,24 @@
assert_single_qa_app_instance
assert_single_dock_tile
swift_assert no-overlay
log "==> QA Dock reopen: showDockIcon=true opens App Grid from explicit app reopen"
click_taglauncher_dock_tile
sleep 1.0
wait_swift_assert overlay
send_keycode 53
sleep 0.4
wait_swift_assert no-overlay
log "==> QA hidden Dock: main hotkey opens App Grid without showing Dock tile"
defaults write "$DEFAULTS_DOMAIN" showDockIcon -bool false
prepare_isolated_app_instance
assert_no_dock_tile
send_main_hotkey
sleep 0.8
wait_swift_assert overlay
assert_no_dock_tile
send_keycode 53
sleep 0.4
wait_swift_assert no-overlay
kill_all_taglauncher_instances
sleep 0.4
swift_assert no-overlay