@lattices/cli 0.4.14 → 0.5.0

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 (180) hide show
  1. package/README.md +5 -7
  2. package/apps/mac/Info.plist +2 -2
  3. package/apps/mac/Lattices.app/Contents/Info.plist +4 -12
  4. package/apps/mac/Lattices.app/Contents/MacOS/Lattices +0 -0
  5. package/bin/lattices-app.ts +110 -17
  6. package/bin/lattices-build +125 -0
  7. package/bin/lattices-dev +89 -16
  8. package/bin/lattices.ts +977 -16
  9. package/docs/agents.md +81 -4
  10. package/docs/ai-chat-ux-review.md +416 -0
  11. package/docs/api.md +135 -3
  12. package/docs/app.md +30 -8
  13. package/docs/config.md +4 -0
  14. package/docs/mouse-gestures.md +60 -1
  15. package/docs/proposals/LAT-004-interactive-overlay-actors.md +1 -1
  16. package/docs/proposals/LAT-005-action-runtime-product-spine.md +914 -0
  17. package/docs/proposals/LAT-006-mira-in-lattices.md +553 -0
  18. package/docs/reference/dewey.config.ts +2 -2
  19. package/docs/release.md +171 -0
  20. package/docs/repo-structure.md +4 -5
  21. package/docs/voice.md +11 -27
  22. package/package.json +9 -10
  23. package/apps/mac/Package.swift +0 -27
  24. package/apps/mac/Sources/AppShell/App.swift +0 -26
  25. package/apps/mac/Sources/AppShell/AppActivationCoordinator.swift +0 -27
  26. package/apps/mac/Sources/AppShell/AppDelegate.swift +0 -189
  27. package/apps/mac/Sources/AppShell/AppServicesBootstrap.swift +0 -25
  28. package/apps/mac/Sources/AppShell/AppShellView.swift +0 -171
  29. package/apps/mac/Sources/AppShell/AppUpdater.swift +0 -305
  30. package/apps/mac/Sources/AppShell/CliActionLauncher.swift +0 -50
  31. package/apps/mac/Sources/AppShell/HomeDashboardView.swift +0 -133
  32. package/apps/mac/Sources/AppShell/HotkeyBootstrap.swift +0 -87
  33. package/apps/mac/Sources/AppShell/KeyRecorderView.swift +0 -210
  34. package/apps/mac/Sources/AppShell/LatticesRuntime.swift +0 -104
  35. package/apps/mac/Sources/AppShell/MainView.swift +0 -847
  36. package/apps/mac/Sources/AppShell/MainWindow.swift +0 -83
  37. package/apps/mac/Sources/AppShell/MenuBarController.swift +0 -177
  38. package/apps/mac/Sources/AppShell/OnboardingView.swift +0 -483
  39. package/apps/mac/Sources/AppShell/PermissionsAssistantView.swift +0 -366
  40. package/apps/mac/Sources/AppShell/PermissionsAssistantWindow.swift +0 -70
  41. package/apps/mac/Sources/AppShell/Preferences.swift +0 -297
  42. package/apps/mac/Sources/AppShell/SettingsView.swift +0 -3163
  43. package/apps/mac/Sources/AppShell/SettingsWindow.swift +0 -34
  44. package/apps/mac/Sources/AppShell/WorkspaceInspectorPresenter.swift +0 -13
  45. package/apps/mac/Sources/Core/Actions/HotkeyManager.swift +0 -256
  46. package/apps/mac/Sources/Core/Actions/HotkeyStore.swift +0 -399
  47. package/apps/mac/Sources/Core/Actions/IntentEngine.swift +0 -988
  48. package/apps/mac/Sources/Core/Actions/IntentSchema.swift +0 -94
  49. package/apps/mac/Sources/Core/Actions/Intents/CreateLayerIntent.swift +0 -54
  50. package/apps/mac/Sources/Core/Actions/Intents/DistributeIntent.swift +0 -56
  51. package/apps/mac/Sources/Core/Actions/Intents/FocusIntent.swift +0 -69
  52. package/apps/mac/Sources/Core/Actions/Intents/HelpIntent.swift +0 -41
  53. package/apps/mac/Sources/Core/Actions/Intents/KillIntent.swift +0 -47
  54. package/apps/mac/Sources/Core/Actions/Intents/LatticeIntent.swift +0 -53
  55. package/apps/mac/Sources/Core/Actions/Intents/LaunchIntent.swift +0 -67
  56. package/apps/mac/Sources/Core/Actions/Intents/ListSessionsIntent.swift +0 -32
  57. package/apps/mac/Sources/Core/Actions/Intents/ListWindowsIntent.swift +0 -30
  58. package/apps/mac/Sources/Core/Actions/Intents/ScanIntent.swift +0 -52
  59. package/apps/mac/Sources/Core/Actions/Intents/SearchIntent.swift +0 -190
  60. package/apps/mac/Sources/Core/Actions/Intents/SwitchLayerIntent.swift +0 -50
  61. package/apps/mac/Sources/Core/Actions/Intents/TileIntent.swift +0 -61
  62. package/apps/mac/Sources/Core/Actions/PaletteCommand.swift +0 -439
  63. package/apps/mac/Sources/Core/Actions/VoiceIntentResolver.swift +0 -713
  64. package/apps/mac/Sources/Core/Companion/CompanionActivityLog.swift +0 -70
  65. package/apps/mac/Sources/Core/Companion/CompanionKeyboardController.swift +0 -141
  66. package/apps/mac/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +0 -454
  67. package/apps/mac/Sources/Core/Companion/LatticesCompanionCockpit.swift +0 -555
  68. package/apps/mac/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +0 -629
  69. package/apps/mac/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +0 -204
  70. package/apps/mac/Sources/Core/Companion/LatticesDeckHost.swift +0 -1463
  71. package/apps/mac/Sources/Core/Daemon/DaemonProtocol.swift +0 -114
  72. package/apps/mac/Sources/Core/Daemon/DaemonServer.swift +0 -427
  73. package/apps/mac/Sources/Core/Daemon/LatticesApi.swift +0 -2965
  74. package/apps/mac/Sources/Core/Desktop/AccessibilityTextExtractor.swift +0 -111
  75. package/apps/mac/Sources/Core/Desktop/AppTypeClassifier.swift +0 -106
  76. package/apps/mac/Sources/Core/Desktop/DesktopModel.swift +0 -331
  77. package/apps/mac/Sources/Core/Desktop/DesktopModelTypes.swift +0 -73
  78. package/apps/mac/Sources/Core/Desktop/InventoryManager.swift +0 -35
  79. package/apps/mac/Sources/Core/Desktop/InventoryPath.swift +0 -43
  80. package/apps/mac/Sources/Core/Desktop/MouseFinder.swift +0 -527
  81. package/apps/mac/Sources/Core/Desktop/OcrModel.swift +0 -467
  82. package/apps/mac/Sources/Core/Desktop/OcrStore.swift +0 -329
  83. package/apps/mac/Sources/Core/Desktop/PlacementSpec.swift +0 -195
  84. package/apps/mac/Sources/Core/Desktop/SessionWindowLocator.swift +0 -139
  85. package/apps/mac/Sources/Core/Desktop/TilePickerView.swift +0 -209
  86. package/apps/mac/Sources/Core/Desktop/WindowCapture.swift +0 -33
  87. package/apps/mac/Sources/Core/Desktop/WindowDragSnapController.swift +0 -429
  88. package/apps/mac/Sources/Core/Desktop/WindowPreviewCard.swift +0 -100
  89. package/apps/mac/Sources/Core/Desktop/WindowPreviewStore.swift +0 -112
  90. package/apps/mac/Sources/Core/Desktop/WindowSelectionStore.swift +0 -76
  91. package/apps/mac/Sources/Core/Desktop/WindowTiler.swift +0 -2222
  92. package/apps/mac/Sources/Core/Input/EventTapBreaker.swift +0 -124
  93. package/apps/mac/Sources/Core/Input/EventTapThread.swift +0 -54
  94. package/apps/mac/Sources/Core/Input/InputCaptureResetCenter.swift +0 -20
  95. package/apps/mac/Sources/Core/Input/KeyboardRemapConfig.swift +0 -69
  96. package/apps/mac/Sources/Core/Input/KeyboardRemapController.swift +0 -346
  97. package/apps/mac/Sources/Core/Input/KeyboardRemapStore.swift +0 -141
  98. package/apps/mac/Sources/Core/Input/MouseGestureConfig.swift +0 -499
  99. package/apps/mac/Sources/Core/Input/MouseGestureController.swift +0 -2583
  100. package/apps/mac/Sources/Core/Input/MouseInputDeviceStore.swift +0 -98
  101. package/apps/mac/Sources/Core/Input/MouseInputEventViewer.swift +0 -272
  102. package/apps/mac/Sources/Core/Input/MouseShortcutStore.swift +0 -170
  103. package/apps/mac/Sources/Core/Input/SecureEventInputMonitor.swift +0 -39
  104. package/apps/mac/Sources/Core/Input/ShapeRecognizer.swift +0 -624
  105. package/apps/mac/Sources/Core/Input/TapBudgetMeter.swift +0 -56
  106. package/apps/mac/Sources/Core/Overlays/AppWindowShell.swift +0 -63
  107. package/apps/mac/Sources/Core/Overlays/CommandMode/CommandModeState.swift +0 -1566
  108. package/apps/mac/Sources/Core/Overlays/CommandMode/CommandModeView.swift +0 -1927
  109. package/apps/mac/Sources/Core/Overlays/CommandMode/CommandModeWindow.swift +0 -196
  110. package/apps/mac/Sources/Core/Overlays/CommandPalette/CommandPaletteView.swift +0 -307
  111. package/apps/mac/Sources/Core/Overlays/CommandPalette/CommandPaletteWindow.swift +0 -67
  112. package/apps/mac/Sources/Core/Overlays/HUD/CheatSheetHUD.swift +0 -576
  113. package/apps/mac/Sources/Core/Overlays/HUD/HUDBottomBar.swift +0 -279
  114. package/apps/mac/Sources/Core/Overlays/HUD/HUDController.swift +0 -1158
  115. package/apps/mac/Sources/Core/Overlays/HUD/HUDLeftBar.swift +0 -849
  116. package/apps/mac/Sources/Core/Overlays/HUD/HUDMinimap.swift +0 -179
  117. package/apps/mac/Sources/Core/Overlays/HUD/HUDRightBar.swift +0 -596
  118. package/apps/mac/Sources/Core/Overlays/HUD/HUDState.swift +0 -367
  119. package/apps/mac/Sources/Core/Overlays/HUD/HUDTopBar.swift +0 -243
  120. package/apps/mac/Sources/Core/Overlays/HUD/LauncherHUD.swift +0 -334
  121. package/apps/mac/Sources/Core/Overlays/HUD/LayerBezel.swift +0 -203
  122. package/apps/mac/Sources/Core/Overlays/OmniSearch/OmniSearchState.swift +0 -280
  123. package/apps/mac/Sources/Core/Overlays/OmniSearch/OmniSearchView.swift +0 -422
  124. package/apps/mac/Sources/Core/Overlays/OmniSearch/OmniSearchWindow.swift +0 -94
  125. package/apps/mac/Sources/Core/Overlays/OverlayPanelShell.swift +0 -241
  126. package/apps/mac/Sources/Core/Overlays/ScreenMap/ScreenMapState.swift +0 -3135
  127. package/apps/mac/Sources/Core/Overlays/ScreenMap/ScreenMapView.swift +0 -3977
  128. package/apps/mac/Sources/Core/Overlays/ScreenMap/ScreenMapWindowController.swift +0 -119
  129. package/apps/mac/Sources/Core/Overlays/ScreenOverlayCanvasController.swift +0 -1217
  130. package/apps/mac/Sources/Core/Overlays/Voice/VoiceCommandWindow.swift +0 -1575
  131. package/apps/mac/Sources/Core/Pi/PiAuthNextStepCard.swift +0 -148
  132. package/apps/mac/Sources/Core/Pi/PiAuthPromptCard.swift +0 -90
  133. package/apps/mac/Sources/Core/Pi/PiChatDock.swift +0 -564
  134. package/apps/mac/Sources/Core/Pi/PiChatSession.swift +0 -1948
  135. package/apps/mac/Sources/Core/Pi/PiInstallCallout.swift +0 -86
  136. package/apps/mac/Sources/Core/Pi/PiProviderSetupCallout.swift +0 -99
  137. package/apps/mac/Sources/Core/Pi/PiWorkspaceView.swift +0 -510
  138. package/apps/mac/Sources/Core/System/Capability.swift +0 -79
  139. package/apps/mac/Sources/Core/System/DiagnosticLog.swift +0 -373
  140. package/apps/mac/Sources/Core/System/EventBus.swift +0 -31
  141. package/apps/mac/Sources/Core/System/PermissionChecker.swift +0 -224
  142. package/apps/mac/Sources/Core/System/ProcessModel.swift +0 -199
  143. package/apps/mac/Sources/Core/System/ProcessQuery.swift +0 -151
  144. package/apps/mac/Sources/Core/System/SystemTelemetryMonitor.swift +0 -273
  145. package/apps/mac/Sources/Core/Voice/AdvisorLearningStore.swift +0 -90
  146. package/apps/mac/Sources/Core/Voice/AgentSession.swift +0 -377
  147. package/apps/mac/Sources/Core/Voice/AudioProvider.swift +0 -555
  148. package/apps/mac/Sources/Core/Voice/HandsOffSession.swift +0 -839
  149. package/apps/mac/Sources/Core/Voice/VoiceChatView.swift +0 -192
  150. package/apps/mac/Sources/Core/Voice/VoxClient.swift +0 -454
  151. package/apps/mac/Sources/Core/Workspace/Project.swift +0 -28
  152. package/apps/mac/Sources/Core/Workspace/ProjectScanner.swift +0 -141
  153. package/apps/mac/Sources/Core/Workspace/SessionLayerStore.swift +0 -285
  154. package/apps/mac/Sources/Core/Workspace/SessionManager.swift +0 -75
  155. package/apps/mac/Sources/Core/Workspace/Terminal/Terminal.swift +0 -259
  156. package/apps/mac/Sources/Core/Workspace/Terminal/TerminalQuery.swift +0 -156
  157. package/apps/mac/Sources/Core/Workspace/Terminal/TerminalSynthesizer.swift +0 -200
  158. package/apps/mac/Sources/Core/Workspace/Tmux/TmuxModel.swift +0 -60
  159. package/apps/mac/Sources/Core/Workspace/Tmux/TmuxQuery.swift +0 -105
  160. package/apps/mac/Sources/Core/Workspace/WorkspaceManager.swift +0 -1027
  161. package/apps/mac/Sources/UI/ActionRow.swift +0 -78
  162. package/apps/mac/Sources/UI/OrphanRow.swift +0 -129
  163. package/apps/mac/Sources/UI/ProjectRow.swift +0 -368
  164. package/apps/mac/Sources/UI/TabGroupRow.swift +0 -178
  165. package/apps/mac/Sources/UI/Theme.swift +0 -164
  166. package/apps/mac/Tests/StageDragTests.swift +0 -333
  167. package/apps/mac/Tests/StageJoinTests.swift +0 -313
  168. package/apps/mac/Tests/StageManagerTests.swift +0 -280
  169. package/apps/mac/Tests/StageTileTests.swift +0 -353
  170. package/swift/Package.swift +0 -20
  171. package/swift/Sources/DeckKit/DeckAction.swift +0 -51
  172. package/swift/Sources/DeckKit/DeckBridgeSecurity.swift +0 -152
  173. package/swift/Sources/DeckKit/DeckCockpit.swift +0 -82
  174. package/swift/Sources/DeckKit/DeckHost.swift +0 -7
  175. package/swift/Sources/DeckKit/DeckManifest.swift +0 -145
  176. package/swift/Sources/DeckKit/DeckRuntimeSnapshot.swift +0 -533
  177. package/swift/Sources/DeckKit/DeckTrackpad.swift +0 -63
  178. package/swift/Sources/DeckKit/DeckValue.swift +0 -93
  179. package/swift/Sources/DeckKit/DeckVoiceError.swift +0 -88
  180. package/swift/Tests/DeckKitTests/DeckKitTests.swift +0 -286
