Ariver
2026-05-23 211eeed2112bec6bd1301c7a15d1e0deebe78226
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
#!/usr/bin/env bash
set -euo pipefail
 
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
APP_BUNDLE="$ROOT_DIR/build/TagLauncher.app"
APP_PROCESS="TagLauncher"
LAUNCH_AGENT_LABEL="com.taglauncher.app"
LAUNCH_AGENT_PLIST="$HOME/Library/LaunchAgents/$LAUNCH_AGENT_LABEL.plist"
USER_GUI_DOMAIN="gui/$(id -u)"
RESTORE_LAUNCH_AGENT=false
CLICK_TOOL="${CLICK_TOOL:-$(command -v cliclick || true)}"
 
if [[ -z "$CLICK_TOOL" ]]; then
  echo "FAIL: cliclick is required for window-position click checks." >&2
  exit 2
fi
 
log() {
  printf '%s\n' "$*"
}
 
send_keycode() {
  local keycode="$1"
  local modifiers="${2:-}"
  if [[ -n "$modifiers" ]]; then
    osascript -e "tell application \"System Events\" to key code $keycode using {$modifiers}"
  else
    osascript -e "tell application \"System Events\" to key code $keycode"
  fi
}
 
send_main_hotkey() {
  osascript -e 'tell application "System Events" to keystroke space using {option down, shift down}'
}
 
send_cmd_comma() {
  osascript -e 'tell application "System Events" to keystroke "," using {command down}'
}
 
send_cmd_w() {
  osascript -e 'tell application "System Events" to keystroke "w" using {command down}'
}
 
show_overlay_from_app_menu() {
  osascript <<'OSA'
tell application "System Events"
  tell process "TagLauncher"
    repeat 50 times
      set frontmost to true
      delay 0.2
      repeat with itemRef in menu items of menu 1 of menu bar item "TagLauncher" of menu bar 1
        try
          set itemName to name of itemRef as text
          if itemName contains "显示应用列表" or itemName contains "Show" then
            click itemRef
            return
          end if
        end try
      end repeat
    end repeat
    error "TagLauncher Show App List menu item did not become available"
  end tell
end tell
OSA
}
 
cliclick_coord() {
  local value="$1"
  if [[ "$value" == -* ]]; then
    printf '=%s' "$value"
  else
    printf '%s' "$value"
  fi
}
 
click_xy() {
  local x="$1"
  local y="$2"
  "$CLICK_TOOL" c:"$(cliclick_coord "$x")","$(cliclick_coord "$y")"
}
 
move_xy() {
  local x="$1"
  local y="$2"
  "$CLICK_TOOL" m:"$(cliclick_coord "$x")","$(cliclick_coord "$y")"
}
 
cleanup() {
  osascript -e 'tell application "System Events" to key code 53' >/dev/null 2>&1 || true
  sleep 0.2
  osascript -e 'tell application "System Events" to key code 53' >/dev/null 2>&1 || true
  kill_all_taglauncher_instances
  if [[ "$RESTORE_LAUNCH_AGENT" == true && -f "$LAUNCH_AGENT_PLIST" ]]; then
    launchctl bootstrap "$USER_GUI_DOMAIN" "$LAUNCH_AGENT_PLIST" >/dev/null 2>&1 || true
  fi
}
trap cleanup EXIT
 
kill_all_taglauncher_instances() {
  local pids
  pids="$(pgrep -f '/TagLauncher.app/Contents/MacOS/TagLauncher' || true)"
  if [[ -n "$pids" ]]; then
    kill $pids >/dev/null 2>&1 || true
    sleep 0.4
  fi
  pids="$(pgrep -f '/TagLauncher.app/Contents/MacOS/TagLauncher' || true)"
  if [[ -n "$pids" ]]; then
    kill -9 $pids >/dev/null 2>&1 || true
  fi
}
 
is_qa_app_only_running() {
  local lines
  lines="$(pgrep -fl '/TagLauncher.app/Contents/MacOS/TagLauncher' || true)"
  [[ -n "$lines" ]] || return 1
  while IFS= read -r line; do
    [[ "$line" == *"$APP_BUNDLE/Contents/MacOS/TagLauncher"* ]] || return 1
  done <<<"$lines"
}
 
