@lattices/cli 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -13
  3. package/{app → apps/mac}/Lattices.app/Contents/Info.plist +10 -2
  4. package/{app → apps/mac}/Lattices.app/Contents/MacOS/Lattices +0 -0
  5. package/{app → apps/mac}/Package.swift +2 -1
  6. package/apps/mac/Resources/Pets/assistant-spark/pet.json +62 -0
  7. package/apps/mac/Resources/Pets/assistant-spark/spritesheet.webp +0 -0
  8. package/apps/mac/Resources/Pets/scout-ranger/pet.json +6 -0
  9. package/apps/mac/Resources/Pets/scout-ranger/spritesheet.webp +0 -0
  10. package/apps/mac/Sources/AppShell/AppActivationCoordinator.swift +27 -0
  11. package/apps/mac/Sources/AppShell/AppDelegate.swift +189 -0
  12. package/apps/mac/Sources/AppShell/AppServicesBootstrap.swift +25 -0
  13. package/{app → apps/mac}/Sources/AppShell/AppShellView.swift +18 -3
  14. package/{app → apps/mac}/Sources/AppShell/AppUpdater.swift +4 -3
  15. package/apps/mac/Sources/AppShell/HotkeyBootstrap.swift +87 -0
  16. package/{app → apps/mac}/Sources/AppShell/LatticesRuntime.swift +43 -0
  17. package/{app → apps/mac}/Sources/AppShell/MainView.swift +116 -63
  18. package/apps/mac/Sources/AppShell/MenuBarController.swift +177 -0
  19. package/{app → apps/mac}/Sources/AppShell/OnboardingView.swift +72 -60
  20. package/apps/mac/Sources/AppShell/PermissionsAssistantView.swift +366 -0
  21. package/apps/mac/Sources/AppShell/PermissionsAssistantWindow.swift +70 -0
  22. package/{app → apps/mac}/Sources/AppShell/Preferences.swift +37 -2
  23. package/{app → apps/mac}/Sources/AppShell/SettingsView.swift +815 -156
  24. package/{app → apps/mac}/Sources/AppShell/SettingsWindow.swift +10 -0
  25. package/apps/mac/Sources/AppShell/WorkspaceInspectorPresenter.swift +13 -0
  26. package/{app → apps/mac}/Sources/Core/Actions/HotkeyStore.swift +6 -1
  27. package/{app → apps/mac}/Sources/Core/Actions/IntentEngine.swift +2 -0
  28. package/{app → apps/mac}/Sources/Core/Daemon/DaemonServer.swift +5 -0
  29. package/{app → apps/mac}/Sources/Core/Daemon/LatticesApi.swift +365 -0
  30. package/{app → apps/mac}/Sources/Core/Desktop/OcrModel.swift +17 -13
  31. package/apps/mac/Sources/Core/Desktop/WindowCapture.swift +33 -0
  32. package/{app → apps/mac}/Sources/Core/Desktop/WindowDragSnapController.swift +18 -217
  33. package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewStore.swift +4 -5
  34. package/{app → apps/mac}/Sources/Core/Desktop/WindowTiler.swift +19 -13
  35. package/apps/mac/Sources/Core/Input/EventTapBreaker.swift +124 -0
  36. package/apps/mac/Sources/Core/Input/EventTapThread.swift +54 -0
  37. package/apps/mac/Sources/Core/Input/InputCaptureResetCenter.swift +20 -0
  38. package/apps/mac/Sources/Core/Input/KeyboardRemapController.swift +335 -0
  39. package/apps/mac/Sources/Core/Input/KeyboardRemapStore.swift +141 -0
  40. package/{app → apps/mac}/Sources/Core/Input/MouseGestureConfig.swift +155 -20
  41. package/apps/mac/Sources/Core/Input/MouseGestureController.swift +2271 -0
  42. package/apps/mac/Sources/Core/Input/MouseShortcutStore.swift +170 -0
  43. package/apps/mac/Sources/Core/Input/SecureEventInputMonitor.swift +39 -0
  44. package/apps/mac/Sources/Core/Input/ShapeRecognizer.swift +624 -0
  45. package/apps/mac/Sources/Core/Input/TapBudgetMeter.swift +56 -0
  46. package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapState.swift +8 -8
  47. package/apps/mac/Sources/Core/Overlays/ScreenOverlayCanvasController.swift +1264 -0
  48. package/{app → apps/mac}/Sources/Core/Overlays/Voice/VoiceCommandWindow.swift +11 -23
  49. package/{app → apps/mac}/Sources/Core/Pi/PiChatDock.swift +90 -43
  50. package/{app → apps/mac}/Sources/Core/Pi/PiChatSession.swift +676 -43
  51. package/{app → apps/mac}/Sources/Core/Pi/PiProviderSetupCallout.swift +5 -5
  52. package/{app → apps/mac}/Sources/Core/Pi/PiWorkspaceView.swift +93 -44
  53. package/apps/mac/Sources/Core/System/Capability.swift +79 -0
  54. package/{app → apps/mac}/Sources/Core/System/PermissionChecker.swift +43 -8
  55. package/{app → apps/mac}/Sources/Core/Voice/AudioProvider.swift +225 -56
  56. package/bin/handsoff-infer.ts +14 -5
  57. package/bin/handsoff-worker.ts +11 -7
  58. package/bin/infer.ts +406 -0
  59. package/bin/lattices-app.ts +57 -7
  60. package/bin/lattices-dev +40 -1
  61. package/bin/lattices.ts +1 -1
  62. package/docs/agent-execution-plan.md +9 -9
  63. package/docs/api.md +119 -0
  64. package/docs/app.md +1 -0
  65. package/docs/companion-deck.md +1 -1
  66. package/docs/gesture-customization-proposal.md +520 -0
  67. package/docs/mouse-gestures.md +79 -0
  68. package/docs/overview.md +2 -2
  69. package/docs/presentation-execution-review.md +9 -9
  70. package/docs/proposals/LAT-001-gesture-visual-customization.md +522 -0
  71. package/docs/proposals/LAT-002-shared-overlay-canvas.md +353 -0
  72. package/docs/proposals/LAT-003-menu-bar-controller-architecture.md +291 -0
  73. package/docs/proposals/LAT-004-interactive-overlay-actors.md +534 -0
  74. package/docs/reference/dewey.config.ts +74 -0
  75. package/docs/reference/install-agent.md +79 -0
  76. package/docs/repo-structure.md +100 -0
  77. package/docs/voice-error-model.md +7 -7
  78. package/docs/voice.md +18 -0
  79. package/package.json +23 -13
  80. package/swift/Package.swift +20 -0
  81. package/swift/Sources/DeckKit/DeckAction.swift +51 -0
  82. package/swift/Sources/DeckKit/DeckBridgeSecurity.swift +152 -0
  83. package/swift/Sources/DeckKit/DeckCockpit.swift +82 -0
  84. package/swift/Sources/DeckKit/DeckHost.swift +7 -0
  85. package/swift/Sources/DeckKit/DeckManifest.swift +145 -0
  86. package/swift/Sources/DeckKit/DeckRuntimeSnapshot.swift +533 -0
  87. package/swift/Sources/DeckKit/DeckTrackpad.swift +63 -0
  88. package/swift/Sources/DeckKit/DeckValue.swift +93 -0
  89. package/swift/Sources/DeckKit/DeckVoiceError.swift +88 -0
  90. package/swift/Tests/DeckKitTests/DeckKitTests.swift +286 -0
  91. package/app/Sources/AppShell/AppDelegate.swift +0 -408
  92. package/app/Sources/Core/Input/KeyboardRemapController.swift +0 -184
  93. package/app/Sources/Core/Input/KeyboardRemapStore.swift +0 -84
  94. package/app/Sources/Core/Input/MouseGestureController.swift +0 -1203
  95. package/app/Sources/Core/Input/MouseShortcutStore.swift +0 -107
  96. /package/{app → apps/mac}/Info.plist +0 -0
  97. /package/{app → apps/mac}/Lattices.app/Contents/Resources/AppIcon.icns +0 -0
  98. /package/{app → apps/mac}/Lattices.app/Contents/Resources/tap.wav +0 -0
  99. /package/{app → apps/mac}/Lattices.app/Contents/_CodeSignature/CodeResources +0 -0
  100. /package/{app → apps/mac}/Lattices.entitlements +0 -0
  101. /package/{app → apps/mac}/Resources/tap.wav +0 -0
  102. /package/{app → apps/mac}/Sources/AppShell/App.swift +0 -0
  103. /package/{app → apps/mac}/Sources/AppShell/CliActionLauncher.swift +0 -0
  104. /package/{app → apps/mac}/Sources/AppShell/HomeDashboardView.swift +0 -0
  105. /package/{app → apps/mac}/Sources/AppShell/KeyRecorderView.swift +0 -0
  106. /package/{app → apps/mac}/Sources/AppShell/MainWindow.swift +0 -0
  107. /package/{app → apps/mac}/Sources/Core/Actions/HotkeyManager.swift +0 -0
  108. /package/{app → apps/mac}/Sources/Core/Actions/IntentSchema.swift +0 -0
  109. /package/{app → apps/mac}/Sources/Core/Actions/Intents/CreateLayerIntent.swift +0 -0
  110. /package/{app → apps/mac}/Sources/Core/Actions/Intents/DistributeIntent.swift +0 -0
  111. /package/{app → apps/mac}/Sources/Core/Actions/Intents/FocusIntent.swift +0 -0
  112. /package/{app → apps/mac}/Sources/Core/Actions/Intents/HelpIntent.swift +0 -0
  113. /package/{app → apps/mac}/Sources/Core/Actions/Intents/KillIntent.swift +0 -0
  114. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LatticeIntent.swift +0 -0
  115. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LaunchIntent.swift +0 -0
  116. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListSessionsIntent.swift +0 -0
  117. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListWindowsIntent.swift +0 -0
  118. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ScanIntent.swift +0 -0
  119. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SearchIntent.swift +0 -0
  120. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SwitchLayerIntent.swift +0 -0
  121. /package/{app → apps/mac}/Sources/Core/Actions/Intents/TileIntent.swift +0 -0
  122. /package/{app → apps/mac}/Sources/Core/Actions/PaletteCommand.swift +0 -0
  123. /package/{app → apps/mac}/Sources/Core/Actions/VoiceIntentResolver.swift +0 -0
  124. /package/{app → apps/mac}/Sources/Core/Companion/CompanionActivityLog.swift +0 -0
  125. /package/{app → apps/mac}/Sources/Core/Companion/CompanionKeyboardController.swift +0 -0
  126. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +0 -0
  127. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionCockpit.swift +0 -0
  128. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +0 -0
  129. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +0 -0
  130. /package/{app → apps/mac}/Sources/Core/Companion/LatticesDeckHost.swift +0 -0
  131. /package/{app → apps/mac}/Sources/Core/Daemon/DaemonProtocol.swift +0 -0
  132. /package/{app → apps/mac}/Sources/Core/Desktop/AccessibilityTextExtractor.swift +0 -0
  133. /package/{app → apps/mac}/Sources/Core/Desktop/AppTypeClassifier.swift +0 -0
  134. /package/{app → apps/mac}/Sources/Core/Desktop/DesktopModel.swift +0 -0
  135. /package/{app → apps/mac}/Sources/Core/Desktop/DesktopModelTypes.swift +0 -0
  136. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryManager.swift +0 -0
  137. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryPath.swift +0 -0
  138. /package/{app → apps/mac}/Sources/Core/Desktop/MouseFinder.swift +0 -0
  139. /package/{app → apps/mac}/Sources/Core/Desktop/OcrStore.swift +0 -0
  140. /package/{app → apps/mac}/Sources/Core/Desktop/PlacementSpec.swift +0 -0
  141. /package/{app → apps/mac}/Sources/Core/Desktop/SessionWindowLocator.swift +0 -0
  142. /package/{app → apps/mac}/Sources/Core/Desktop/TilePickerView.swift +0 -0
  143. /package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewCard.swift +0 -0
  144. /package/{app → apps/mac}/Sources/Core/Desktop/WindowSelectionStore.swift +0 -0
  145. /package/{app → apps/mac}/Sources/Core/Input/KeyboardRemapConfig.swift +0 -0
  146. /package/{app → apps/mac}/Sources/Core/Input/MouseInputDeviceStore.swift +0 -0
  147. /package/{app → apps/mac}/Sources/Core/Input/MouseInputEventViewer.swift +0 -0
  148. /package/{app → apps/mac}/Sources/Core/Overlays/AppWindowShell.swift +0 -0
  149. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeState.swift +0 -0
  150. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeView.swift +0 -0
  151. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeWindow.swift +0 -0
  152. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteView.swift +0 -0
  153. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteWindow.swift +0 -0
  154. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/CheatSheetHUD.swift +0 -0
  155. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDBottomBar.swift +0 -0
  156. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDController.swift +0 -0
  157. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDLeftBar.swift +0 -0
  158. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDMinimap.swift +0 -0
  159. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDRightBar.swift +0 -0
  160. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDState.swift +0 -0
  161. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDTopBar.swift +0 -0
  162. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LauncherHUD.swift +0 -0
  163. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LayerBezel.swift +0 -0
  164. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchState.swift +0 -0
  165. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchView.swift +0 -0
  166. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchWindow.swift +0 -0
  167. /package/{app → apps/mac}/Sources/Core/Overlays/OverlayPanelShell.swift +0 -0
  168. /package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapView.swift +0 -0
  169. /package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapWindowController.swift +0 -0
  170. /package/{app → apps/mac}/Sources/Core/Pi/PiAuthNextStepCard.swift +0 -0
  171. /package/{app → apps/mac}/Sources/Core/Pi/PiAuthPromptCard.swift +0 -0
  172. /package/{app → apps/mac}/Sources/Core/Pi/PiInstallCallout.swift +0 -0
  173. /package/{app → apps/mac}/Sources/Core/System/DiagnosticLog.swift +0 -0
  174. /package/{app → apps/mac}/Sources/Core/System/EventBus.swift +0 -0
  175. /package/{app → apps/mac}/Sources/Core/System/ProcessModel.swift +0 -0
  176. /package/{app → apps/mac}/Sources/Core/System/ProcessQuery.swift +0 -0
  177. /package/{app → apps/mac}/Sources/Core/System/SystemTelemetryMonitor.swift +0 -0
  178. /package/{app → apps/mac}/Sources/Core/Voice/AdvisorLearningStore.swift +0 -0
  179. /package/{app → apps/mac}/Sources/Core/Voice/AgentSession.swift +0 -0
  180. /package/{app → apps/mac}/Sources/Core/Voice/HandsOffSession.swift +0 -0
  181. /package/{app → apps/mac}/Sources/Core/Voice/VoiceChatView.swift +0 -0
  182. /package/{app → apps/mac}/Sources/Core/Voice/VoxClient.swift +0 -0
  183. /package/{app → apps/mac}/Sources/Core/Workspace/Project.swift +0 -0
  184. /package/{app → apps/mac}/Sources/Core/Workspace/ProjectScanner.swift +0 -0
  185. /package/{app → apps/mac}/Sources/Core/Workspace/SessionLayerStore.swift +0 -0
  186. /package/{app → apps/mac}/Sources/Core/Workspace/SessionManager.swift +0 -0
  187. /package/{app → apps/mac}/Sources/Core/Workspace/Terminal/Terminal.swift +0 -0
  188. /package/{app → apps/mac}/Sources/Core/Workspace/Terminal/TerminalQuery.swift +0 -0
  189. /package/{app → apps/mac}/Sources/Core/Workspace/Terminal/TerminalSynthesizer.swift +0 -0
  190. /package/{app → apps/mac}/Sources/Core/Workspace/Tmux/TmuxModel.swift +0 -0
  191. /package/{app → apps/mac}/Sources/Core/Workspace/Tmux/TmuxQuery.swift +0 -0
  192. /package/{app → apps/mac}/Sources/Core/Workspace/WorkspaceManager.swift +0 -0
  193. /package/{app → apps/mac}/Sources/UI/ActionRow.swift +0 -0
  194. /package/{app → apps/mac}/Sources/UI/OrphanRow.swift +0 -0
  195. /package/{app → apps/mac}/Sources/UI/ProjectRow.swift +0 -0
  196. /package/{app → apps/mac}/Sources/UI/TabGroupRow.swift +0 -0
  197. /package/{app → apps/mac}/Sources/UI/Theme.swift +0 -0
  198. /package/{app → apps/mac}/Tests/StageDragTests.swift +0 -0
  199. /package/{app → apps/mac}/Tests/StageJoinTests.swift +0 -0
  200. /package/{app → apps/mac}/Tests/StageManagerTests.swift +0 -0
  201. /package/{app → apps/mac}/Tests/StageTileTests.swift +0 -0
