Ariver
2026-06-28 d8b67d9510123320c78bf15c26c8a0177848b0b1
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
#!/usr/bin/env bash
set -euo pipefail
 
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
INFO_PLIST="$ROOT_DIR/Apptag/Info.plist"
APPTAG_APP_SWIFT="$ROOT_DIR/Apptag/ApptagApp.swift"
PREFERENCES_VIEW_SWIFT="$ROOT_DIR/Apptag/PreferencesView.swift"
L10N_SWIFT="$ROOT_DIR/Apptag/L10n.swift"
LOCALIZATION_DIR="$ROOT_DIR/Apptag/Localization"
 
fail() {
  printf 'FAIL: %s\n' "$*" >&2
  exit 1
}
 
[[ -f "$INFO_PLIST" ]] || fail "missing Info.plist"
[[ -f "$APPTAG_APP_SWIFT" ]] || fail "missing ApptagApp.swift"
[[ -f "$PREFERENCES_VIEW_SWIFT" ]] || fail "missing PreferencesView.swift"
[[ -f "$L10N_SWIFT" ]] || fail "missing L10n.swift"
[[ -d "$LOCALIZATION_DIR" ]] || fail "missing Localization directory"
 
plutil -lint "$INFO_PLIST" >/dev/null || fail "Info.plist is not valid"
 
SCHEME=$(/usr/libexec/PlistBuddy -c "Print :CFBundleURLTypes:0:CFBundleURLSchemes:0" "$INFO_PLIST" 2>/dev/null || true)
[[ "$SCHEME" == "taglauncher" ]] || fail "Info.plist must register taglauncher URL scheme"
 
VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST")
BUILD=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$INFO_PLIST")
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "invalid CFBundleShortVersionString: $VERSION"
[[ "$BUILD" =~ ^[0-9]{8}\.[0-9]{4}$ ]] || fail "invalid CFBundleVersion: $BUILD"
 
python3 - "$ROOT_DIR" <<'PY'
import json
import pathlib
import re
import sys
 
root = pathlib.Path(sys.argv[1])
app = (root / "Apptag" / "ApptagApp.swift").read_text(encoding="utf-8")
preferences = (root / "Apptag" / "PreferencesView.swift").read_text(encoding="utf-8")
l10n = (root / "Apptag" / "L10n.swift").read_text(encoding="utf-8")
localization_dir = root / "Apptag" / "Localization"
 
 
def fail(message: str) -> None:
    print(f"FAIL: {message}", file=sys.stderr)
    sys.exit(1)
 
 
def require(pattern: str, source: str, message: str) -> None:
    if not re.search(pattern, source, re.S):
        fail(message)
 
 
require(
    r"func\s+application\s*\(\s*_\s+application\s*:\s*NSApplication\s*,\s*open\s+urls\s*:\s*\[URL\]\s*\)",
    app,
    "AppDelegate must implement application(_:open:) for URL scheme activation",
)
require(r'externalInvocationScheme\s*=\s*"taglauncher"', app, "URL scheme constant must be taglauncher")
require(r'externalInvocationShowHost\s*=\s*"show"', app, "URL show route constant must be show")
require(r"pendingShowOverlayInvocation", app, "cold-launch URL requests must have a pending show flag")
require(r"didFinishLaunching", app, "URL requests must be gated on launch readiness")
require(
    r"private\s+func\s+requestShowOverlayFromExternalInvocation\s*\(\)\s*\{(?P<body>.*?)showOrFocusOverlay\s*\(",
    app,
    "external show invocation must call showOrFocusOverlay()",
)
request_match = re.search(
    r"private\s+func\s+requestShowOverlayFromExternalInvocation\s*\(\)\s*\{(?P<body>.*?)\n\s*private\s+func\s+consumePendingShowOverlayInvocationIfNeeded",
    app,
    re.S,
)
if not request_match:
    fail("could not inspect requestShowOverlayFromExternalInvocation()")
request_body = request_match.group("body")
if "performToggleOverlay" in request_body or "toggleOverlay" in request_body:
    fail("external URL show must not use toggle overlay behavior")
if "dismissQuickSearchIfNeeded()" not in request_body:
    fail("external URL show must dismiss conflicting Quick Search transient state")
require(
    r"private\s+func\s+consumePendingShowOverlayInvocationIfNeeded\s*\(\)\s*\{(?P<body>.*?)requestShowOverlayFromExternalInvocation\s*\(\)",
    app,
    "launch completion must consume pending URL show requests",
)
require(
    r"quickSearch.globalHotkey(?P<body>.*?)trackpadGesture.title(?P<body2>.*?)taglauncher://show",
    preferences,
    "Hotkeys settings must document taglauncher://show for external gesture tools",
)
 
for forbidden in [
    "MultitouchSupport",
    "IOHID",
    "CGEventTapCreate",
    "AXIsProcessTrusted",
    "InputMonitoring",
    "addGlobalMonitorForEvents(matching: .gesture",
]:
    if forbidden in app:
        fail(f"AppDelegate must not add native/global trackpad capture: {forbidden}")
 
match = re.search(
    r"static\s+let\s+supported\s*:\s*\[\(code:\s*String,\s*name:\s*String\)\]\s*=\s*\[(.*?)\n\s*\]",
    l10n,
    re.S,
)
if not match:
    fail("could not read L10n.supported")
codes = re.findall(r'\("([^"]+)",\s*"[^"]+"\)', match.group(1))
if len(codes) != 29:
    fail(f"expected 29 supported languages, found {len(codes)}")
 
required_keys = [
    "trackpadGesture.title",
    "trackpadGesture.description",
    "trackpadGesture.status",
]
for code in codes:
    path = localization_dir / f"{code}.json"
    if not path.is_file():
        fail(f"missing localization file for {code}")
    data = json.loads(path.read_text(encoding="utf-8"))
    missing = [key for key in required_keys if not isinstance(data.get(key), str) or not data[key].strip()]
    if missing:
        fail(f"{code}.json missing URL scheme gesture keys: {', '.join(missing)}")
    if "taglauncher://show" in data["trackpadGesture.description"]:
        fail(f"{code}.json should keep the URL in the fixed display field, not inside localized prose")
 
print(
    "PASS URL scheme activation QA: taglauncher://show, show/focus semantics, "
    f"{len(codes)} localized settings strings, no private gesture capture"
)
PY