prepare_isolated_app_instance() {
  if launchctl print "$USER_GUI_DOMAIN/$LAUNCH_AGENT_LABEL" >/dev/null 2>&1; then
    RESTORE_LAUNCH_AGENT=true
    launchctl bootout "$USER_GUI_DOMAIN/$LAUNCH_AGENT_LABEL" >/dev/null 2>&1 || true
  fi
 
  kill_all_taglauncher_instances
  open -n "$APP_BUNDLE"
  sleep 2.5
 
  if ! is_qa_app_only_running; then
    echo "FAIL: expected only QA build TagLauncher instance to be running" >&2
    pgrep -fl '/TagLauncher.app/Contents/MacOS/TagLauncher' >&2 || true
    exit 1
  fi
}
 
assert_swift="$(mktemp -t taglauncher-window-assert.XXXXXX.swift)"
coords_swift="$(mktemp -t taglauncher-window-coords.XXXXXX.swift)"
screens_swift="$(mktemp -t taglauncher-screens.XXXXXX.swift)"
trap 'rm -f "$assert_swift" "$coords_swift" "$screens_swift"; cleanup' EXIT
 
cat >"$assert_swift" <<'SWIFT'
import AppKit
import CoreGraphics
import Foundation
 
struct WindowInfo {
    let owner: String
    let name: String
    let layer: Int
    let bounds: NSDictionary
}
 
func allWindows() -> [WindowInfo] {
    let raw = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? []
    return raw.map {
        WindowInfo(
            owner: $0[kCGWindowOwnerName as String] as? String ?? "",
            name: $0[kCGWindowName as String] as? String ?? "",
            layer: $0[kCGWindowLayer as String] as? Int ?? -999,
            bounds: $0[kCGWindowBounds as String] as? NSDictionary ?? [:]
        )
    }
}
 
func dumpRelevantWindows() {
    fputs("---- relevant on-screen windows ----\n", stderr)
    for (index, window) in allWindows().enumerated() {
        let isRelevant = window.owner == "TagLauncher"
            || window.owner == "Window Server"
            || window.owner == "Dock"
            || window.owner == "loginwindow"
        guard isRelevant else { continue }
        fputs("#\(index) owner=\(window.owner) name=\(window.name) layer=\(window.layer) bounds=\(window.bounds)\n", stderr)
    }
    fputs("------------------------------------\n", stderr)
}
 
func fail(_ message: String) -> Never {
    fputs("FAIL: \(message)\n", stderr)
    dumpRelevantWindows()
    exit(1)
}
 
func tagWindows(_ windows: [WindowInfo]) -> [WindowInfo] {
    windows.filter { $0.owner == "TagLauncher" }
}
 
func assertTagLayer(_ tag: [WindowInfo]) {
    for window in tag where window.layer != 23 {
        fail("TagLauncher window has unexpected layer \(window.layer); expected 23")
    }
}
 
let mode = CommandLine.arguments.dropFirst().first ?? ""
let windows = allWindows()
let tag = tagWindows(windows)
 
switch mode {
case "overlay":
    guard tag.count == 1 else { fail("overlay expected 1 TagLauncher window, got \(tag.count)") }
    assertTagLayer(tag)
    let menubarLayer = windows.first { $0.owner == "Window Server" && $0.name == "Menubar" }?.layer
    guard menubarLayer == 24 else { fail("menubar layer expected 24, got \(String(describing: menubarLayer))") }
    let dockWindows = windows.filter { $0.owner == "Dock" }
    guard dockWindows.isEmpty else { fail("Dock should be hidden while overlay is visible; found \(dockWindows.count) Dock windows") }
    print("PASS overlay: tagLayer=\(tag[0].layer) menubarLayer=24 dockWindows=0")
 
case "settings":
    guard tag.count == 2 else { fail("settings expected 2 TagLauncher windows, got \(tag.count)") }
    assertTagLayer(tag)
    guard !tag[0].name.isEmpty, tag[1].name.isEmpty else {
        fail("settings order wrong: \(tag.map(\.name))")
    }
    print("PASS settings over overlay: order=\(tag.map(\.name))")
 
case "file-panel":
    guard tag.count == 3 else { fail("file panel expected 3 TagLauncher windows, got \(tag.count)") }
    assertTagLayer(tag)
    guard !tag[0].name.isEmpty, !tag[1].name.isEmpty, tag[2].name.isEmpty else {
        fail("file panel order wrong: \(tag.map(\.name))")
    }
    print("PASS file panel over settings: order=\(tag.map(\.name))")
 
case "no-overlay":
    guard tag.isEmpty else { fail("expected no TagLauncher windows, got \(tag.count)") }
    print("PASS overlay hidden")
 
case "force-quit":
    guard let overlay = tag.first else { fail("force quit check expected overlay window") }
    guard let forceQuit = windows.first(where: {
        $0.owner == "loginwindow" && ($0.name.localizedCaseInsensitiveContains("force") || $0.name.contains("强制"))
    }) else {
        fail("force quit window not found")
    }
    guard forceQuit.layer > overlay.layer else {
        fail("force quit layer \(forceQuit.layer) is not above overlay layer \(overlay.layer)")
    }
    print("PASS force quit above overlay: forceQuitLayer=\(forceQuit.layer) overlayLayer=\(overlay.layer)")
 
case "screen-count":
    print("INFO screens=\(NSScreen.screens.count) frames=\(NSScreen.screens.map { NSStringFromRect($0.frame) })")
 
default:
    fail("unknown assert mode: \(mode)")
}
SWIFT
 
