@lattices/cli 0.4.14 → 0.6.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 (181) hide show
  1. package/README.md +5 -7
  2. package/apps/mac/Info.plist +4 -4
  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/proposals/LAT-007-unified-app-shell.md +128 -0
  19. package/docs/reference/dewey.config.ts +2 -2
  20. package/docs/release.md +171 -0
  21. package/docs/repo-structure.md +5 -5
  22. package/docs/voice.md +11 -27
  23. package/package.json +11 -10
  24. package/apps/mac/Package.swift +0 -27
  25. package/apps/mac/Sources/AppShell/App.swift +0 -26
  26. package/apps/mac/Sources/AppShell/AppActivationCoordinator.swift +0 -27
  27. package/apps/mac/Sources/AppShell/AppDelegate.swift +0 -189
  28. package/apps/mac/Sources/AppShell/AppServicesBootstrap.swift +0 -25
  29. package/apps/mac/Sources/AppShell/AppShellView.swift +0 -171
  30. package/apps/mac/Sources/AppShell/AppUpdater.swift +0 -305
  31. package/apps/mac/Sources/AppShell/CliActionLauncher.swift +0 -50
  32. package/apps/mac/Sources/AppShell/HomeDashboardView.swift +0 -133
  33. package/apps/mac/Sources/AppShell/HotkeyBootstrap.swift +0 -87
  34. package/apps/mac/Sources/AppShell/KeyRecorderView.swift +0 -210
  35. package/apps/mac/Sources/AppShell/LatticesRuntime.swift +0 -104
  36. package/apps/mac/Sources/AppShell/MainView.swift +0 -847
  37. package/apps/mac/Sources/AppShell/MainWindow.swift +0 -83
  38. package/apps/mac/Sources/AppShell/MenuBarController.swift +0 -177
  39. package/apps/mac/Sources/AppShell/OnboardingView.swift +0 -483
  40. package/apps/mac/Sources/AppShell/PermissionsAssistantView.swift +0 -366
  41. package/apps/mac/Sources/AppShell/PermissionsAssistantWindow.swift +0 -70
  42. package/apps/mac/Sources/AppShell/Preferences.swift +0 -297
  43. package/apps/mac/Sources/AppShell/SettingsView.swift +0 -3163
  44. package/apps/mac/Sources/AppShell/SettingsWindow.swift +0 -34
  45. package/apps/mac/Sources/AppShell/WorkspaceInspectorPresenter.swift +0 -13
  46. package/apps/mac/Sources/Core/Actions/HotkeyManager.swift +0 -256
  47. package/apps/mac/Sources/Core/Actions/HotkeyStore.swift +0 -399
  48. package/apps/mac/Sources/Core/Actions/IntentEngine.swift +0 -988
  49. package/apps/mac/Sources/Core/Actions/IntentSchema.swift +0 -94
  50. package/apps/mac/Sources/Core/Actions/Intents/CreateLayerIntent.swift +0 -54
  51. package/apps/mac/Sources/Core/Actions/Intents/DistributeIntent.swift +0 -56
  52. package/apps/mac/Sources/Core/Actions/Intents/FocusIntent.swift +0 -69
  53. package/apps/mac/Sources/Core/Actions/Intents/HelpIntent.swift +0 -41
  54. package/apps/mac/Sources/Core/Actions/Intents/KillIntent.swift +0 -47
  55. package/apps/mac/Sources/Core/Actions/Intents/LatticeIntent.swift +0 -53
  56. package/apps/mac/Sources/Core/Actions/Intents/LaunchIntent.swift +0 -67
  57. package/apps/mac/Sources/Core/Actions/Intents/ListSessionsIntent.swift +0 -32
  58. package/apps/mac/Sources/Core/Actions/Intents/ListWindowsIntent.swift +0 -30
  59. package/apps/mac/Sources/Core/Actions/Intents/ScanIntent.swift +0 -52
  60. package/apps/mac/Sources/Core/Actions/Intents/SearchIntent.swift +0 -190
  61. package/apps/mac/Sources/Core/Actions/Intents/SwitchLayerIntent.swift +0 -50
  62. package/apps/mac/Sources/Core/Actions/Intents/TileIntent.swift +0 -61
  63. package/apps/mac/Sources/Core/Actions/PaletteCommand.swift +0 -439
  64. package/apps/mac/Sources/Core/Actions/VoiceIntentResolver.swift +0 -713
  65. package/apps/mac/Sources/Core/Companion/CompanionActivityLog.swift +0 -70
  66. package/apps/mac/Sources/Core/Companion/CompanionKeyboardController.swift +0 -141
  67. package/apps/mac/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +0 -454
  68. package/apps/mac/Sources/Core/Companion/LatticesCompanionCockpit.swift +0 -555
  69. package/apps/mac/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +0 -629
  70. package/apps/mac/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +0 -204
  71. package/apps/mac/Sources/Core/Companion/LatticesDeckHost.swift +0 -1463
  72. package/apps/mac/Sources/Core/Daemon/DaemonProtocol.swift +0 -114
  73. package/apps/mac/Sources/Core/Daemon/DaemonServer.swift +0 -427
  74. package/apps/mac/Sources/Core/Daemon/LatticesApi.swift +0 -2965
  75. package/apps/mac/Sources/Core/Desktop/AccessibilityTextExtractor.swift +0 -111
  76. package/apps/mac/Sources/Core/Desktop/AppTypeClassifier.swift +0 -106
  77. package/apps/mac/Sources/Core/Desktop/DesktopModel.swift +0 -331
  78. package/apps/mac/Sources/Core/Desktop/DesktopModelTypes.swift +0 -73
  79. package/apps/mac/Sources/Core/Desktop/InventoryManager.swift +0 -35
  80. package/apps/mac/Sources/Core/Desktop/InventoryPath.swift +0 -43
  81. package/apps/mac/Sources/Core/Desktop/MouseFinder.swift +0 -527
  82. package/apps/mac/Sources/Core/Desktop/OcrModel.swift +0 -467
  83. package/apps/mac/Sources/Core/Desktop/OcrStore.swift +0 -329
  84. package/apps/mac/Sources/Core/Desktop/PlacementSpec.swift +0 -195
  85. package/apps/mac/Sources/Core/Desktop/SessionWindowLocator.swift +0 -139
  86. package/apps/mac/Sources/Core/Desktop/TilePickerView.swift +0 -209
  87. package/apps/mac/Sources/Core/Desktop/WindowCapture.swift +0 -33
  88. package/apps/mac/Sources/Core/Desktop/WindowDragSnapController.swift +0 -429
  89. package/apps/mac/Sources/Core/Desktop/WindowPreviewCard.swift +0 -100
  90. package/apps/mac/Sources/Core/Desktop/WindowPreviewStore.swift +0 -112
  91. package/apps/mac/Sources/Core/Desktop/WindowSelectionStore.swift +0 -76
  92. package/apps/mac/Sources/Core/Desktop/WindowTiler.swift +0 -2222
  93. package/apps/mac/Sources/Core/Input/EventTapBreaker.swift +0 -124
  94. package/apps/mac/Sources/Core/Input/EventTapThread.swift +0 -54
  95. package/apps/mac/Sources/Core/Input/InputCaptureResetCenter.swift +0 -20
  96. package/apps/mac/Sources/Core/Input/KeyboardRemapConfig.swift +0 -69
  97. package/apps/mac/Sources/Core/Input/KeyboardRemapController.swift +0 -346
  98. package/apps/mac/Sources/Core/Input/KeyboardRemapStore.swift +0 -141
  99. package/apps/mac/Sources/Core/Input/MouseGestureConfig.swift +0 -499
  100. package/apps/mac/Sources/Core/Input/MouseGestureController.swift +0 -2583
  101. package/apps/mac/Sources/Core/Input/MouseInputDeviceStore.swift +0 -98
  102. package/apps/mac/Sources/Core/Input/MouseInputEventViewer.swift +0 -272
  103. package/apps/mac/Sources/Core/Input/MouseShortcutStore.swift +0 -170
  104. package/apps/mac/Sources/Core/Input/SecureEventInputMonitor.swift +0 -39
  105. package/apps/mac/Sources/Core/Input/ShapeRecognizer.swift +0 -624
  106. package/apps/mac/Sources/Core/Input/TapBudgetMeter.swift +0 -56
  107. package/apps/mac/Sources/Core/Overlays/AppWindowShell.swift +0 -63
  108. package/apps/mac/Sources/Core/Overlays/CommandMode/CommandModeState.swift +0 -1566
  109. package/apps/mac/Sources/Core/Overlays/CommandMode/CommandModeView.swift +0 -1927
  110. package/apps/mac/Sources/Core/Overlays/CommandMode/CommandModeWindow.swift +0 -196
  111. package/apps/mac/Sources/Core/Overlays/CommandPalette/CommandPaletteView.swift +0 -307
  112. package/apps/mac/Sources/Core/Overlays/CommandPalette/CommandPaletteWindow.swift +0 -67
  113. package/apps/mac/Sources/Core/Overlays/HUD/CheatSheetHUD.swift +0 -576
  114. package/apps/mac/Sources/Core/Overlays/HUD/HUDBottomBar.swift +0 -279
  115. package/apps/mac/Sources/Core/Overlays/HUD/HUDController.swift +0 -1158
  116. package/apps/mac/Sources/Core/Overlays/HUD/HUDLeftBar.swift +0 -849
  117. package/apps/mac/Sources/Core/Overlays/HUD/HUDMinimap.swift +0 -179
  118. package/apps/mac/Sources/Core/Overlays/HUD/HUDRightBar.swift +0 -596
  119. package/apps/mac/Sources/Core/Overlays/HUD/HUDState.swift +0 -367
  120. package/apps/mac/Sources/Core/Overlays/HUD/HUDTopBar.swift +0 -243
  121. package/apps/mac/Sources/Core/Overlays/HUD/LauncherHUD.swift +0 -334
  122. package/apps/mac/Sources/Core/Overlays/HUD/LayerBezel.swift +0 -203
  123. package/apps/mac/Sources/Core/Overlays/OmniSearch/OmniSearchState.swift +0 -280
  124. package/apps/mac/Sources/Core/Overlays/OmniSearch/OmniSearchView.swift +0 -422
  125. package/apps/mac/Sources/Core/Overlays/OmniSearch/OmniSearchWindow.swift +0 -94
  126. package/apps/mac/Sources/Core/Overlays/OverlayPanelShell.swift +0 -241
  127. package/apps/mac/Sources/Core/Overlays/ScreenMap/ScreenMapState.swift +0 -3135
  128. package/apps/mac/Sources/Core/Overlays/ScreenMap/ScreenMapView.swift +0 -3977
  129. package/apps/mac/Sources/Core/Overlays/ScreenMap/ScreenMapWindowController.swift +0 -119
  130. package/apps/mac/Sources/Core/Overlays/ScreenOverlayCanvasController.swift +0 -1217
  131. package/apps/mac/Sources/Core/Overlays/Voice/VoiceCommandWindow.swift +0 -1575
  132. package/apps/mac/Sources/Core/Pi/PiAuthNextStepCard.swift +0 -148
  133. package/apps/mac/Sources/Core/Pi/PiAuthPromptCard.swift +0 -90
  134. package/apps/mac/Sources/Core/Pi/PiChatDock.swift +0 -564
  135. package/apps/mac/Sources/Core/Pi/PiChatSession.swift +0 -1948
  136. package/apps/mac/Sources/Core/Pi/PiInstallCallout.swift +0 -86
  137. package/apps/mac/Sources/Core/Pi/PiProviderSetupCallout.swift +0 -99
  138. package/apps/mac/Sources/Core/Pi/PiWorkspaceView.swift +0 -510
  139. package/apps/mac/Sources/Core/System/Capability.swift +0 -79
  140. package/apps/mac/Sources/Core/System/DiagnosticLog.swift +0 -373
  141. package/apps/mac/Sources/Core/System/EventBus.swift +0 -31
  142. package/apps/mac/Sources/Core/System/PermissionChecker.swift +0 -224
  143. package/apps/mac/Sources/Core/System/ProcessModel.swift +0 -199
  144. package/apps/mac/Sources/Core/System/ProcessQuery.swift +0 -151
  145. package/apps/mac/Sources/Core/System/SystemTelemetryMonitor.swift +0 -273
  146. package/apps/mac/Sources/Core/Voice/AdvisorLearningStore.swift +0 -90
  147. package/apps/mac/Sources/Core/Voice/AgentSession.swift +0 -377
  148. package/apps/mac/Sources/Core/Voice/AudioProvider.swift +0 -555
  149. package/apps/mac/Sources/Core/Voice/HandsOffSession.swift +0 -839
  150. package/apps/mac/Sources/Core/Voice/VoiceChatView.swift +0 -192
  151. package/apps/mac/Sources/Core/Voice/VoxClient.swift +0 -454
  152. package/apps/mac/Sources/Core/Workspace/Project.swift +0 -28
  153. package/apps/mac/Sources/Core/Workspace/ProjectScanner.swift +0 -141
  154. package/apps/mac/Sources/Core/Workspace/SessionLayerStore.swift +0 -285
  155. package/apps/mac/Sources/Core/Workspace/SessionManager.swift +0 -75
  156. package/apps/mac/Sources/Core/Workspace/Terminal/Terminal.swift +0 -259
  157. package/apps/mac/Sources/Core/Workspace/Terminal/TerminalQuery.swift +0 -156
  158. package/apps/mac/Sources/Core/Workspace/Terminal/TerminalSynthesizer.swift +0 -200
  159. package/apps/mac/Sources/Core/Workspace/Tmux/TmuxModel.swift +0 -60
  160. package/apps/mac/Sources/Core/Workspace/Tmux/TmuxQuery.swift +0 -105
  161. package/apps/mac/Sources/Core/Workspace/WorkspaceManager.swift +0 -1027
  162. package/apps/mac/Sources/UI/ActionRow.swift +0 -78
  163. package/apps/mac/Sources/UI/OrphanRow.swift +0 -129
  164. package/apps/mac/Sources/UI/ProjectRow.swift +0 -368
  165. package/apps/mac/Sources/UI/TabGroupRow.swift +0 -178
  166. package/apps/mac/Sources/UI/Theme.swift +0 -164
  167. package/apps/mac/Tests/StageDragTests.swift +0 -333
  168. package/apps/mac/Tests/StageJoinTests.swift +0 -313
  169. package/apps/mac/Tests/StageManagerTests.swift +0 -280
  170. package/apps/mac/Tests/StageTileTests.swift +0 -353
  171. package/swift/Package.swift +0 -20
  172. package/swift/Sources/DeckKit/DeckAction.swift +0 -51
  173. package/swift/Sources/DeckKit/DeckBridgeSecurity.swift +0 -152
  174. package/swift/Sources/DeckKit/DeckCockpit.swift +0 -82
  175. package/swift/Sources/DeckKit/DeckHost.swift +0 -7
  176. package/swift/Sources/DeckKit/DeckManifest.swift +0 -145
  177. package/swift/Sources/DeckKit/DeckRuntimeSnapshot.swift +0 -533
  178. package/swift/Sources/DeckKit/DeckTrackpad.swift +0 -63
  179. package/swift/Sources/DeckKit/DeckValue.swift +0 -93
  180. package/swift/Sources/DeckKit/DeckVoiceError.swift +0 -88
  181. 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
- }