@@ -1,399 +0,0 @@
1
- import Carbon
2
- import AppKit
3
- import Combine
4
-
5
- // MARK: - HotkeyGroup
6
-
7
- enum HotkeyGroup: String, CaseIterable {
8
- case app
9
- case layers
10
- case tiling
11
- }
12
-
13
- // MARK: - HotkeyAction
14
-
15
- enum HotkeyAction: String, CaseIterable, Codable {
16
- // App
17
- case palette
18
- case screenMap
19
- case bezel
20
- case cheatSheet
21
- case desktopInventory
22
- case omniSearch
23
- case voiceCommand
24
- case handsOff
25
- case unifiedWindow
26
- case hud
27
- case mouseFinder
28
- case overlayActors
29
- // Layers
30
- case layer1, layer2, layer3, layer4, layer5, layer6, layer7, layer8, layer9
31
- case layerNext, layerPrev, layerTag
32
- // Tiling
33
- case tileLeft, tileRight, tileMaximize, tileCenter
34
- case tileTopLeft, tileTopRight, tileBottomLeft, tileBottomRight
35
- case tileTop, tileBottom, tileDistribute, tileTypeGrid, tileOrganize
36
- case tileLeftThird, tileCenterThird, tileRightThird
37
-
38
- var label: String {
39
- switch self {
40
- case .palette: return "Command Palette"
41
- case .screenMap: return "Screen Map"
42
- case .bezel: return "Window Bezel"
43
- case .cheatSheet: return "Cheat Sheet"
44
- case .desktopInventory: return "Window Selector"
45
- case .omniSearch: return "Search"
46
- case .voiceCommand: return "Voice Command"
47
- case .handsOff: return "Hands-Off Mode"
48
- case .unifiedWindow: return "Workspace Home"
49
- case .hud: return "HUD"
50
- case .mouseFinder: return "Find Mouse"
51
- case .overlayActors: return "Toggle Overlay Actors"
52
- case .layer1: return "Layer 1"
53
- case .layer2: return "Layer 2"
54
- case .layer3: return "Layer 3"
55
- case .layer4: return "Layer 4"
56
- case .layer5: return "Layer 5"
57
- case .layer6: return "Layer 6"
58
- case .layer7: return "Layer 7"
59
- case .layer8: return "Layer 8"
60
- case .layer9: return "Layer 9"
61
- case .layerNext: return "Next Layer"
62
- case .layerPrev: return "Previous Layer"
63
- case .layerTag: return "Tag Window"
64
- case .tileLeft: return "Tile Left"
65
- case .tileRight: return "Tile Right"
66
- case .tileMaximize: return "Maximize"
67
- case .tileCenter: return "Center"
68
- case .tileTopLeft: return "Top Left"
69
- case .tileTopRight: return "Top Right"
70
- case .tileBottomLeft: return "Bottom Left"
71
- case .tileBottomRight: return "Bottom Right"
72
- case .tileTop: return "Top Half"
73
- case .tileBottom: return "Bottom Half"
74
- case .tileDistribute: return "Distribute"
75
- case .tileTypeGrid: return "Grid Type"
76
- case .tileOrganize: return "Organize Windows"
77
- case .tileLeftThird: return "Left Third"
78
- case .tileCenterThird: return "Center Third"
79
- case .tileRightThird: return "Right Third"
80
- }
81
- }
82
-
83
- var group: HotkeyGroup {
84
- switch self {
85
- case .palette, .screenMap, .bezel, .cheatSheet, .desktopInventory, .omniSearch, .voiceCommand, .handsOff, .unifiedWindow, .hud, .mouseFinder, .overlayActors: return .app
86
- case .layer1, .layer2, .layer3, .layer4, .layer5,
87
- .layer6, .layer7, .layer8, .layer9,
88
- .layerNext, .layerPrev, .layerTag: return .layers
89
- default: return .tiling
90
- }
91
- }
92
-
93
- var carbonID: UInt32 {
94
- switch self {
95
- case .palette: return 1
96
- case .screenMap: return 200
97
- case .bezel: return 201
98
- case .cheatSheet: return 202
99
- case .desktopInventory: return 203
100
- case .omniSearch: return 204
101
- case .voiceCommand: return 205
102
- case .handsOff: return 206
103
- case .unifiedWindow: return 207
104
- case .hud: return 208
105
- case .mouseFinder: return 209
106
- case .overlayActors: return 210
107
- case .layer1: return 101
108
- case .layer2: return 102
109
- case .layer3: return 103
110
- case .layer4: return 104
111
- case .layer5: return 105
112
- case .layer6: return 106
113
- case .layer7: return 107
114
- case .layer8: return 108
115
- case .layer9: return 109
116
- case .layerNext: return 110
117
- case .layerPrev: return 111
118
- case .layerTag: return 112
119
- case .tileLeft: return 300
120
- case .tileRight: return 301
121
- case .tileMaximize: return 302
122
- case .tileCenter: return 303
123
- case .tileTopLeft: return 304
124
- case .tileTopRight: return 305
125
- case .tileBottomLeft: return 306
126
- case .tileBottomRight: return 307
127
- case .tileTop: return 308
128
- case .tileBottom: return 309
129
- case .tileDistribute: return 310
130
- case .tileTypeGrid: return 314
131
- case .tileLeftThird: return 311
132
- case .tileCenterThird: return 312
133
- case .tileRightThird: return 313
134
- case .tileOrganize: return 315
135
- }
136
- }
137
-
138
- static var layerActions: [HotkeyAction] {
139
- [.layer1, .layer2, .layer3, .layer4, .layer5, .layer6, .layer7, .layer8, .layer9]
140
- }
141
- }
142
-
143
- // MARK: - KeyBinding
144
-
145
- struct KeyBinding: Codable, Equatable {
146
- let keyCode: UInt32
147
- let carbonModifiers: UInt32
148
- var displayParts: [String]
149
-
150
- var compactDisplayParts: [String] {
151
- guard let key = displayParts.last else { return [] }
152
- let modifiers = Set(displayParts.dropLast())
153
- if modifiers == Set(["Ctrl", "Option", "Shift", "Cmd"]) {
154
- return ["Hyper", key]
155
- }
156
- return displayParts
157
- }
158
-
159
- static func carbonModifiers(from flags: NSEvent.ModifierFlags) -> UInt32 {
160
- var mods: UInt32 = 0
161
- if flags.contains(.command) { mods |= UInt32(cmdKey) }
162
- if flags.contains(.shift) { mods |= UInt32(shiftKey) }
163
- if flags.contains(.option) { mods |= UInt32(optionKey) }
164
- if flags.contains(.control) { mods |= UInt32(controlKey) }
165
- return mods
166
- }
167
-
168
- static func displayParts(keyCode: UInt32, carbonModifiers: UInt32) -> [String] {
169
- var parts: [String] = []
170
- if carbonModifiers & UInt32(controlKey) != 0 { parts.append("Ctrl") }
171
- if carbonModifiers & UInt32(optionKey) != 0 { parts.append("Option") }
172
- if carbonModifiers & UInt32(shiftKey) != 0 { parts.append("Shift") }
173
- if carbonModifiers & UInt32(cmdKey) != 0 { parts.append("Cmd") }
174
- parts.append(keyName(for: keyCode))
175
- return parts
176
- }
177
-
178
- static func keyName(for keyCode: UInt32) -> String {
179
- let names: [UInt32: String] = [
180
- 0: "A", 1: "S", 2: "D", 3: "F", 4: "H", 5: "G", 6: "Z", 7: "X",
181
- 8: "C", 9: "V", 11: "B", 12: "Q", 13: "W", 14: "E", 15: "R",
182
- 16: "Y", 17: "T", 18: "1", 19: "2", 20: "3", 21: "4", 22: "6",
183
- 23: "5", 24: "=", 25: "9", 26: "7", 27: "-", 28: "8", 29: "0",
184
- 30: "]", 31: "O", 32: "U", 33: "[", 34: "I", 35: "P",
185
- 36: "Return", 37: "L", 38: "J", 39: "'", 40: "K", 41: ";",
186
- 42: "\\", 43: ",", 44: "/", 45: "N", 46: "M", 47: ".",
187
- 48: "Tab", 49: "Space", 50: "`", 51: "Delete",
188
- 53: "Escape",
189
- 65: ".", // numpad
190
- 67: "*", // numpad
191
- 69: "+", // numpad
192
- 71: "Clear", // numpad
193
- 75: "/", // numpad
194
- 76: "Enter", // numpad
195
- 78: "-", // numpad
196
- 82: "0", 83: "1", 84: "2", 85: "3", 86: "4", // numpad
197
- 87: "5", 88: "6", 89: "7", 91: "8", 92: "9", // numpad
198
- 96: "F5", 97: "F6", 98: "F7", 99: "F3", 100: "F8",
199
- 101: "F9", 103: "F11", 105: "F13", 107: "F14",
200
- 109: "F10", 111: "F12", 113: "F15", 114: "Help",
201
- 115: "Home", 116: "PgUp", 117: "Del", 118: "F4",
202
- 119: "End", 120: "F2", 121: "PgDn", 122: "F1",
203
- 123: "\u{2190}", // left arrow
204
- 124: "\u{2192}", // right arrow
205
- 125: "\u{2193}", // down arrow
206
- 126: "\u{2191}", // up arrow
207
- ]
208
- return names[keyCode] ?? "Key\(keyCode)"
209
- }
210
- }
211
-
212
- // MARK: - HotkeyStore
213
-
214
- class HotkeyStore: ObservableObject {
215
- static let shared = HotkeyStore()
216
-
217
- @Published var bindings: [HotkeyAction: KeyBinding]
218
- private var callbacks: [HotkeyAction: () -> Void] = [:]
219
-
220
- private func instrumentedCallback(for action: HotkeyAction, callback: @escaping () -> Void) -> () -> Void {
221
- {
222
- let timed = DiagnosticLog.shared.startTimed("Hotkey \(action.label)")
223
- callback()
224
- DiagnosticLog.shared.finish(timed)
225
- }
226
- }
227
-
228
- static let defaultBindings: [HotkeyAction: KeyBinding] = {
229
- var d = [HotkeyAction: KeyBinding]()
230
- let hyper = UInt32(cmdKey | controlKey | optionKey | shiftKey)
231
- let cmdShift = UInt32(cmdKey | shiftKey)
232
- let cmdOpt = UInt32(cmdKey | optionKey)
233
- let ctrlOpt = UInt32(controlKey | optionKey)
234
-
235
- func bind(_ action: HotkeyAction, _ keyCode: UInt32, _ mods: UInt32) {
236
- d[action] = KeyBinding(
237
- keyCode: keyCode,
238
- carbonModifiers: mods,
239
- displayParts: KeyBinding.displayParts(keyCode: keyCode, carbonModifiers: mods)
240
- )
241
- }
242
-
243
- // App
244
- bind(.palette, 46, cmdShift) // Cmd+Shift+M
245
- bind(.unifiedWindow, 18, hyper) // Hyper+1 (Workspace Home)
246
- bind(.screenMap, 37, hyper) // Hyper+L (Layout)
247
- bind(.bezel, 19, hyper) // Hyper+2
248
- bind(.hud, 20, hyper) // Hyper+3 (HUD overlay)
249
- bind(.desktopInventory, 5, hyper) // Hyper+G
250
- bind(.voiceCommand, 21, hyper) // Hyper+4 (moved from Hyper+3)
251
- let cmdCtrl = UInt32(cmdKey | controlKey)
252
- bind(.handsOff, 46, cmdCtrl) // Ctrl+Cmd+M
253
- bind(.omniSearch, 23, hyper) // Hyper+5
254
- bind(.cheatSheet, 22, hyper) // Hyper+6
255
- bind(.mouseFinder, 26, hyper) // Hyper+7
256
- bind(.overlayActors, 28, hyper) // Hyper+8
257
-
258
- // Layers: Cmd+Option+1-9
259
- let layerKeyCodes: [UInt32] = [18, 19, 20, 21, 23, 22, 26, 28, 25]
260
- for (i, action) in HotkeyAction.layerActions.enumerated() {
261
- bind(action, layerKeyCodes[i], cmdOpt)
262
- }
263
-
264
- // Layer cycling: Cmd+Option+Arrow / Cmd+Option+T
265
- bind(.layerNext, 124, cmdOpt) // Cmd+Opt+→
266
- bind(.layerPrev, 123, cmdOpt) // Cmd+Opt+←
267
- bind(.layerTag, 17, cmdOpt) // Cmd+Opt+T
268
-
269
- // Tiling: Ctrl+Option for all
270
- bind(.tileLeft, 123, ctrlOpt) // Ctrl+Opt+←
271
- bind(.tileRight, 124, ctrlOpt) // Ctrl+Opt+→
272
- bind(.tileTop, 126, ctrlOpt) // Ctrl+Opt+↑
273
- bind(.tileBottom, 125, ctrlOpt) // Ctrl+Opt+↓
274
- bind(.tileMaximize, 36, ctrlOpt) // Ctrl+Opt+Return
275
- bind(.tileCenter, 8, ctrlOpt) // Ctrl+Opt+C
276
- bind(.tileTopLeft, 32, ctrlOpt) // Ctrl+Opt+U
277
- bind(.tileTopRight, 34, ctrlOpt) // Ctrl+Opt+I
278
- bind(.tileBottomLeft, 38, ctrlOpt) // Ctrl+Opt+J
279
- bind(.tileBottomRight, 40, ctrlOpt) // Ctrl+Opt+K
280
- bind(.tileDistribute, 2, ctrlOpt) // Ctrl+Opt+D
281
- bind(.tileTypeGrid, 5, hyper) // Hyper+G
282
- bind(.tileLeftThird, 18, ctrlOpt) // Ctrl+Opt+1
283
- bind(.tileCenterThird, 19, ctrlOpt) // Ctrl+Opt+2
284
- bind(.tileRightThird, 20, ctrlOpt) // Ctrl+Opt+3
285
- bind(.tileOrganize, 31, ctrlOpt) // Ctrl+Opt+O
286
-
287
- return d
288
- }()
289
-
290
- private init() {
291
- // Start with defaults
292
- var merged = Self.defaultBindings
293
-
294
- // Layer 2: UserDefaults overrides
295
- let ud = UserDefaults.standard
296
- for action in HotkeyAction.allCases {
297
- let key = "hotkey.\(action.rawValue)"
298
- if let data = ud.data(forKey: key),
299
- let binding = try? JSONDecoder().decode(KeyBinding.self, from: data) {
300
- merged[action] = binding
301
- }
302
- }
303
-
304
- // Layer 3: ~/.lattices/hotkeys.json overrides
305
- let jsonPath = NSHomeDirectory() + "/.lattices/hotkeys.json"
306
- if let data = FileManager.default.contents(atPath: jsonPath),
307
- let overrides = try? JSONDecoder().decode([String: KeyBinding].self, from: data) {
308
- for (rawValue, binding) in overrides {
309
- if let action = HotkeyAction(rawValue: rawValue) {
310
- merged[action] = binding
311
- }
312
- }
313
- }
314
-
315
- self.bindings = merged
316
- }
317
-
318
- // MARK: - Registration
319
-
320
- func register(action: HotkeyAction, callback: @escaping () -> Void) {
321
- callbacks[action] = callback
322
- guard let binding = bindings[action] else { return }
323
- HotkeyManager.shared.registerSingle(
324
- id: action.carbonID,
325
- keyCode: binding.keyCode,
326
- modifiers: binding.carbonModifiers,
327
- callback: instrumentedCallback(for: action, callback: callback)
328
- )
329
- }
330
-
331
- // MARK: - Update
332
-
333
- func updateBinding(for action: HotkeyAction, to binding: KeyBinding) {
334
- bindings[action] = binding
335
-
336
- // Persist to UserDefaults
337
- if let data = try? JSONEncoder().encode(binding) {
338
- UserDefaults.standard.set(data, forKey: "hotkey.\(action.rawValue)")
339
- }
340
-
341
- // Re-register if we have a callback
342
- if let callback = callbacks[action] {
343
- HotkeyManager.shared.registerSingle(
344
- id: action.carbonID,
345
- keyCode: binding.keyCode,
346
- modifiers: binding.carbonModifiers,
347
- callback: instrumentedCallback(for: action, callback: callback)
348
- )
349
- }
350
- }
351
-
352
- // MARK: - Reset
353
-
354
- func resetBinding(for action: HotkeyAction) {
355
- guard let defaultBinding = Self.defaultBindings[action] else { return }
356
- UserDefaults.standard.removeObject(forKey: "hotkey.\(action.rawValue)")
357
- bindings[action] = defaultBinding
358
-
359
- if let callback = callbacks[action] {
360
- HotkeyManager.shared.registerSingle(
361
- id: action.carbonID,
362
- keyCode: defaultBinding.keyCode,
363
- modifiers: defaultBinding.carbonModifiers,
364
- callback: instrumentedCallback(for: action, callback: callback)
365
- )
366
- }
367
- }
368
-
369
- func resetAll() {
370
- for action in HotkeyAction.allCases {
371
- UserDefaults.standard.removeObject(forKey: "hotkey.\(action.rawValue)")
372
- }
373
- bindings = Self.defaultBindings
374
-
375
- // Re-register all with stored callbacks
376
- for (action, callback) in callbacks {
377
- guard let binding = bindings[action] else { continue }
378
- HotkeyManager.shared.registerSingle(
379
- id: action.carbonID,
380
- keyCode: binding.keyCode,
381
- modifiers: binding.carbonModifiers,
382
- callback: instrumentedCallback(for: action, callback: callback)
383
- )
384
- }
385
- }
386
-
387
- // MARK: - Conflict detection
388
-
389
- func conflicts(for action: HotkeyAction, with binding: KeyBinding) -> HotkeyAction? {
390
- for (existingAction, existingBinding) in bindings {
391
- if existingAction != action &&
392
- existingBinding.keyCode == binding.keyCode &&
393
- existingBinding.carbonModifiers == binding.carbonModifiers {
394
- return existingAction
395
- }
396
- }
397
- return nil
398
- }
399
- }