cat >"$coords_swift" <<'SWIFT'
import CoreGraphics
import Foundation
 
let raw = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? []
let tag = raw.filter { ($0[kCGWindowOwnerName as String] as? String) == "TagLauncher" }
let mode = CommandLine.arguments.dropFirst().first ?? ""
switch mode {
case "data-tab":
    guard let settings = tag.first(where: { (($0[kCGWindowName as String] as? String) ?? "").isEmpty == false }),
          let bounds = settings[kCGWindowBounds as String] as? NSDictionary,
          let x = bounds["X"] as? CGFloat,
          let y = bounds["Y"] as? CGFloat else {
        fputs("FAIL: could not find settings window bounds\n", stderr)
        exit(1)
    }
    print("\(Int(round(x + 523))) \(Int(round(y + 50)))")
case "export":
    guard let settings = tag.first(where: { (($0[kCGWindowName as String] as? String) ?? "").isEmpty == false }),
          let bounds = settings[kCGWindowBounds as String] as? NSDictionary,
          let x = bounds["X"] as? CGFloat,
          let y = bounds["Y"] as? CGFloat else {
        fputs("FAIL: could not find settings window bounds\n", stderr)
        exit(1)
    }
    print("\(Int(round(x + 375))) \(Int(round(y + 331)))")
case "overlay-outside":
    guard let overlay = tag.first(where: { (($0[kCGWindowName as String] as? String) ?? "").isEmpty }),
          let overlayBounds = overlay[kCGWindowBounds as String] as? NSDictionary,
          let overlayX = overlayBounds["X"] as? CGFloat,
          let overlayY = overlayBounds["Y"] as? CGFloat else {
        fputs("FAIL: could not find overlay window bounds\n", stderr)
        exit(1)
    }
    print("\(Int(round(overlayX + 120))) \(Int(round(overlayY + 160)))")
default:
    fputs("FAIL: unknown coords mode \(mode)\n", stderr)
    exit(1)
}
SWIFT
 
cat >"$screens_swift" <<'SWIFT'
import AppKit
import Foundation
 
for (index, screen) in NSScreen.screens.enumerated() {
    let frame = screen.frame
    let cgTop = NSScreen.screens.map { $0.frame.maxY }.max() ?? frame.maxY
    let cgY = cgTop - frame.maxY
    let clickY = cgY + frame.height / 2
    print("\(index)|\(Int(round(frame.midX)))|\(Int(round(clickY)))|\(Int(round(frame.origin.x)))|\(Int(round(cgY)))|\(Int(round(frame.width)))|\(Int(round(frame.height)))")
}
SWIFT
 
swift_assert() {
  swift "$assert_swift" "$1"
}
 
wait_swift_assert() {
  local mode="$1"
  local output=""
  for _ in {1..12}; do
    if output="$(swift "$assert_swift" "$mode" 2>&1)"; then
      printf '%s\n' "$output"
      return 0
    fi
    sleep 0.2
  done
  printf '%s\n' "$output" >&2
  return 1
}
 
show_overlay() {
  send_main_hotkey
  if wait_swift_assert overlay >/dev/null 2>&1; then
    swift_assert overlay
    return 0
  fi
 
  show_overlay_from_app_menu
  wait_swift_assert overlay
}
 
