@lattices/cli 0.4.9 → 0.4.11

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/DesktopModel.swift +1 -0
  31. package/{app → apps/mac}/Sources/Core/Desktop/OcrModel.swift +17 -13
  32. package/apps/mac/Sources/Core/Desktop/WindowCapture.swift +33 -0
  33. package/{app → apps/mac}/Sources/Core/Desktop/WindowDragSnapController.swift +18 -217
  34. package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewStore.swift +4 -5
  35. package/{app → apps/mac}/Sources/Core/Desktop/WindowTiler.swift +19 -13
  36. package/apps/mac/Sources/Core/Input/EventTapBreaker.swift +124 -0
  37. package/apps/mac/Sources/Core/Input/EventTapThread.swift +54 -0
  38. package/apps/mac/Sources/Core/Input/InputCaptureResetCenter.swift +20 -0
  39. package/apps/mac/Sources/Core/Input/KeyboardRemapController.swift +335 -0
  40. package/apps/mac/Sources/Core/Input/KeyboardRemapStore.swift +141 -0
  41. package/{app → apps/mac}/Sources/Core/Input/MouseGestureConfig.swift +155 -20
  42. package/apps/mac/Sources/Core/Input/MouseGestureController.swift +2259 -0
  43. package/apps/mac/Sources/Core/Input/MouseShortcutStore.swift +170 -0
  44. package/apps/mac/Sources/Core/Input/SecureEventInputMonitor.swift +39 -0
  45. package/apps/mac/Sources/Core/Input/ShapeRecognizer.swift +624 -0
  46. package/apps/mac/Sources/Core/Input/TapBudgetMeter.swift +56 -0
  47. package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapState.swift +46 -27
  48. package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapView.swift +580 -162
  49. package/apps/mac/Sources/Core/Overlays/ScreenOverlayCanvasController.swift +1240 -0
  50. package/{app → apps/mac}/Sources/Core/Overlays/Voice/VoiceCommandWindow.swift +11 -23
  51. package/{app → apps/mac}/Sources/Core/Pi/PiChatDock.swift +90 -43
  52. package/{app → apps/mac}/Sources/Core/Pi/PiChatSession.swift +676 -43
  53. package/{app → apps/mac}/Sources/Core/Pi/PiProviderSetupCallout.swift +5 -5
  54. package/{app → apps/mac}/Sources/Core/Pi/PiWorkspaceView.swift +93 -44
  55. package/apps/mac/Sources/Core/System/Capability.swift +79 -0
  56. package/{app → apps/mac}/Sources/Core/System/PermissionChecker.swift +43 -8
  57. package/{app → apps/mac}/Sources/Core/Voice/AudioProvider.swift +225 -56
  58. package/bin/handsoff-infer.ts +14 -5
  59. package/bin/handsoff-worker.ts +11 -7
  60. package/bin/infer.ts +406 -0
  61. package/bin/lattices-app.ts +57 -7
  62. package/bin/lattices-dev +40 -1
  63. package/bin/lattices.ts +1 -1
  64. package/docs/agent-execution-plan.md +9 -9
  65. package/docs/api.md +119 -0
  66. package/docs/app.md +1 -0
  67. package/docs/companion-deck.md +1 -1
  68. package/docs/gesture-customization-proposal.md +520 -0
  69. package/docs/mouse-gestures.md +79 -0
  70. package/docs/overview.md +2 -2
  71. package/docs/presentation-execution-review.md +9 -9
  72. package/docs/proposals/LAT-001-gesture-visual-customization.md +522 -0
  73. package/docs/proposals/LAT-002-shared-overlay-canvas.md +353 -0
  74. package/docs/proposals/LAT-003-menu-bar-controller-architecture.md +291 -0
  75. package/docs/proposals/LAT-004-interactive-overlay-actors.md +534 -0
  76. package/docs/reference/dewey.config.ts +74 -0
  77. package/docs/reference/install-agent.md +79 -0
  78. package/docs/repo-structure.md +100 -0
  79. package/docs/voice-error-model.md +7 -7
  80. package/docs/voice.md +18 -0
  81. package/package.json +23 -13
  82. package/swift/Package.swift +20 -0
  83. package/swift/Sources/DeckKit/DeckAction.swift +51 -0
  84. package/swift/Sources/DeckKit/DeckBridgeSecurity.swift +152 -0
  85. package/swift/Sources/DeckKit/DeckCockpit.swift +82 -0
  86. package/swift/Sources/DeckKit/DeckHost.swift +7 -0
  87. package/swift/Sources/DeckKit/DeckManifest.swift +145 -0
  88. package/swift/Sources/DeckKit/DeckRuntimeSnapshot.swift +533 -0
  89. package/swift/Sources/DeckKit/DeckTrackpad.swift +63 -0
  90. package/swift/Sources/DeckKit/DeckValue.swift +93 -0
  91. package/swift/Sources/DeckKit/DeckVoiceError.swift +88 -0
  92. package/swift/Tests/DeckKitTests/DeckKitTests.swift +286 -0
  93. package/app/Sources/AppShell/AppDelegate.swift +0 -408
  94. package/app/Sources/Core/Input/KeyboardRemapController.swift +0 -184
  95. package/app/Sources/Core/Input/KeyboardRemapStore.swift +0 -84
  96. package/app/Sources/Core/Input/MouseGestureController.swift +0 -1203
  97. package/app/Sources/Core/Input/MouseShortcutStore.swift +0 -107
  98. /package/{app → apps/mac}/Info.plist +0 -0
  99. /package/{app → apps/mac}/Lattices.app/Contents/Resources/AppIcon.icns +0 -0
  100. /package/{app → apps/mac}/Lattices.app/Contents/Resources/tap.wav +0 -0
  101. /package/{app → apps/mac}/Lattices.app/Contents/_CodeSignature/CodeResources +0 -0
  102. /package/{app → apps/mac}/Lattices.entitlements +0 -0
  103. /package/{app → apps/mac}/Resources/tap.wav +0 -0
  104. /package/{app → apps/mac}/Sources/AppShell/App.swift +0 -0
  105. /package/{app → apps/mac}/Sources/AppShell/CliActionLauncher.swift +0 -0
  106. /package/{app → apps/mac}/Sources/AppShell/HomeDashboardView.swift +0 -0
  107. /package/{app → apps/mac}/Sources/AppShell/KeyRecorderView.swift +0 -0
  108. /package/{app → apps/mac}/Sources/AppShell/MainWindow.swift +0 -0
  109. /package/{app → apps/mac}/Sources/Core/Actions/HotkeyManager.swift +0 -0
  110. /package/{app → apps/mac}/Sources/Core/Actions/IntentSchema.swift +0 -0
  111. /package/{app → apps/mac}/Sources/Core/Actions/Intents/CreateLayerIntent.swift +0 -0
  112. /package/{app → apps/mac}/Sources/Core/Actions/Intents/DistributeIntent.swift +0 -0
  113. /package/{app → apps/mac}/Sources/Core/Actions/Intents/FocusIntent.swift +0 -0
  114. /package/{app → apps/mac}/Sources/Core/Actions/Intents/HelpIntent.swift +0 -0
  115. /package/{app → apps/mac}/Sources/Core/Actions/Intents/KillIntent.swift +0 -0
  116. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LatticeIntent.swift +0 -0
  117. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LaunchIntent.swift +0 -0
  118. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListSessionsIntent.swift +0 -0
  119. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListWindowsIntent.swift +0 -0
  120. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ScanIntent.swift +0 -0
  121. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SearchIntent.swift +0 -0
  122. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SwitchLayerIntent.swift +0 -0
  123. /package/{app → apps/mac}/Sources/Core/Actions/Intents/TileIntent.swift +0 -0
  124. /package/{app → apps/mac}/Sources/Core/Actions/PaletteCommand.swift +0 -0
  125. /package/{app → apps/mac}/Sources/Core/Actions/VoiceIntentResolver.swift +0 -0
  126. /package/{app → apps/mac}/Sources/Core/Companion/CompanionActivityLog.swift +0 -0
  127. /package/{app → apps/mac}/Sources/Core/Companion/CompanionKeyboardController.swift +0 -0
  128. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +0 -0
  129. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionCockpit.swift +0 -0
  130. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +0 -0
  131. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +0 -0
  132. /package/{app → apps/mac}/Sources/Core/Companion/LatticesDeckHost.swift +0 -0
  133. /package/{app → apps/mac}/Sources/Core/Daemon/DaemonProtocol.swift +0 -0
  134. /package/{app → apps/mac}/Sources/Core/Desktop/AccessibilityTextExtractor.swift +0 -0
  135. /package/{app → apps/mac}/Sources/Core/Desktop/AppTypeClassifier.swift +0 -0
  136. /package/{app → apps/mac}/Sources/Core/Desktop/DesktopModelTypes.swift +0 -0
  137. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryManager.swift +0 -0
  138. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryPath.swift +0 -0
  139. /package/{app → apps/mac}/Sources/Core/Desktop/MouseFinder.swift +0 -0
  140. /package/{app → apps/mac}/Sources/Core/Desktop/OcrStore.swift +0 -0
  141. /package/{app → apps/mac}/Sources/Core/Desktop/PlacementSpec.swift +0 -0
  142. /package/{app → apps/mac}/Sources/Core/Desktop/SessionWindowLocator.swift +0 -0
  143. /package/{app → apps/mac}/Sources/Core/Desktop/TilePickerView.swift +0 -0
  144. /package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewCard.swift +0 -0
  145. /package/{app → apps/mac}/Sources/Core/Desktop/WindowSelectionStore.swift +0 -0
  146. /package/{app → apps/mac}/Sources/Core/Input/KeyboardRemapConfig.swift +0 -0
  147. /package/{app → apps/mac}/Sources/Core/Input/MouseInputDeviceStore.swift +0 -0
  148. /package/{app → apps/mac}/Sources/Core/Input/MouseInputEventViewer.swift +0 -0
  149. /package/{app → apps/mac}/Sources/Core/Overlays/AppWindowShell.swift +0 -0
  150. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeState.swift +0 -0
  151. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeView.swift +0 -0
  152. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeWindow.swift +0 -0
  153. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteView.swift +0 -0
  154. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteWindow.swift +0 -0
  155. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/CheatSheetHUD.swift +0 -0
  156. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDBottomBar.swift +0 -0
  157. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDController.swift +0 -0
  158. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDLeftBar.swift +0 -0
  159. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDMinimap.swift +0 -0
  160. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDRightBar.swift +0 -0
  161. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDState.swift +0 -0
  162. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDTopBar.swift +0 -0
  163. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LauncherHUD.swift +0 -0
  164. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LayerBezel.swift +0 -0
  165. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchState.swift +0 -0
  166. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchView.swift +0 -0
  167. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchWindow.swift +0 -0
  168. /package/{app → apps/mac}/Sources/Core/Overlays/OverlayPanelShell.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
