@lattices/cli 0.4.5 → 0.4.7
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.
- package/app/Info.plist +2 -2
- package/app/Lattices.app/Contents/Info.plist +2 -2
- package/app/Lattices.app/Contents/MacOS/Lattices +0 -0
- package/app/Sources/{AppDelegate.swift → AppShell/AppDelegate.swift} +9 -0
- package/app/Sources/{AppShellView.swift → AppShell/AppShellView.swift} +10 -1
- package/app/Sources/{KeyRecorderView.swift → AppShell/KeyRecorderView.swift} +1 -1
- package/app/Sources/{Preferences.swift → AppShell/Preferences.swift} +0 -2
- package/app/Sources/{SettingsView.swift → AppShell/SettingsView.swift} +27 -2
- package/app/Sources/{HotkeyStore.swift → Core/Actions/HotkeyStore.swift} +15 -2
- package/app/Sources/{IntentEngine.swift → Core/Actions/IntentEngine.swift} +44 -26
- package/app/Sources/Core/Actions/IntentSchema.swift +94 -0
- package/app/Sources/{Intents → Core/Actions/Intents}/LatticeIntent.swift +0 -25
- package/app/Sources/{VoiceIntentResolver.swift → Core/Actions/VoiceIntentResolver.swift} +46 -4
- package/app/Sources/{DesktopModel.swift → Core/Desktop/DesktopModel.swift} +2 -8
- package/app/Sources/Core/Desktop/SessionWindowLocator.swift +139 -0
- package/app/Sources/Core/Desktop/WindowPreviewCard.swift +100 -0
- package/app/Sources/Core/Desktop/WindowPreviewStore.swift +113 -0
- package/app/Sources/Core/Desktop/WindowSelectionStore.swift +76 -0
- package/app/Sources/{WindowTiler.swift → Core/Desktop/WindowTiler.swift} +24 -110
- package/app/Sources/{CommandModeState.swift → Core/Overlays/CommandMode/CommandModeState.swift} +228 -24
- package/app/Sources/{CommandModeView.swift → Core/Overlays/CommandMode/CommandModeView.swift} +601 -59
- package/app/Sources/{CommandModeWindow.swift → Core/Overlays/CommandMode/CommandModeWindow.swift} +9 -5
- package/app/Sources/Core/Overlays/CommandPalette/CommandPaletteWindow.swift +67 -0
- package/app/Sources/{CheatSheetHUD.swift → Core/Overlays/HUD/CheatSheetHUD.swift} +1 -0
- package/app/Sources/{HUDRightBar.swift → Core/Overlays/HUD/HUDRightBar.swift} +23 -201
- package/app/Sources/{LauncherHUD.swift → Core/Overlays/HUD/LauncherHUD.swift} +12 -26
- package/app/Sources/Core/Overlays/OmniSearch/OmniSearchWindow.swift +94 -0
- package/app/Sources/Core/Overlays/OverlayPanelShell.swift +241 -0
- package/app/Sources/{ScreenMapState.swift → Core/Overlays/ScreenMap/ScreenMapState.swift} +25 -2
- package/app/Sources/{ScreenMapView.swift → Core/Overlays/ScreenMap/ScreenMapView.swift} +20 -7
- package/app/Sources/{VoiceCommandWindow.swift → Core/Overlays/Voice/VoiceCommandWindow.swift} +46 -74
- package/app/Sources/{WorkspaceManager.swift → Core/Workspace/WorkspaceManager.swift} +59 -4
- package/docs/component-extraction-roadmap.md +392 -0
- package/package.json +3 -1
- package/app/Sources/CommandPaletteWindow.swift +0 -134
- package/app/Sources/OmniSearchWindow.swift +0 -165
- /package/app/Sources/{App.swift → AppShell/App.swift} +0 -0
- /package/app/Sources/{AppUpdater.swift → AppShell/AppUpdater.swift} +0 -0
- /package/app/Sources/{CliActionLauncher.swift → AppShell/CliActionLauncher.swift} +0 -0
- /package/app/Sources/{HomeDashboardView.swift → AppShell/HomeDashboardView.swift} +0 -0
- /package/app/Sources/{LatticesRuntime.swift → AppShell/LatticesRuntime.swift} +0 -0
- /package/app/Sources/{MainView.swift → AppShell/MainView.swift} +0 -0
- /package/app/Sources/{MainWindow.swift → AppShell/MainWindow.swift} +0 -0
- /package/app/Sources/{OnboardingView.swift → AppShell/OnboardingView.swift} +0 -0
- /package/app/Sources/{SettingsWindow.swift → AppShell/SettingsWindow.swift} +0 -0
- /package/app/Sources/{HotkeyManager.swift → Core/Actions/HotkeyManager.swift} +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/CreateLayerIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/DistributeIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/FocusIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/HelpIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/KillIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/LaunchIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/ListSessionsIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/ListWindowsIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/ScanIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/SearchIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/SwitchLayerIntent.swift +0 -0
- /package/app/Sources/{Intents → Core/Actions/Intents}/TileIntent.swift +0 -0
- /package/app/Sources/{PaletteCommand.swift → Core/Actions/PaletteCommand.swift} +0 -0
- /package/app/Sources/{CompanionActivityLog.swift → Core/Companion/CompanionActivityLog.swift} +0 -0
- /package/app/Sources/{CompanionKeyboardController.swift → Core/Companion/CompanionKeyboardController.swift} +0 -0
- /package/app/Sources/{LatticesCompanionBridgeServer.swift → Core/Companion/LatticesCompanionBridgeServer.swift} +0 -0
- /package/app/Sources/{LatticesCompanionCockpit.swift → Core/Companion/LatticesCompanionCockpit.swift} +0 -0
- /package/app/Sources/{LatticesCompanionSecurityCoordinator.swift → Core/Companion/LatticesCompanionSecurityCoordinator.swift} +0 -0
- /package/app/Sources/{LatticesCompanionTrackpadController.swift → Core/Companion/LatticesCompanionTrackpadController.swift} +0 -0
- /package/app/Sources/{LatticesDeckHost.swift → Core/Companion/LatticesDeckHost.swift} +0 -0
- /package/app/Sources/{DaemonProtocol.swift → Core/Daemon/DaemonProtocol.swift} +0 -0
- /package/app/Sources/{DaemonServer.swift → Core/Daemon/DaemonServer.swift} +0 -0
- /package/app/Sources/{LatticesApi.swift → Core/Daemon/LatticesApi.swift} +0 -0
- /package/app/Sources/{AccessibilityTextExtractor.swift → Core/Desktop/AccessibilityTextExtractor.swift} +0 -0
- /package/app/Sources/{AppTypeClassifier.swift → Core/Desktop/AppTypeClassifier.swift} +0 -0
- /package/app/Sources/{DesktopModelTypes.swift → Core/Desktop/DesktopModelTypes.swift} +0 -0
- /package/app/Sources/{InventoryManager.swift → Core/Desktop/InventoryManager.swift} +0 -0
- /package/app/Sources/{InventoryPath.swift → Core/Desktop/InventoryPath.swift} +0 -0
- /package/app/Sources/{MouseFinder.swift → Core/Desktop/MouseFinder.swift} +0 -0
- /package/app/Sources/{OcrModel.swift → Core/Desktop/OcrModel.swift} +0 -0
- /package/app/Sources/{OcrStore.swift → Core/Desktop/OcrStore.swift} +0 -0
- /package/app/Sources/{PlacementSpec.swift → Core/Desktop/PlacementSpec.swift} +0 -0
- /package/app/Sources/{TilePickerView.swift → Core/Desktop/TilePickerView.swift} +0 -0
- /package/app/Sources/{WindowDragSnapController.swift → Core/Desktop/WindowDragSnapController.swift} +0 -0
- /package/app/Sources/{MouseGestureConfig.swift → Core/Input/MouseGestureConfig.swift} +0 -0
- /package/app/Sources/{MouseGestureController.swift → Core/Input/MouseGestureController.swift} +0 -0
- /package/app/Sources/{MouseInputDeviceStore.swift → Core/Input/MouseInputDeviceStore.swift} +0 -0
- /package/app/Sources/{MouseInputEventViewer.swift → Core/Input/MouseInputEventViewer.swift} +0 -0
- /package/app/Sources/{MouseShortcutStore.swift → Core/Input/MouseShortcutStore.swift} +0 -0
- /package/app/Sources/{AppWindowShell.swift → Core/Overlays/AppWindowShell.swift} +0 -0
- /package/app/Sources/{CommandPaletteView.swift → Core/Overlays/CommandPalette/CommandPaletteView.swift} +0 -0
- /package/app/Sources/{HUDBottomBar.swift → Core/Overlays/HUD/HUDBottomBar.swift} +0 -0
- /package/app/Sources/{HUDController.swift → Core/Overlays/HUD/HUDController.swift} +0 -0
- /package/app/Sources/{HUDLeftBar.swift → Core/Overlays/HUD/HUDLeftBar.swift} +0 -0
- /package/app/Sources/{HUDMinimap.swift → Core/Overlays/HUD/HUDMinimap.swift} +0 -0
- /package/app/Sources/{HUDState.swift → Core/Overlays/HUD/HUDState.swift} +0 -0
- /package/app/Sources/{HUDTopBar.swift → Core/Overlays/HUD/HUDTopBar.swift} +0 -0
- /package/app/Sources/{LayerBezel.swift → Core/Overlays/HUD/LayerBezel.swift} +0 -0
- /package/app/Sources/{OmniSearchState.swift → Core/Overlays/OmniSearch/OmniSearchState.swift} +0 -0
- /package/app/Sources/{OmniSearchView.swift → Core/Overlays/OmniSearch/OmniSearchView.swift} +0 -0
- /package/app/Sources/{ScreenMapWindowController.swift → Core/Overlays/ScreenMap/ScreenMapWindowController.swift} +0 -0
- /package/app/Sources/{PiAuthNextStepCard.swift → Core/Pi/PiAuthNextStepCard.swift} +0 -0
- /package/app/Sources/{PiAuthPromptCard.swift → Core/Pi/PiAuthPromptCard.swift} +0 -0
- /package/app/Sources/{PiChatDock.swift → Core/Pi/PiChatDock.swift} +0 -0
- /package/app/Sources/{PiChatSession.swift → Core/Pi/PiChatSession.swift} +0 -0
- /package/app/Sources/{PiInstallCallout.swift → Core/Pi/PiInstallCallout.swift} +0 -0
- /package/app/Sources/{PiProviderSetupCallout.swift → Core/Pi/PiProviderSetupCallout.swift} +0 -0
- /package/app/Sources/{PiWorkspaceView.swift → Core/Pi/PiWorkspaceView.swift} +0 -0
- /package/app/Sources/{DiagnosticLog.swift → Core/System/DiagnosticLog.swift} +0 -0
- /package/app/Sources/{EventBus.swift → Core/System/EventBus.swift} +0 -0
- /package/app/Sources/{PermissionChecker.swift → Core/System/PermissionChecker.swift} +0 -0
- /package/app/Sources/{ProcessModel.swift → Core/System/ProcessModel.swift} +0 -0
- /package/app/Sources/{ProcessQuery.swift → Core/System/ProcessQuery.swift} +0 -0
- /package/app/Sources/{SystemTelemetryMonitor.swift → Core/System/SystemTelemetryMonitor.swift} +0 -0
- /package/app/Sources/{AdvisorLearningStore.swift → Core/Voice/AdvisorLearningStore.swift} +0 -0
- /package/app/Sources/{AgentSession.swift → Core/Voice/AgentSession.swift} +0 -0
- /package/app/Sources/{AudioProvider.swift → Core/Voice/AudioProvider.swift} +0 -0
- /package/app/Sources/{HandsOffSession.swift → Core/Voice/HandsOffSession.swift} +0 -0
- /package/app/Sources/{VoiceChatView.swift → Core/Voice/VoiceChatView.swift} +0 -0
- /package/app/Sources/{VoxClient.swift → Core/Voice/VoxClient.swift} +0 -0
- /package/app/Sources/{Project.swift → Core/Workspace/Project.swift} +0 -0
- /package/app/Sources/{ProjectScanner.swift → Core/Workspace/ProjectScanner.swift} +0 -0
- /package/app/Sources/{SessionLayerStore.swift → Core/Workspace/SessionLayerStore.swift} +0 -0
- /package/app/Sources/{SessionManager.swift → Core/Workspace/SessionManager.swift} +0 -0
- /package/app/Sources/{Terminal.swift → Core/Workspace/Terminal/Terminal.swift} +0 -0
- /package/app/Sources/{TerminalQuery.swift → Core/Workspace/Terminal/TerminalQuery.swift} +0 -0
- /package/app/Sources/{TerminalSynthesizer.swift → Core/Workspace/Terminal/TerminalSynthesizer.swift} +0 -0
- /package/app/Sources/{TmuxModel.swift → Core/Workspace/Tmux/TmuxModel.swift} +0 -0
- /package/app/Sources/{TmuxQuery.swift → Core/Workspace/Tmux/TmuxQuery.swift} +0 -0
- /package/app/Sources/{ActionRow.swift → UI/ActionRow.swift} +0 -0
- /package/app/Sources/{OrphanRow.swift → UI/OrphanRow.swift} +0 -0
- /package/app/Sources/{ProjectRow.swift → UI/ProjectRow.swift} +0 -0
- /package/app/Sources/{TabGroupRow.swift → UI/TabGroupRow.swift} +0 -0
- /package/app/Sources/{Theme.swift → UI/Theme.swift} +0 -0
package/app/Info.plist
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>APPL</string>
|
|
17
17
|
<key>CFBundleVersion</key>
|
|
18
|
-
<string>0.4.
|
|
18
|
+
<string>0.4.7</string>
|
|
19
19
|
<key>CFBundleShortVersionString</key>
|
|
20
|
-
<string>0.4.
|
|
20
|
+
<string>0.4.7</string>
|
|
21
21
|
<key>LSMinimumSystemVersion</key>
|
|
22
22
|
<string>13.0</string>
|
|
23
23
|
<key>LSUIElement</key>
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>APPL</string>
|
|
17
17
|
<key>CFBundleVersion</key>
|
|
18
|
-
<string>0.4.
|
|
18
|
+
<string>0.4.7</string>
|
|
19
19
|
<key>CFBundleShortVersionString</key>
|
|
20
|
-
<string>0.4.
|
|
20
|
+
<string>0.4.7</string>
|
|
21
21
|
<key>LSMinimumSystemVersion</key>
|
|
22
22
|
<string>13.0</string>
|
|
23
23
|
<key>LSUIElement</key>
|
|
Binary file
|
|
@@ -91,6 +91,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|
|
91
91
|
store.register(action: .unifiedWindow) { ScreenMapWindowController.shared.toggle() }
|
|
92
92
|
store.register(action: .bezel) { Self.showWorkspaceInspector() }
|
|
93
93
|
store.register(action: .cheatSheet) { SettingsWindowController.shared.show() }
|
|
94
|
+
store.register(action: .desktopInventory) {
|
|
95
|
+
DiagnosticLog.shared.info("Hotkey: desktopInventory triggered")
|
|
96
|
+
ScreenMapWindowController.shared.showPage(.desktopInventory)
|
|
97
|
+
}
|
|
94
98
|
store.register(action: .voiceCommand) {
|
|
95
99
|
DiagnosticLog.shared.info("Hotkey: voiceCommand triggered")
|
|
96
100
|
VoiceCommandWindow.shared.toggle()
|
|
@@ -158,6 +162,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|
|
158
162
|
}
|
|
159
163
|
store.register(action: .tileDistribute) { WindowTiler.distributeVisible(reactivateLattices: false) }
|
|
160
164
|
store.register(action: .tileTypeGrid) { WindowTiler.distributeVisibleByFrontmostType(reactivateLattices: false) }
|
|
165
|
+
store.register(action: .tileOrganize) {
|
|
166
|
+
let appName = DesktopModel.shared.frontmostWindow()?.app
|
|
167
|
+
?? NSWorkspace.shared.frontmostApplication?.localizedName
|
|
168
|
+
CommandModeWindow.shared.show(launchMode: .organize(appName: appName))
|
|
169
|
+
}
|
|
161
170
|
|
|
162
171
|
// Onboarding on first launch; otherwise just check permissions
|
|
163
172
|
if !OnboardingWindowController.shared.showIfNeeded() {
|
|
@@ -56,6 +56,10 @@ struct AppShellView: View {
|
|
|
56
56
|
.background(Palette.bg)
|
|
57
57
|
.onAppear {
|
|
58
58
|
commandState.onDismiss = { windowController.activePage = .home }
|
|
59
|
+
syncPageState(windowController.activePage)
|
|
60
|
+
}
|
|
61
|
+
.onChange(of: windowController.activePage) { page in
|
|
62
|
+
syncPageState(page)
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
|
|
@@ -116,7 +120,7 @@ struct AppShellView: View {
|
|
|
116
120
|
windowController.activePage = page
|
|
117
121
|
})
|
|
118
122
|
case .desktopInventory:
|
|
119
|
-
CommandModeView(state: commandState)
|
|
123
|
+
CommandModeView(state: commandState, presentation: .embedded)
|
|
120
124
|
case .pi:
|
|
121
125
|
PiWorkspaceView()
|
|
122
126
|
case .settings:
|
|
@@ -134,4 +138,9 @@ struct AppShellView: View {
|
|
|
134
138
|
)
|
|
135
139
|
}
|
|
136
140
|
}
|
|
141
|
+
|
|
142
|
+
private func syncPageState(_ page: AppPage) {
|
|
143
|
+
if page == .screenMap { controller.enter() }
|
|
144
|
+
if page == .desktopInventory { commandState.enter() }
|
|
145
|
+
}
|
|
137
146
|
}
|
|
@@ -34,7 +34,7 @@ struct KeyRecorderView: View {
|
|
|
34
34
|
.frame(minWidth: 80, alignment: .leading)
|
|
35
35
|
} else if let binding = binding {
|
|
36
36
|
HStack(spacing: 4) {
|
|
37
|
-
ForEach(binding.
|
|
37
|
+
ForEach(binding.compactDisplayParts, id: \.self) { part in
|
|
38
38
|
keyBadge(part)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -37,7 +37,6 @@ class Preferences: ObservableObject {
|
|
|
37
37
|
@Published var companionCockpitLayout: LatticesCompanionCockpitLayout {
|
|
38
38
|
didSet { persistCompanionCockpitLayout() }
|
|
39
39
|
}
|
|
40
|
-
|
|
41
40
|
@Published var mouseGesturesEnabled: Bool {
|
|
42
41
|
didSet { UserDefaults.standard.set(mouseGesturesEnabled, forKey: "mouseGestures.enabled") }
|
|
43
42
|
}
|
|
@@ -163,7 +162,6 @@ class Preferences: ObservableObject {
|
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
self.companionCockpitLayout = Self.loadCompanionCockpitLayout()
|
|
166
|
-
|
|
167
165
|
if UserDefaults.standard.object(forKey: "mouseGestures.enabled") != nil {
|
|
168
166
|
self.mouseGesturesEnabled = UserDefaults.standard.bool(forKey: "mouseGestures.enabled")
|
|
169
167
|
} else {
|
|
@@ -57,6 +57,7 @@ struct SettingsContentView: View {
|
|
|
57
57
|
@ObservedObject var prefs: Preferences
|
|
58
58
|
@ObservedObject var scanner: ProjectScanner
|
|
59
59
|
@ObservedObject var hotkeyStore: HotkeyStore = .shared
|
|
60
|
+
@ObservedObject var workspaceManager: WorkspaceManager = .shared
|
|
60
61
|
@ObservedObject var appUpdater: AppUpdater = .shared
|
|
61
62
|
@ObservedObject var mouseShortcutStore: MouseShortcutStore = .shared
|
|
62
63
|
var onBack: (() -> Void)? = nil
|
|
@@ -85,6 +86,13 @@ struct SettingsContentView: View {
|
|
|
85
86
|
page == .docs ? "Docs" : selectedTab.title
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
private var snapModifierBinding: Binding<SnapModifierKey> {
|
|
90
|
+
Binding(
|
|
91
|
+
get: { workspaceManager.snapZonesConfig.modifier ?? .command },
|
|
92
|
+
set: { workspaceManager.updateSnapModifier($0) }
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
private var backBar: some View {
|
|
89
97
|
VStack(spacing: 0) {
|
|
90
98
|
HStack(spacing: 8) {
|
|
@@ -459,13 +467,28 @@ struct SettingsContentView: View {
|
|
|
459
467
|
.labelsHidden()
|
|
460
468
|
}
|
|
461
469
|
|
|
462
|
-
|
|
470
|
+
HStack {
|
|
471
|
+
Text("Snap modifier")
|
|
472
|
+
.font(Typo.mono(10))
|
|
473
|
+
.foregroundColor(Palette.textDim)
|
|
474
|
+
Spacer()
|
|
475
|
+
Picker("", selection: snapModifierBinding) {
|
|
476
|
+
ForEach(SnapModifierKey.allCases) { modifier in
|
|
477
|
+
Text(modifier.shortLabel).tag(modifier)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
.pickerStyle(.segmented)
|
|
481
|
+
.labelsHidden()
|
|
482
|
+
.frame(width: 220)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
Text("Dragging stays normal until you hold \(snapModifierBinding.wrappedValue.label). While that key is down, Lattices reveals snap targets and a live preview for the window you’re moving.")
|
|
463
486
|
.font(Typo.caption(9))
|
|
464
487
|
.foregroundColor(Palette.textMuted.opacity(0.7))
|
|
465
488
|
|
|
466
489
|
cardDivider
|
|
467
490
|
|
|
468
|
-
Text("
|
|
491
|
+
Text("Advanced landing-zone rules still live in ~/.lattices/snap-zones.json. Modifier changes here take effect on the next drag.")
|
|
469
492
|
.font(Typo.caption(9))
|
|
470
493
|
.foregroundColor(Palette.textMuted.opacity(0.7))
|
|
471
494
|
}
|
|
@@ -1541,6 +1564,8 @@ struct SettingsContentView: View {
|
|
|
1541
1564
|
.foregroundColor(Palette.textMuted)
|
|
1542
1565
|
.fixedSize(horizontal: false, vertical: true)
|
|
1543
1566
|
}
|
|
1567
|
+
|
|
1568
|
+
compactKeyRecorder(action: .tileOrganize)
|
|
1544
1569
|
}
|
|
1545
1570
|
}
|
|
1546
1571
|
|
|
@@ -31,7 +31,7 @@ enum HotkeyAction: String, CaseIterable, Codable {
|
|
|
31
31
|
// Tiling
|
|
32
32
|
case tileLeft, tileRight, tileMaximize, tileCenter
|
|
33
33
|
case tileTopLeft, tileTopRight, tileBottomLeft, tileBottomRight
|
|
34
|
-
case tileTop, tileBottom, tileDistribute, tileTypeGrid
|
|
34
|
+
case tileTop, tileBottom, tileDistribute, tileTypeGrid, tileOrganize
|
|
35
35
|
case tileLeftThird, tileCenterThird, tileRightThird
|
|
36
36
|
|
|
37
37
|
var label: String {
|
|
@@ -40,7 +40,7 @@ enum HotkeyAction: String, CaseIterable, Codable {
|
|
|
40
40
|
case .screenMap: return "Screen Map"
|
|
41
41
|
case .bezel: return "Window Bezel"
|
|
42
42
|
case .cheatSheet: return "Cheat Sheet"
|
|
43
|
-
case .desktopInventory: return "
|
|
43
|
+
case .desktopInventory: return "Window Selector"
|
|
44
44
|
case .omniSearch: return "Search"
|
|
45
45
|
case .voiceCommand: return "Voice Command"
|
|
46
46
|
case .handsOff: return "Hands-Off Mode"
|
|
@@ -71,6 +71,7 @@ enum HotkeyAction: String, CaseIterable, Codable {
|
|
|
71
71
|
case .tileBottom: return "Bottom Half"
|
|
72
72
|
case .tileDistribute: return "Distribute"
|
|
73
73
|
case .tileTypeGrid: return "Grid Type"
|
|
74
|
+
case .tileOrganize: return "Organize Windows"
|
|
74
75
|
case .tileLeftThird: return "Left Third"
|
|
75
76
|
case .tileCenterThird: return "Center Third"
|
|
76
77
|
case .tileRightThird: return "Right Third"
|
|
@@ -127,6 +128,7 @@ enum HotkeyAction: String, CaseIterable, Codable {
|
|
|
127
128
|
case .tileLeftThird: return 311
|
|
128
129
|
case .tileCenterThird: return 312
|
|
129
130
|
case .tileRightThird: return 313
|
|
131
|
+
case .tileOrganize: return 315
|
|
130
132
|
}
|
|
131
133
|
}
|
|
132
134
|
|
|
@@ -142,6 +144,15 @@ struct KeyBinding: Codable, Equatable {
|
|
|
142
144
|
let carbonModifiers: UInt32
|
|
143
145
|
var displayParts: [String]
|
|
144
146
|
|
|
147
|
+
var compactDisplayParts: [String] {
|
|
148
|
+
guard let key = displayParts.last else { return [] }
|
|
149
|
+
let modifiers = Set(displayParts.dropLast())
|
|
150
|
+
if modifiers == Set(["Ctrl", "Option", "Shift", "Cmd"]) {
|
|
151
|
+
return ["Hyper", key]
|
|
152
|
+
}
|
|
153
|
+
return displayParts
|
|
154
|
+
}
|
|
155
|
+
|
|
145
156
|
static func carbonModifiers(from flags: NSEvent.ModifierFlags) -> UInt32 {
|
|
146
157
|
var mods: UInt32 = 0
|
|
147
158
|
if flags.contains(.command) { mods |= UInt32(cmdKey) }
|
|
@@ -231,6 +242,7 @@ class HotkeyStore: ObservableObject {
|
|
|
231
242
|
bind(.unifiedWindow, 18, hyper) // Hyper+1 (Workspace Home)
|
|
232
243
|
bind(.bezel, 19, hyper) // Hyper+2
|
|
233
244
|
bind(.hud, 20, hyper) // Hyper+3 (HUD overlay)
|
|
245
|
+
bind(.desktopInventory, 5, hyper) // Hyper+G
|
|
234
246
|
bind(.voiceCommand, 21, hyper) // Hyper+4 (moved from Hyper+3)
|
|
235
247
|
let cmdCtrl = UInt32(cmdKey | controlKey)
|
|
236
248
|
bind(.handsOff, 46, cmdCtrl) // Ctrl+Cmd+M
|
|
@@ -265,6 +277,7 @@ class HotkeyStore: ObservableObject {
|
|
|
265
277
|
bind(.tileLeftThird, 18, ctrlOpt) // Ctrl+Opt+1
|
|
266
278
|
bind(.tileCenterThird, 19, ctrlOpt) // Ctrl+Opt+2
|
|
267
279
|
bind(.tileRightThird, 20, ctrlOpt) // Ctrl+Opt+3
|
|
280
|
+
bind(.tileOrganize, 31, ctrlOpt) // Ctrl+Opt+O
|
|
268
281
|
|
|
269
282
|
return d
|
|
270
283
|
}()
|
|
@@ -1,31 +1,5 @@
|
|
|
1
1
|
import AppKit
|
|
2
2
|
|
|
3
|
-
// MARK: - Intent Definition
|
|
4
|
-
|
|
5
|
-
struct IntentDef {
|
|
6
|
-
let name: String
|
|
7
|
-
let description: String
|
|
8
|
-
let examples: [String] // Example phrases that map to this intent
|
|
9
|
-
let slots: [IntentSlot] // Named parameters extracted from the utterance
|
|
10
|
-
let handler: (IntentRequest) throws -> JSON
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
struct IntentSlot {
|
|
14
|
-
let name: String
|
|
15
|
-
let type: String // "string", "int", "position", "query"
|
|
16
|
-
let required: Bool
|
|
17
|
-
let description: String
|
|
18
|
-
let enumValues: [String]? // For constrained slots like tile positions
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
struct IntentRequest {
|
|
22
|
-
let intent: String
|
|
23
|
-
let slots: [String: JSON]
|
|
24
|
-
let rawText: String? // Original transcription, for fallback matching
|
|
25
|
-
let confidence: Double? // Transcription confidence from voice service
|
|
26
|
-
let source: String? // "vox", "siri", "cli", etc.
|
|
27
|
-
}
|
|
28
|
-
|
|
29
3
|
// MARK: - Intent Engine
|
|
30
4
|
|
|
31
5
|
final class IntentEngine {
|
|
@@ -133,6 +107,8 @@ final class IntentEngine {
|
|
|
133
107
|
description: "Target window ID", enumValues: nil),
|
|
134
108
|
IntentSlot(name: "session", type: "string", required: false,
|
|
135
109
|
description: "Target session name", enumValues: nil),
|
|
110
|
+
IntentSlot(name: "selection", type: "bool", required: false,
|
|
111
|
+
description: "Apply to the active multi-window selection instead of a single window", enumValues: nil),
|
|
136
112
|
],
|
|
137
113
|
handler: { req in
|
|
138
114
|
guard let posStr = req.slots["position"]?.stringValue else {
|
|
@@ -176,6 +152,34 @@ final class IntentEngine {
|
|
|
176
152
|
throw IntentError.targetNotFound("No window found for app '\(app)'")
|
|
177
153
|
}
|
|
178
154
|
|
|
155
|
+
if req.slots["selection"]?.boolValue == true {
|
|
156
|
+
let selectionIds = WindowSelectionStore.shared.windowIds
|
|
157
|
+
guard !selectionIds.isEmpty else {
|
|
158
|
+
throw IntentError.targetNotFound("No active window selection")
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if selectionIds.count == 1,
|
|
162
|
+
let wid = selectionIds.first,
|
|
163
|
+
let entry = DesktopModel.shared.windows[wid] {
|
|
164
|
+
tileEntry(entry)
|
|
165
|
+
return .object([
|
|
166
|
+
"ok": .bool(true),
|
|
167
|
+
"target": .string("selection"),
|
|
168
|
+
"wid": .int(Int(wid)),
|
|
169
|
+
"position": .string(posStr)
|
|
170
|
+
])
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return try LatticesApi.shared.dispatch(
|
|
174
|
+
method: "space.optimize",
|
|
175
|
+
params: .object([
|
|
176
|
+
"scope": .string("selection"),
|
|
177
|
+
"windowIds": .array(selectionIds.map { .int(Int($0)) }),
|
|
178
|
+
"region": .string(posStr)
|
|
179
|
+
])
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
179
183
|
// Default: tile frontmost window
|
|
180
184
|
DispatchQueue.main.async {
|
|
181
185
|
WindowTiler.tileFrontmostViaAX(to: placement)
|
|
@@ -401,6 +405,8 @@ final class IntentEngine {
|
|
|
401
405
|
description: "Constrain the grid to a screen region. Uses tile position names.",
|
|
402
406
|
enumValues: ["left", "right", "top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right",
|
|
403
407
|
"left-third", "center-third", "right-third"]),
|
|
408
|
+
IntentSlot(name: "selection", type: "bool", required: false,
|
|
409
|
+
description: "Use the active selected windows instead of all visible windows", enumValues: nil),
|
|
404
410
|
],
|
|
405
411
|
handler: { req in
|
|
406
412
|
var params: [String: JSON] = [:]
|
|
@@ -413,6 +419,18 @@ final class IntentEngine {
|
|
|
413
419
|
if let region = req.slots["region"]?.stringValue {
|
|
414
420
|
params["region"] = .string(region)
|
|
415
421
|
}
|
|
422
|
+
if req.slots["selection"]?.boolValue == true {
|
|
423
|
+
let selectionIds = WindowSelectionStore.shared.windowIds
|
|
424
|
+
guard !selectionIds.isEmpty else {
|
|
425
|
+
throw IntentError.targetNotFound("No active window selection")
|
|
426
|
+
}
|
|
427
|
+
params["scope"] = .string("selection")
|
|
428
|
+
params["windowIds"] = .array(selectionIds.map { .int(Int($0)) })
|
|
429
|
+
return try LatticesApi.shared.dispatch(
|
|
430
|
+
method: "space.optimize",
|
|
431
|
+
params: .object(params)
|
|
432
|
+
)
|
|
433
|
+
}
|
|
416
434
|
return try LatticesApi.shared.dispatch(
|
|
417
435
|
method: "layout.distribute",
|
|
418
436
|
params: params.isEmpty ? nil : .object(params)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
struct IntentDef {
|
|
4
|
+
let name: String
|
|
5
|
+
let description: String
|
|
6
|
+
let examples: [String]
|
|
7
|
+
let slots: [IntentSlot]
|
|
8
|
+
let handler: (IntentRequest) throws -> JSON
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
struct IntentSlot {
|
|
12
|
+
let name: String
|
|
13
|
+
let type: String
|
|
14
|
+
let required: Bool
|
|
15
|
+
let description: String
|
|
16
|
+
let enumValues: [String]?
|
|
17
|
+
let defaultValue: JSON?
|
|
18
|
+
|
|
19
|
+
init(
|
|
20
|
+
name: String,
|
|
21
|
+
type: String,
|
|
22
|
+
required: Bool,
|
|
23
|
+
description: String,
|
|
24
|
+
enumValues: [String]? = nil,
|
|
25
|
+
defaultValue: JSON? = nil
|
|
26
|
+
) {
|
|
27
|
+
self.name = name
|
|
28
|
+
self.type = type
|
|
29
|
+
self.required = required
|
|
30
|
+
self.description = description
|
|
31
|
+
self.enumValues = enumValues
|
|
32
|
+
self.defaultValue = defaultValue
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
struct IntentRequest {
|
|
37
|
+
let intent: String
|
|
38
|
+
let slots: [String: JSON]
|
|
39
|
+
let rawText: String?
|
|
40
|
+
let confidence: Double?
|
|
41
|
+
let source: String?
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
enum SlotType {
|
|
45
|
+
case string
|
|
46
|
+
case int
|
|
47
|
+
case bool
|
|
48
|
+
case position
|
|
49
|
+
case query
|
|
50
|
+
case app
|
|
51
|
+
case session
|
|
52
|
+
case layer
|
|
53
|
+
case enumerated([String])
|
|
54
|
+
|
|
55
|
+
var typeLabel: String {
|
|
56
|
+
switch self {
|
|
57
|
+
case .string: return "string"
|
|
58
|
+
case .int: return "int"
|
|
59
|
+
case .bool: return "bool"
|
|
60
|
+
case .position: return "position"
|
|
61
|
+
case .query: return "query"
|
|
62
|
+
case .app: return "app"
|
|
63
|
+
case .session: return "session"
|
|
64
|
+
case .layer: return "layer"
|
|
65
|
+
case .enumerated: return "string"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
var enumValues: [String]? {
|
|
70
|
+
guard case .enumerated(let values) = self else { return nil }
|
|
71
|
+
return values
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
typealias SlotDef = IntentSlot
|
|
76
|
+
|
|
77
|
+
extension IntentSlot {
|
|
78
|
+
init(
|
|
79
|
+
name: String,
|
|
80
|
+
type: SlotType,
|
|
81
|
+
required: Bool = true,
|
|
82
|
+
description: String = "",
|
|
83
|
+
defaultValue: JSON? = nil
|
|
84
|
+
) {
|
|
85
|
+
self.init(
|
|
86
|
+
name: name,
|
|
87
|
+
type: type.typeLabel,
|
|
88
|
+
required: required,
|
|
89
|
+
description: description,
|
|
90
|
+
enumValues: type.enumValues,
|
|
91
|
+
defaultValue: defaultValue
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -12,31 +12,6 @@ protocol LatticeIntent {
|
|
|
12
12
|
func perform(slots: [String: JSON]) throws -> JSON
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
// MARK: - Slot Definition
|
|
16
|
-
|
|
17
|
-
enum SlotType {
|
|
18
|
-
case string // Free-form text
|
|
19
|
-
case position // Tile position (left, right, maximize, etc.)
|
|
20
|
-
case app // Running app name
|
|
21
|
-
case session // Active tmux session
|
|
22
|
-
case layer // Layer name
|
|
23
|
-
case enumerated([String]) // Fixed set of values
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
struct SlotDef {
|
|
27
|
-
let name: String
|
|
28
|
-
let type: SlotType
|
|
29
|
-
let required: Bool
|
|
30
|
-
let defaultValue: JSON?
|
|
31
|
-
|
|
32
|
-
init(name: String, type: SlotType, required: Bool = true, defaultValue: JSON? = nil) {
|
|
33
|
-
self.name = name
|
|
34
|
-
self.type = type
|
|
35
|
-
self.required = required
|
|
36
|
-
self.defaultValue = defaultValue
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
15
|
// MARK: - Compiled Phrase Template
|
|
41
16
|
|
|
42
17
|
struct CompiledPhrase {
|
|
@@ -141,10 +141,43 @@ final class VoiceIntentResolver {
|
|
|
141
141
|
private func extractSlots(for intentName: String, input: String) -> ExtractedSlots {
|
|
142
142
|
switch intentName {
|
|
143
143
|
case "tile_window":
|
|
144
|
-
|
|
144
|
+
var slots: [String: JSON] = [:]
|
|
145
|
+
var boost = 0.0
|
|
146
|
+
|
|
147
|
+
if let position = resolvePosition(in: input) {
|
|
148
|
+
slots["position"] = .string(position)
|
|
149
|
+
boost += 0.28
|
|
150
|
+
} else {
|
|
145
151
|
return ExtractedSlots(slots: [:], boost: 0)
|
|
146
152
|
}
|
|
147
|
-
|
|
153
|
+
|
|
154
|
+
if refersToSelection(in: input) {
|
|
155
|
+
slots["selection"] = .bool(true)
|
|
156
|
+
boost += 0.08
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return ExtractedSlots(slots: slots, boost: boost)
|
|
160
|
+
|
|
161
|
+
case "distribute":
|
|
162
|
+
var slots: [String: JSON] = [:]
|
|
163
|
+
var boost = 0.0
|
|
164
|
+
|
|
165
|
+
if let region = resolvePosition(in: input) {
|
|
166
|
+
slots["region"] = .string(region)
|
|
167
|
+
boost += 0.18
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if let app = detectKnownApp(in: input) {
|
|
171
|
+
slots["app"] = .string(app)
|
|
172
|
+
boost += 0.14
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if refersToSelection(in: input) {
|
|
176
|
+
slots["selection"] = .bool(true)
|
|
177
|
+
boost += 0.12
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return ExtractedSlots(slots: slots, boost: boost)
|
|
148
181
|
|
|
149
182
|
case "focus":
|
|
150
183
|
if let app = detectKnownApp(in: input) ?? extractEntity(in: input, prefixes: focusPrefixes) {
|
|
@@ -426,6 +459,15 @@ final class VoiceIntentResolver {
|
|
|
426
459
|
return nil
|
|
427
460
|
}
|
|
428
461
|
|
|
462
|
+
private func refersToSelection(in input: String) -> Bool {
|
|
463
|
+
let markers = [
|
|
464
|
+
"grid that", "grid these", "grid those",
|
|
465
|
+
"tile that", "tile these", "tile those",
|
|
466
|
+
"selected windows", "selection", "selected", "these windows", "those windows", "them"
|
|
467
|
+
]
|
|
468
|
+
return markers.contains(where: input.contains)
|
|
469
|
+
}
|
|
470
|
+
|
|
429
471
|
private func detectKnownApp(in input: String) -> String? {
|
|
430
472
|
for app in knownApps() {
|
|
431
473
|
let lower = app.lowercased()
|
|
@@ -601,7 +643,7 @@ final class VoiceIntentResolver {
|
|
|
601
643
|
"search": ["find", "search", "look for", "where is", "where d", "locate", "lost", "show me all", "windows"],
|
|
602
644
|
"list_windows": ["what s open", "list windows", "which windows", "what do i have open"],
|
|
603
645
|
"list_sessions": ["list sessions", "what s running", "which projects", "show my sessions"],
|
|
604
|
-
"distribute": ["distribute", "spread", "organize", "arrange", "tidy", "clean up", "grid"],
|
|
646
|
+
"distribute": ["distribute", "spread", "organize", "arrange", "tidy", "clean up", "grid", "selected", "selection"],
|
|
605
647
|
"create_layer": ["create layer", "save layout", "snapshot", "remember this layout"],
|
|
606
648
|
"kill": ["kill", "stop", "shut down", "close", "terminate", "end"],
|
|
607
649
|
"scan": ["scan", "rescan", "ocr", "read the screen", "what s on my screen", "screen text"],
|
|
@@ -662,7 +704,7 @@ final class VoiceIntentResolver {
|
|
|
662
704
|
"search": ["where d my slack go", "pull up everything with dewey in it", "show me all the chrome windows", "dewey"],
|
|
663
705
|
"list_windows": ["what do i have open", "what windows do i have"],
|
|
664
706
|
"list_sessions": ["show me my sessions", "which projects are active"],
|
|
665
|
-
"distribute": ["tidy up", "line everything up", "clean up the windows"],
|
|
707
|
+
"distribute": ["tidy up", "line everything up", "clean up the windows", "grid that in the bottom half", "arrange the selected windows"],
|
|
666
708
|
"create_layer": ["snapshot this", "remember this layout"],
|
|
667
709
|
"kill": ["close the dewey session", "stop my session"],
|
|
668
710
|
"scan": ["what s on my screen", "read the screen", "give me a fresh scan"],
|
|
@@ -106,8 +106,7 @@ final class DesktopModel: ObservableObject {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
func windowForSession(_ session: String) -> WindowEntry? {
|
|
109
|
-
|
|
110
|
-
return windows.values.first { $0.title.contains(tag) }
|
|
109
|
+
SessionWindowLocator.cachedWindow(forSession: session, in: windows)
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
/// Assign a layer tag to a window (in-memory only)
|
|
@@ -205,12 +204,7 @@ final class DesktopModel: ObservableObject {
|
|
|
205
204
|
|
|
206
205
|
let spaceIds = WindowTiler.getSpacesForWindow(wid)
|
|
207
206
|
|
|
208
|
-
|
|
209
|
-
var latticesSession: String?
|
|
210
|
-
if let range = title.range(of: #"\[lattices:([^\]]+)\]"#, options: .regularExpression) {
|
|
211
|
-
let match = String(title[range])
|
|
212
|
-
latticesSession = String(match.dropFirst(9).dropLast(1)) // drop "[lattices:" and "]"
|
|
213
|
-
}
|
|
207
|
+
let latticesSession = SessionWindowLocator.extractSessionName(from: title)
|
|
214
208
|
|
|
215
209
|
var entry = WindowEntry(
|
|
216
210
|
wid: wid,
|