click_relative_to_settings() {
  local mode="$1"
  local coords
  coords="$(swift "$coords_swift" "$mode")"
  read -r x y <<<"$coords"
  click_xy "$x" "$y"
}
 
click_overlay_outside_quick_search() {
  local coords
  coords="$(swift "$coords_swift" overlay-outside)"
  read -r x y <<<"$coords"
  click_xy "$x" "$y"
}
 
log "==> Building app"
bash "$ROOT_DIR/build.sh" >/dev/null
 
log "==> Starting clean app instance"
prepare_isolated_app_instance
 
log "==> QA 1/7: overlay claims foreground, hides Dock, keeps menu bar visible"
show_overlay
frontmost="$(osascript -e 'tell application "System Events" to get name of first application process whose frontmost is true')"
[[ "$frontmost" == "TagLauncher" ]] || { echo "FAIL: frontmost app is $frontmost, expected TagLauncher" >&2; exit 1; }
swift_assert overlay
 
log "==> QA 1/7 and 4/7: settings floats above appgrid and quick search"
send_keycode 49
sleep 0.4
send_cmd_comma
sleep 0.7
swift_assert settings
 
log "==> QA 2/7: import/export file panel floats above settings"
click_relative_to_settings data-tab
sleep 0.3
click_relative_to_settings export
sleep 0.7
swift_assert file-panel
send_keycode 53
sleep 0.3
send_cmd_w
sleep 0.5
swift_assert overlay
 
log "==> QA 4/7 and 5/7: appgrid-space quick search and double-Esc behavior"
send_keycode 49
sleep 0.4
send_keycode 53
sleep 0.4
swift_assert overlay
send_keycode 53
sleep 0.4
swift_assert no-overlay
 
log "==> QA 5/7: clicking outside quick search closes search, not appgrid"
show_overlay
send_keycode 49
sleep 0.4
click_overlay_outside_quick_search
sleep 0.4
swift_assert overlay
 
log "==> QA 3/7: system force-quit window stays above TagLauncher"
send_keycode 53 "option down, command down"
sleep 0.7
swift_assert force-quit
send_keycode 53
sleep 0.3
 
log "==> QA 6/7: screen-following logic"
swift_assert screen-count
screen_count="$(swift "$screens_swift" | wc -l | tr -d ' ')"
if [[ "$screen_count" -gt 1 ]]; then
  while IFS='|' read -r index cx cy sx sy sw sh; do
    kill_all_taglauncher_instances
    open -n "$APP_BUNDLE"
    sleep 2.5
    if ! is_qa_app_only_running; then
      echo "FAIL: expected only QA build TagLauncher instance during screen-following check" >&2
      pgrep -fl '/TagLauncher.app/Contents/MacOS/TagLauncher' >&2 || true
      exit 1
    fi
    move_xy "$cx" "$cy"
    sleep 0.2
    show_overlay
    wait_swift_assert overlay
    swift - "$sx" "$sy" "$sw" "$sh" <<'SWIFT'
import CoreGraphics
import Foundation
let expected = CommandLine.arguments.dropFirst().map { Int($0)! }
let raw = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? []
let tag = raw.filter { ($0[kCGWindowOwnerName as String] as? String) == "TagLauncher" }
guard tag.count == 1, let bounds = tag[0][kCGWindowBounds as String] as? NSDictionary else {
    fputs("FAIL: expected one overlay for screen-following check\n", stderr)
    exit(1)
}
let actual = ["X", "Y", "Width", "Height"].map { Int(round((bounds[$0] as? Double) ?? 0)) }
guard actual == expected else {
    fputs("FAIL: overlay bounds \(actual) did not match screen frame \(expected)\n", stderr)
    exit(1)
}
print("PASS screen frame: \(actual)")
SWIFT
  done < <(swift "$screens_swift")
else
  rg -Fq 'screenContainingCurrentPointer() ??' "$ROOT_DIR/Apptag/ApptagApp.swift"
  rg -Fq 'NSMouseInRect(mousePoint, $0.frame, false)' "$ROOT_DIR/Apptag/ApptagApp.swift"
  log "PASS screen-following static path: single physical display here; code selects NSScreen under current pointer"
fi
 
log "==> QA 7/7: final chrome state still valid"
swift_assert overlay
send_keycode 53
sleep 0.4
swift_assert no-overlay
 
log "ALL WINDOW LOGIC QA PASSED"