@@ -6,10 +6,21 @@ enum MouseGestureDirection: String, CaseIterable, Codable, Equatable {
6
6
  case right
7
7
  case up
8
8
  case down
9
+
10
+ var displayLabel: String {
11
+ switch self {
12
+ case .left: return "Left"
13
+ case .right: return "Right"
14
+ case .up: return "Up"
15
+ case .down: return "Down"
16
+ }
17
+ }
9
18
  }
10
19
 
11
20
  enum MouseShortcutTriggerKind: String, Codable, Equatable {
12
21
  case drag
22
+ case click
23
+ case shape
13
24
  }
14
25
 
15
26
  enum MouseShortcutActionType: String, Codable, Equatable {
@@ -18,6 +29,7 @@ enum MouseShortcutActionType: String, Codable, Equatable {
18
29
  case screenMapToggle = "screenmap.toggle"
19
30
  case dictationStart = "dictation.start"
20
31
  case shortcutSend = "shortcut.send"
32
+ case appActivate = "app.activate"
21
33
  }
22
34
 
23
35
  enum MouseShortcutModifier: String, CaseIterable, Codable, Equatable {
@@ -46,6 +58,7 @@ enum MouseShortcutModifier: String, CaseIterable, Codable, Equatable {
46
58
  }
47
59
 
48
60
  enum MouseShortcutButton: Hashable, Codable, Equatable {
61
+ case right
49
62
  case middle
50
63
  case button4
51
64
  case button5
@@ -53,6 +66,7 @@ enum MouseShortcutButton: Hashable, Codable, Equatable {
53
66
 
54
67
  init(rawButtonNumber: Int) {
55
68
  switch rawButtonNumber {
69
+ case 1: self = .right
56
70
  case 2: self = .middle
57
71
  case 3: self = .button4
58
72
  case 4: self = .button5
@@ -69,11 +83,13 @@ enum MouseShortcutButton: Hashable, Codable, Equatable {
69
83
 
70
84
  let stringValue = try container.decode(String.self)
71
85
  switch stringValue.lowercased() {
86
+ case "right", "button.right":
87
+ self = .right
72
88
  case "middle", "button.middle":
73
89
  self = .middle
74
- case "button4", "button.button4":
90
+ case "back", "button.back", "button4", "button.button4":
75
91
  self = .button4
76
- case "button5", "button.button5":
92
+ case "forward", "button.forward", "button5", "button.button5":
77
93
  self = .button5
78
94
  default:
79
95
  if let raw = Int(stringValue.filter(\.isNumber)) {
@@ -91,6 +107,7 @@ enum MouseShortcutButton: Hashable, Codable, Equatable {
91
107
 
92
108
  var rawButtonNumber: Int {
93
109
  switch self {
110
+ case .right: return 1
94
111
  case .middle: return 2
95
112
  case .button4: return 3
96
113
  case .button5: return 4
@@ -100,27 +117,30 @@ enum MouseShortcutButton: Hashable, Codable, Equatable {
100
117
 
101
118
  var configValue: String {
102
119
  switch self {
120
+ case .right: return "right"
103
121
  case .middle: return "middle"
104
- case .button4: return "button4"
105
- case .button5: return "button5"
122
+ case .button4: return "back"
123
+ case .button5: return "forward"
106
124
  case .number(let value): return "button\(value)"
107
125
  }
108
126
  }
109
127
 
110
128
  var displayLabel: String {
111
129
  switch self {
130
+ case .right: return "Right Click"
112
131
  case .middle: return "Middle Click"
113
- case .button4: return "Button 4"
114
- case .button5: return "Button 5"
132
+ case .button4: return "Back Button"
133
+ case .button5: return "Forward Button"
115
134
  case .number(let value): return "Button \(value)"
116
135
  }
117
136
  }
118
137
 
119
138
  var triggerToken: String {
120
139
  switch self {
140
+ case .right: return "button.right"
121
141
  case .middle: return "button.middle"
122
- case .button4: return "button.button4"
123
- case .button5: return "button.button5"
142
+ case .button4: return "button.back"
143
+ case .button5: return "button.forward"
124
144
  case .number(let value): return "button.\(value)"
125
145
  }
126
146
  }
@@ -226,10 +246,37 @@ struct MouseShortcutDeviceSelector: Codable, Equatable {
226
246
  struct MouseShortcutTrigger: Codable, Equatable {
227
247
  var button: MouseShortcutButton
228
248
  var kind: MouseShortcutTriggerKind
229
- var direction: MouseGestureDirection
249
+ var direction: MouseGestureDirection?
250
+ var shape: GestureShapeLabel?
230
251
 
231
252
  var triggerName: String {
232
- "\(button.triggerToken).\(kind.rawValue).\(direction.rawValue)"
253
+ let detail: String?
254
+ switch kind {
255
+ case .drag:
256
+ detail = direction?.rawValue
257
+ case .shape:
258
+ detail = shape?.rawValue
259
+ case .click:
260
+ detail = nil
261
+ }
262
+ return ([button.triggerToken, kind.rawValue] + [detail].compactMap { $0 }).joined(separator: ".")
263
+ }
264
+
265
+ var displayLabel: String {
266
+ switch kind {
267
+ case .click:
268
+ return "\(button.displayLabel) click"
269
+ case .drag:
270
+ if let direction {
271
+ return "\(button.displayLabel) drag \(direction.displayLabel.lowercased())"
272
+ }
273
+ return "\(button.displayLabel) drag"
274
+ case .shape:
275
+ if let shape {
276
+ return "\(button.displayLabel) \(shape.displayName)"
277
+ }
278
+ return "\(button.displayLabel) shape"
279
+ }
233
280
  }
234
281
  }
235
282
 
@@ -248,6 +295,13 @@ struct MouseShortcutKeyStroke: Codable, Equatable {
248
295
  struct MouseShortcutActionDefinition: Codable, Equatable {
249
296
  var type: MouseShortcutActionType
250
297
  var shortcut: MouseShortcutKeyStroke?
298
+ var app: String?
299
+
300
+ init(type: MouseShortcutActionType, shortcut: MouseShortcutKeyStroke? = nil, app: String? = nil) {
301
+ self.type = type
302
+ self.shortcut = shortcut
303
+ self.app = app
304
+ }
251
305
 
252
306
  var label: String {
253
307
  switch type {
@@ -261,16 +315,82 @@ struct MouseShortcutActionDefinition: Codable, Equatable {
261
315
  return "Dictation"
262
316
  case .shortcutSend:
263
317
  return shortcut?.displayLabel ?? "Send Shortcut"
318
+ case .appActivate:
319
+ return app.map { "Activate \($0)" } ?? "Activate App"
264
320
  }
265
321
  }
266
322
  }
267
323
 
324
+ struct MouseShortcutVisualDefinition: Codable, Equatable {
325
+ var renderer: String
326
+ var theme: String?
327
+ var asset: String?
328
+ var character: String?
329
+ var markers: [String: String]?
330
+ var events: [String: String]?
331
+
332
+ init(
333
+ renderer: String = "native",
334
+ theme: String? = nil,
335
+ asset: String? = nil,
336
+ character: String? = nil,
337
+ markers: [String: String]? = nil,
338
+ events: [String: String]? = nil
339
+ ) {
340
+ self.renderer = renderer
341
+ self.theme = theme
342
+ self.asset = asset
343
+ self.character = character
344
+ self.markers = markers
345
+ self.events = events
346
+ }
347
+
348
+ var isLottiePOC: Bool {
349
+ renderer.localizedCaseInsensitiveCompare("lottie") == .orderedSame
350
+ }
351
+
352
+ func marker(phase: String, shape: GestureShapeLabel?, success: Bool?) -> String? {
353
+ let keys: [String] = [
354
+ success.map { "\(phase).\($0 ? "success" : "failure")" },
355
+ shape.map { "recognized:\($0.rawValue)" },
356
+ phase,
357
+ ].compactMap { $0 }
358
+
359
+ for key in keys {
360
+ if let marker = markers?[key] {
361
+ return marker
362
+ }
363
+ if let marker = events?[key] {
364
+ return marker
365
+ }
366
+ }
367
+ return nil
368
+ }
369
+ }
370
+
268
371
  struct MouseShortcutRule: Codable, Equatable, Identifiable {
269
372
  var id: String
270
373
  var enabled: Bool
271
374
  var device: MouseShortcutDeviceSelector
272
375
  var trigger: MouseShortcutTrigger
273
376
  var action: MouseShortcutActionDefinition
377
+ var visual: MouseShortcutVisualDefinition?
378
+
379
+ init(
380
+ id: String,
381
+ enabled: Bool,
382
+ device: MouseShortcutDeviceSelector,
383
+ trigger: MouseShortcutTrigger,
384
+ action: MouseShortcutActionDefinition,
385
+ visual: MouseShortcutVisualDefinition? = nil
386
+ ) {
387
+ self.id = id
388
+ self.enabled = enabled
389
+ self.device = device
390
+ self.trigger = trigger
391
+ self.action = action
392
+ self.visual = visual
393
+ }
274
394
 
275
395
  var summary: String {
276
396
  "\(trigger.triggerName) -> \(action.type.rawValue)"
@@ -302,29 +422,29 @@ struct MouseShortcutConfig: Codable, Equatable {
302
422
  id: "space-previous",
303
423
  enabled: true,
304
424
  device: .any,
305
- trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .left),
306
- action: MouseShortcutActionDefinition(type: .spacePrevious, shortcut: nil)
425
+ trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .left, shape: nil),
426
+ action: MouseShortcutActionDefinition(type: .spacePrevious)
307
427
  ),
308
428
  MouseShortcutRule(
309
429
  id: "space-next",
310
430
  enabled: true,
311
431
  device: .any,
312
- trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .right),
313
- action: MouseShortcutActionDefinition(type: .spaceNext, shortcut: nil)
432
+ trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .right, shape: nil),
433
+ action: MouseShortcutActionDefinition(type: .spaceNext)
314
434
  ),
315
435
  MouseShortcutRule(
316
436
  id: "screenmap-overview",
317
437
  enabled: true,
318
438
  device: .any,
319
- trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .down),
320
- action: MouseShortcutActionDefinition(type: .screenMapToggle, shortcut: nil)
439
+ trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .down, shape: nil),
440
+ action: MouseShortcutActionDefinition(type: .screenMapToggle)
321
441
  ),
322
442
  MouseShortcutRule(
323
443
  id: "dictation",
324
444
  enabled: true,
325
445
  device: .any,
326
- trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .up),
327
- action: MouseShortcutActionDefinition(type: .dictationStart, shortcut: nil)
446
+ trigger: MouseShortcutTrigger(button: .middle, kind: .drag, direction: .up, shape: nil),
447
+ action: MouseShortcutActionDefinition(type: .dictationStart)
328
448
  ),
329
449
  ]
330
450
  )
@@ -339,11 +459,26 @@ struct MouseShortcutMatchResult {
339
459
  struct MouseShortcutTriggerEvent {
340
460
  let button: MouseShortcutButton
341
461
  let kind: MouseShortcutTriggerKind
342
- let direction: MouseGestureDirection
462
+ let direction: MouseGestureDirection?
463
+ let shape: GestureShapeLabel?
343
464
  let device: MouseInputDeviceInfo?
344
465
 
466
+ init(
467
+ button: MouseShortcutButton,
468
+ kind: MouseShortcutTriggerKind,
469
+ direction: MouseGestureDirection? = nil,
470
+ shape: GestureShapeLabel? = nil,
471
+ device: MouseInputDeviceInfo? = nil
472
+ ) {
473
+ self.button = button
474
+ self.kind = kind
475
+ self.direction = direction
476
+ self.shape = shape
477
+ self.device = device
478
+ }
479
+
345
480
  var triggerName: String {
346
- MouseShortcutTrigger(button: button, kind: kind, direction: direction).triggerName
481
+ MouseShortcutTrigger(button: button, kind: kind, direction: direction, shape: shape).triggerName
347
482
  }
348
483
  }
349
484