@@ -0,0 +1,170 @@
1
+ import AppKit
2
+ import Combine
3
+ import Foundation
4
+
5
+ final class MouseShortcutStore: ObservableObject {
6
+ static let shared = MouseShortcutStore()
7
+
8
+ /// Drives SwiftUI bindings; mutations always happen on main.
9
+ @Published private(set) var config: MouseShortcutConfig
10
+
11
+ let configURL: URL
12
+
13
+ /// Lock-protected mirror of `config` for tap-thread reads. The mouse event
14
+ /// tap fires on a non-main thread (EventTapThread) and reads
15
+ /// `watchedButtonNumbers` to compute the consume-vs-pass verdict; mutating
16
+ /// `config` (a struct) on main while reading from the tap thread is a
17
+ /// torn-read race. All tap-thread accessors read this snapshot under
18
+ /// `stateLock`.
19
+ private let stateLock = NSLock()
20
+ private var snapshot: MouseShortcutConfig
21
+ private var lastLoadedModifiedDate: Date?
22
+
23
+ private init() {
24
+ let dir = FileManager.default.homeDirectoryForCurrentUser
25
+ .appendingPathComponent(".lattices")
26
+ try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
27
+ self.configURL = dir.appendingPathComponent("mouse-shortcuts.json")
28
+ self.config = .defaults
29
+ self.snapshot = .defaults
30
+ ensureConfigFile()
31
+ reload()
32
+ }
33
+
34
+ var tuning: MouseShortcutTuning {
35
+ stateLock.lock(); defer { stateLock.unlock() }
36
+ return snapshot.tuning
37
+ }
38
+
39
+ var enabledRules: [MouseShortcutRule] {
40
+ stateLock.lock(); defer { stateLock.unlock() }
41
+ return snapshot.rules.filter(\.enabled)
42
+ }
43
+
44
+ var watchedButtonNumbers: Set<Int64> {
45
+ stateLock.lock(); defer { stateLock.unlock() }
46
+ return Set(snapshot.rules.filter(\.enabled).map { Int64($0.trigger.button.rawButtonNumber) })
47
+ }
48
+
49
+ func hasEnabledRule(button: MouseShortcutButton, kind: MouseShortcutTriggerKind) -> Bool {
50
+ stateLock.lock(); defer { stateLock.unlock() }
51
+ return snapshot.rules.contains { rule in
52
+ rule.enabled
53
+ && rule.trigger.button == button
54
+ && rule.trigger.kind == kind
55
+ }
56
+ }
57
+
58
+ var summaryLines: [String] {
59
+ stateLock.lock(); defer { stateLock.unlock() }
60
+ return snapshot.rules.filter(\.enabled).map { "\($0.trigger.triggerName) -> \($0.action.type.rawValue)" }
61
+ }
62
+
63
+ func visualHint(for button: MouseShortcutButton) -> MouseShortcutVisualDefinition? {
64
+ stateLock.lock(); defer { stateLock.unlock() }
65
+ return snapshot.rules.filter(\.enabled).first { $0.trigger.button == button && $0.visual != nil }?.visual
66
+ }
67
+
68
+ func ensureConfigFile() {
69
+ guard !FileManager.default.fileExists(atPath: configURL.path) else { return }
70
+ write(config: .defaults)
71
+ }
72
+
73
+ func reload() {
74
+ let newDate = modifiedDate()
75
+ let newConfig: MouseShortcutConfig
76
+ if let data = FileManager.default.contents(atPath: configURL.path) {
77
+ do {
78
+ newConfig = try JSONDecoder().decode(MouseShortcutConfig.self, from: data)
79
+ } catch {
80
+ DiagnosticLog.shared.error("MouseShortcutStore: failed to decode mouse-shortcuts.json - \(error.localizedDescription)")
81
+ newConfig = .defaults
82
+ }
83
+ } else {
84
+ newConfig = .defaults
85
+ }
86
+ stateLock.lock()
87
+ snapshot = newConfig
88
+ lastLoadedModifiedDate = newDate
89
+ stateLock.unlock()
90
+ // @Published mutation must happen on main.
91
+ if Thread.isMainThread {
92
+ config = newConfig
93
+ } else {
94
+ DispatchQueue.main.async { [weak self] in
95
+ self?.config = newConfig
96
+ }
97
+ }
98
+ }
99
+
100
+ func reloadIfNeeded() {
101
+ // Called from the mouse event-tap thread (and from main paths). The
102
+ // stat is cheap and thread-safe; we claim the new mtime up-front so
103
+ // concurrent calls don't queue duplicate reloads while one is in
104
+ // flight (if reload fails to decode, we'll retry on the next mtime
105
+ // change).
106
+ let currentModifiedDate = modifiedDate()
107
+ stateLock.lock()
108
+ let needsReload = currentModifiedDate != lastLoadedModifiedDate
109
+ if needsReload {
110
+ lastLoadedModifiedDate = currentModifiedDate
111
+ }
112
+ stateLock.unlock()
113
+ guard needsReload else { return }
114
+ reload()
115
+ }
116
+
117
+ func restoreDefaults() {
118
+ write(config: .defaults)
119
+ reload()
120
+ DiagnosticLog.shared.info("Mouse shortcuts restored to defaults")
121
+ }
122
+
123
+ func openConfiguration() {
124
+ ensureConfigFile()
125
+ NSWorkspace.shared.open(configURL)
126
+ }
127
+
128
+ func match(for event: MouseShortcutTriggerEvent) -> MouseShortcutMatchResult? {
129
+ stateLock.lock()
130
+ let rules = snapshot.rules.filter(\.enabled)
131
+ stateLock.unlock()
132
+ for rule in rules {
133
+ guard rule.trigger.kind == event.kind,
134
+ rule.trigger.button == event.button,
135
+ rule.device.matches(event.device) else {
136
+ continue
137
+ }
138
+ switch event.kind {
139
+ case .drag:
140
+ guard rule.trigger.direction == event.direction else { continue }
141
+ case .shape:
142
+ guard rule.trigger.shape == event.shape else { continue }
143
+ case .click:
144
+ break
145
+ }
146
+
147
+ return MouseShortcutMatchResult(
148
+ rule: rule,
149
+ action: rule.action,
150
+ triggerName: rule.trigger.triggerName
151
+ )
152
+ }
153
+
154
+ return nil
155
+ }
156
+
157
+ private func write(config: MouseShortcutConfig) {
158
+ let encoder = JSONEncoder()
159
+ encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]
160
+ guard let data = try? encoder.encode(config) else { return }
161
+ try? data.write(to: configURL, options: .atomic)
162
+ let newDate = modifiedDate()
163
+ stateLock.lock(); lastLoadedModifiedDate = newDate; stateLock.unlock()
164
+ }
165
+
166
+ private func modifiedDate() -> Date? {
167
+ let attrs = try? FileManager.default.attributesOfItem(atPath: configURL.path)
168
+ return attrs?[.modificationDate] as? Date
169
+ }
170
+ }
@@ -0,0 +1,39 @@
1
+ import Carbon
2
+ import Foundation
3
+
4
+ final class SecureEventInputMonitor {
5
+ static let shared = SecureEventInputMonitor()
6
+
7
+ private var timer: Timer?
8
+ private var lastEnabled = IsSecureEventInputEnabled()
9
+
10
+ private init() {}
11
+
12
+ func start() {
13
+ dispatchPrecondition(condition: .onQueue(.main))
14
+ guard timer == nil else { return }
15
+
16
+ lastEnabled = IsSecureEventInputEnabled()
17
+ let timer = Timer(timeInterval: 0.25, repeats: true) { [weak self] _ in
18
+ self?.poll()
19
+ }
20
+ self.timer = timer
21
+ RunLoop.main.add(timer, forMode: .common)
22
+ }
23
+
24
+ func stop() {
25
+ dispatchPrecondition(condition: .onQueue(.main))
26
+ timer?.invalidate()
27
+ timer = nil
28
+ }
29
+
30
+ private func poll() {
31
+ let enabled = IsSecureEventInputEnabled()
32
+ guard enabled != lastEnabled else { return }
33
+
34
+ lastEnabled = enabled
35
+ let reason = enabled ? "Secure Event Input enabled" : "Secure Event Input disabled"
36
+ DiagnosticLog.shared.warn("InputCapture: \(reason)")
37
+ InputCaptureResetCenter.reset(reason: reason)
38
+ }
39
+ }