@lattices/cli 0.4.2 → 0.4.6
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/README.md +3 -0
- 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/Package.swift +6 -0
- package/app/Sources/AppShell/App.swift +20 -0
- package/app/Sources/{AppDelegate.swift → AppShell/AppDelegate.swift} +94 -34
- package/app/Sources/{AppShellView.swift → AppShell/AppShellView.swift} +12 -1
- package/app/Sources/AppShell/AppUpdater.swift +92 -0
- package/app/Sources/AppShell/CliActionLauncher.swift +50 -0
- package/app/Sources/{HomeDashboardView.swift → AppShell/HomeDashboardView.swift} +18 -10
- package/app/Sources/AppShell/LatticesRuntime.swift +61 -0
- package/app/Sources/{MainView.swift → AppShell/MainView.swift} +351 -191
- package/app/Sources/{OnboardingView.swift → AppShell/OnboardingView.swift} +30 -16
- package/app/Sources/{Preferences.swift → AppShell/Preferences.swift} +78 -0
- package/app/Sources/{SettingsView.swift → AppShell/SettingsView.swift} +869 -152
- package/app/Sources/{HotkeyStore.swift → Core/Actions/HotkeyStore.swift} +9 -5
- package/app/Sources/{IntentEngine.swift → Core/Actions/IntentEngine.swift} +51 -27
- package/app/Sources/Core/Actions/IntentSchema.swift +94 -0
- package/app/Sources/{Intents → Core/Actions/Intents}/LatticeIntent.swift +0 -25
- package/app/Sources/{PaletteCommand.swift → Core/Actions/PaletteCommand.swift} +26 -6
- package/app/Sources/{VoiceIntentResolver.swift → Core/Actions/VoiceIntentResolver.swift} +46 -4
- package/app/Sources/Core/Companion/CompanionActivityLog.swift +70 -0
- package/app/Sources/Core/Companion/CompanionKeyboardController.swift +141 -0
- package/app/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +438 -0
- package/app/Sources/Core/Companion/LatticesCompanionCockpit.swift +555 -0
- package/app/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +594 -0
- package/app/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +204 -0
- package/app/Sources/Core/Companion/LatticesDeckHost.swift +1463 -0
- package/app/Sources/{LatticesApi.swift → Core/Daemon/LatticesApi.swift} +125 -4
- package/app/Sources/{AppTypeClassifier.swift → Core/Desktop/AppTypeClassifier.swift} +36 -0
- package/app/Sources/{DesktopModel.swift → Core/Desktop/DesktopModel.swift} +6 -8
- package/app/Sources/Core/Desktop/MouseFinder.swift +527 -0
- package/app/Sources/Core/Desktop/SessionWindowLocator.swift +139 -0
- package/app/Sources/Core/Desktop/WindowDragSnapController.swift +628 -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} +351 -172
- package/app/Sources/Core/Input/MouseGestureConfig.swift +364 -0
- package/app/Sources/Core/Input/MouseGestureController.swift +1203 -0
- package/app/Sources/Core/Input/MouseInputDeviceStore.swift +98 -0
- package/app/Sources/Core/Input/MouseInputEventViewer.swift +272 -0
- package/app/Sources/Core/Input/MouseShortcutStore.swift +107 -0
- package/app/Sources/{CommandModeState.swift → Core/Overlays/CommandMode/CommandModeState.swift} +127 -24
- package/app/Sources/{CommandModeView.swift → Core/Overlays/CommandMode/CommandModeView.swift} +492 -79
- 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/{OmniSearchView.swift → Core/Overlays/OmniSearch/OmniSearchView.swift} +136 -2
- package/app/Sources/{OmniSearchWindow.swift → Core/Overlays/OmniSearch/OmniSearchWindow.swift} +21 -32
- package/app/Sources/Core/Overlays/OverlayPanelShell.swift +241 -0
- package/app/Sources/{ScreenMapState.swift → Core/Overlays/ScreenMap/ScreenMapState.swift} +116 -32
- package/app/Sources/{ScreenMapView.swift → Core/Overlays/ScreenMap/ScreenMapView.swift} +510 -524
- package/app/Sources/{ScreenMapWindowController.swift → Core/Overlays/ScreenMap/ScreenMapWindowController.swift} +12 -4
- package/app/Sources/{VoiceCommandWindow.swift → Core/Overlays/Voice/VoiceCommandWindow.swift} +46 -53
- package/app/Sources/Core/Pi/PiAuthNextStepCard.swift +148 -0
- package/app/Sources/Core/Pi/PiAuthPromptCard.swift +90 -0
- package/app/Sources/{PiChatDock.swift → Core/Pi/PiChatDock.swift} +137 -74
- package/app/Sources/{PiChatSession.swift → Core/Pi/PiChatSession.swift} +608 -108
- package/app/Sources/Core/Pi/PiInstallCallout.swift +86 -0
- package/app/Sources/Core/Pi/PiProviderSetupCallout.swift +99 -0
- package/app/Sources/{PiWorkspaceView.swift → Core/Pi/PiWorkspaceView.swift} +174 -77
- package/app/Sources/{PermissionChecker.swift → Core/System/PermissionChecker.swift} +76 -2
- package/app/Sources/Core/System/SystemTelemetryMonitor.swift +273 -0
- package/app/Sources/{HandsOffSession.swift → Core/Voice/HandsOffSession.swift} +15 -4
- package/app/Sources/{WorkspaceManager.swift → Core/Workspace/WorkspaceManager.swift} +288 -0
- package/bin/assistant-intelligence.ts +874 -0
- package/bin/handsoff-infer.ts +16 -209
- package/bin/handsoff-worker.ts +45 -258
- package/bin/lattices-app.ts +62 -0
- package/bin/lattices-dev +4 -0
- package/bin/lattices.ts +125 -14
- package/docs/agents.md +14 -0
- package/docs/api.md +55 -0
- package/docs/app.md +3 -0
- package/docs/companion-deck.md +180 -0
- package/docs/component-extraction-roadmap.md +392 -0
- package/docs/config.md +25 -0
- package/docs/tiling-reference.md +55 -0
- package/docs/voice-error-model.md +73 -0
- package/package.json +4 -1
- package/app/Sources/App.swift +0 -10
- package/app/Sources/CommandPaletteWindow.swift +0 -134
- package/app/Sources/MouseFinder.swift +0 -222
- /package/app/Sources/{KeyRecorderView.swift → AppShell/KeyRecorderView.swift} +0 -0
- /package/app/Sources/{MainWindow.swift → AppShell/MainWindow.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/{DaemonProtocol.swift → Core/Daemon/DaemonProtocol.swift} +0 -0
- /package/app/Sources/{DaemonServer.swift → Core/Daemon/DaemonServer.swift} +0 -0
- /package/app/Sources/{AccessibilityTextExtractor.swift → Core/Desktop/AccessibilityTextExtractor.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/{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/{AppWindowShell.swift → Core/Overlays/AppWindowShell.swift} +0 -0
- /package/app/Sources/{CommandModeWindow.swift → Core/Overlays/CommandMode/CommandModeWindow.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/{DiagnosticLog.swift → Core/System/DiagnosticLog.swift} +0 -0
- /package/app/Sources/{EventBus.swift → Core/System/EventBus.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/{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/{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
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import AppKit
|
|
2
|
-
import SwiftUI
|
|
3
|
-
|
|
4
|
-
/// NSPanel subclass that accepts key events even without a titlebar
|
|
5
|
-
private class KeyablePanel: NSPanel {
|
|
6
|
-
override var canBecomeKey: Bool { true }
|
|
7
|
-
override var canBecomeMain: Bool { true }
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
final class CommandPaletteWindow {
|
|
11
|
-
static let shared = CommandPaletteWindow()
|
|
12
|
-
|
|
13
|
-
private var panel: NSPanel?
|
|
14
|
-
private var scanner: ProjectScanner?
|
|
15
|
-
|
|
16
|
-
func configure(scanner: ProjectScanner) {
|
|
17
|
-
self.scanner = scanner
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
var isVisible: Bool { panel?.isVisible ?? false }
|
|
21
|
-
|
|
22
|
-
func toggle() {
|
|
23
|
-
if let p = panel, p.isVisible {
|
|
24
|
-
dismiss()
|
|
25
|
-
} else {
|
|
26
|
-
show()
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
func show() {
|
|
31
|
-
// Always rebuild for fresh command state
|
|
32
|
-
dismiss()
|
|
33
|
-
|
|
34
|
-
guard let scanner = scanner else { return }
|
|
35
|
-
|
|
36
|
-
// Ensure projects are up to date (full scan if list is empty,
|
|
37
|
-
// e.g. palette opened via hotkey before main popover appeared)
|
|
38
|
-
if scanner.projects.isEmpty {
|
|
39
|
-
scanner.scan()
|
|
40
|
-
} else {
|
|
41
|
-
scanner.refreshStatus()
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let commands = CommandBuilder.build(scanner: scanner)
|
|
45
|
-
let view = CommandPaletteView(commands: commands) { [weak self] in
|
|
46
|
-
self?.dismiss()
|
|
47
|
-
}
|
|
48
|
-
.preferredColorScheme(.dark)
|
|
49
|
-
|
|
50
|
-
let hosting = NSHostingView(rootView: view)
|
|
51
|
-
hosting.translatesAutoresizingMaskIntoConstraints = false
|
|
52
|
-
|
|
53
|
-
let panel = KeyablePanel(
|
|
54
|
-
contentRect: NSRect(x: 0, y: 0, width: 540, height: 440),
|
|
55
|
-
styleMask: [.nonactivatingPanel],
|
|
56
|
-
backing: .buffered,
|
|
57
|
-
defer: false
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
panel.isOpaque = false
|
|
61
|
-
panel.backgroundColor = .clear
|
|
62
|
-
panel.hasShadow = true
|
|
63
|
-
panel.level = .floating
|
|
64
|
-
panel.isMovableByWindowBackground = true
|
|
65
|
-
panel.hidesOnDeactivate = true
|
|
66
|
-
panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
|
|
67
|
-
panel.isReleasedWhenClosed = false
|
|
68
|
-
|
|
69
|
-
// Use NSVisualEffectView as contentView with a maskImage to communicate
|
|
70
|
-
// the rounded shape to the window server (layer.cornerRadius only clips
|
|
71
|
-
// at the view level — the window backing store stays rectangular)
|
|
72
|
-
let cornerRadius: CGFloat = 14
|
|
73
|
-
|
|
74
|
-
let effectView = NSVisualEffectView()
|
|
75
|
-
effectView.blendingMode = .behindWindow
|
|
76
|
-
effectView.material = .popover
|
|
77
|
-
effectView.state = .active
|
|
78
|
-
effectView.wantsLayer = true
|
|
79
|
-
effectView.maskImage = Self.maskImage(cornerRadius: cornerRadius)
|
|
80
|
-
|
|
81
|
-
panel.contentView = effectView
|
|
82
|
-
|
|
83
|
-
effectView.addSubview(hosting)
|
|
84
|
-
NSLayoutConstraint.activate([
|
|
85
|
-
hosting.leadingAnchor.constraint(equalTo: effectView.leadingAnchor),
|
|
86
|
-
hosting.trailingAnchor.constraint(equalTo: effectView.trailingAnchor),
|
|
87
|
-
hosting.topAnchor.constraint(equalTo: effectView.topAnchor),
|
|
88
|
-
hosting.bottomAnchor.constraint(equalTo: effectView.bottomAnchor),
|
|
89
|
-
])
|
|
90
|
-
|
|
91
|
-
// Center horizontally, slightly above vertical center (Spotlight-style)
|
|
92
|
-
if let screen = NSScreen.main {
|
|
93
|
-
let screenFrame = screen.visibleFrame
|
|
94
|
-
let x = screenFrame.midX - 270
|
|
95
|
-
let y = screenFrame.midY - 220 + (screenFrame.height * 0.1)
|
|
96
|
-
panel.setFrameOrigin(NSPoint(x: x, y: y))
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
panel.makeKeyAndOrderFront(nil)
|
|
100
|
-
NSApp.activate(ignoringOtherApps: true)
|
|
101
|
-
|
|
102
|
-
self.panel = panel
|
|
103
|
-
AppDelegate.updateActivationPolicy()
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
func dismiss() {
|
|
107
|
-
panel?.orderOut(nil)
|
|
108
|
-
panel = nil
|
|
109
|
-
AppDelegate.updateActivationPolicy()
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/// Stretchable mask image for rounded corners — capInsets preserve the
|
|
113
|
-
/// corner arcs while the center stretches to any window size
|
|
114
|
-
private static func maskImage(cornerRadius: CGFloat) -> NSImage {
|
|
115
|
-
let edgeLength = 2.0 * cornerRadius + 1.0
|
|
116
|
-
let maskImage = NSImage(
|
|
117
|
-
size: NSSize(width: edgeLength, height: edgeLength),
|
|
118
|
-
flipped: false
|
|
119
|
-
) { rect in
|
|
120
|
-
let path = NSBezierPath(roundedRect: rect, xRadius: cornerRadius, yRadius: cornerRadius)
|
|
121
|
-
NSColor.black.set()
|
|
122
|
-
path.fill()
|
|
123
|
-
return true
|
|
124
|
-
}
|
|
125
|
-
maskImage.capInsets = NSEdgeInsets(
|
|
126
|
-
top: cornerRadius,
|
|
127
|
-
left: cornerRadius,
|
|
128
|
-
bottom: cornerRadius,
|
|
129
|
-
right: cornerRadius
|
|
130
|
-
)
|
|
131
|
-
maskImage.resizingMode = .stretch
|
|
132
|
-
return maskImage
|
|
133
|
-
}
|
|
134
|
-
}
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import AppKit
|
|
2
|
-
import CoreGraphics
|
|
3
|
-
|
|
4
|
-
/// Locates the mouse cursor with an animated sonar pulse overlay.
|
|
5
|
-
/// "Find" shows rings at the current cursor position.
|
|
6
|
-
/// "Summon" warps the cursor to screen center (or a given point).
|
|
7
|
-
final class MouseFinder {
|
|
8
|
-
static let shared = MouseFinder()
|
|
9
|
-
|
|
10
|
-
private var overlayWindows: [NSWindow] = []
|
|
11
|
-
private var dismissTimer: Timer?
|
|
12
|
-
private var animationTimer: Timer?
|
|
13
|
-
private var animationStart: CFTimeInterval = 0
|
|
14
|
-
private let animationDuration: CFTimeInterval = 1.5
|
|
15
|
-
|
|
16
|
-
// MARK: - Find (highlight current position)
|
|
17
|
-
|
|
18
|
-
func find() {
|
|
19
|
-
let pos = NSEvent.mouseLocation
|
|
20
|
-
showSonar(at: pos)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// MARK: - Summon (warp to center of the screen the mouse is on, or a specific point)
|
|
24
|
-
|
|
25
|
-
func summon(to point: CGPoint? = nil) {
|
|
26
|
-
let target: NSPoint
|
|
27
|
-
if let point {
|
|
28
|
-
target = point
|
|
29
|
-
} else {
|
|
30
|
-
let screen = mouseScreen()
|
|
31
|
-
let frame = screen.frame
|
|
32
|
-
target = NSPoint(x: frame.midX, y: frame.midY)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// CGWarpMouseCursorPosition uses top-left origin
|
|
36
|
-
let primaryHeight = NSScreen.screens.first?.frame.height ?? 0
|
|
37
|
-
let cgPoint = CGPoint(x: target.x, y: primaryHeight - target.y)
|
|
38
|
-
CGWarpMouseCursorPosition(cgPoint)
|
|
39
|
-
// Re-associate mouse with cursor position after warp
|
|
40
|
-
CGAssociateMouseAndMouseCursorPosition(1)
|
|
41
|
-
|
|
42
|
-
showSonar(at: target)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// MARK: - Sonar Animation
|
|
46
|
-
|
|
47
|
-
private func showSonar(at nsPoint: NSPoint) {
|
|
48
|
-
dismiss()
|
|
49
|
-
|
|
50
|
-
let screens = NSScreen.screens
|
|
51
|
-
guard !screens.isEmpty else { return }
|
|
52
|
-
|
|
53
|
-
let ringCount = 3
|
|
54
|
-
let maxRadius: CGFloat = 120
|
|
55
|
-
let totalSize = maxRadius * 2 + 20
|
|
56
|
-
|
|
57
|
-
for screen in screens {
|
|
58
|
-
// Only show on screens near the cursor
|
|
59
|
-
let extendedBounds = screen.frame.insetBy(dx: -maxRadius, dy: -maxRadius)
|
|
60
|
-
guard extendedBounds.contains(nsPoint) else { continue }
|
|
61
|
-
|
|
62
|
-
let windowFrame = NSRect(
|
|
63
|
-
x: nsPoint.x - totalSize / 2,
|
|
64
|
-
y: nsPoint.y - totalSize / 2,
|
|
65
|
-
width: totalSize,
|
|
66
|
-
height: totalSize
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
let window = NSWindow(
|
|
70
|
-
contentRect: windowFrame,
|
|
71
|
-
styleMask: .borderless,
|
|
72
|
-
backing: .buffered,
|
|
73
|
-
defer: false
|
|
74
|
-
)
|
|
75
|
-
window.isOpaque = false
|
|
76
|
-
window.backgroundColor = .clear
|
|
77
|
-
window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
|
|
78
|
-
window.hasShadow = false
|
|
79
|
-
window.ignoresMouseEvents = true
|
|
80
|
-
window.collectionBehavior = [.canJoinAllSpaces, .stationary]
|
|
81
|
-
|
|
82
|
-
let sonarView = SonarView(
|
|
83
|
-
frame: NSRect(origin: .zero, size: windowFrame.size),
|
|
84
|
-
ringCount: ringCount,
|
|
85
|
-
maxRadius: maxRadius
|
|
86
|
-
)
|
|
87
|
-
window.contentView = sonarView
|
|
88
|
-
|
|
89
|
-
window.alphaValue = 0
|
|
90
|
-
window.orderFrontRegardless()
|
|
91
|
-
overlayWindows.append(window)
|
|
92
|
-
|
|
93
|
-
// Fade in
|
|
94
|
-
NSAnimationContext.runAnimationGroup { ctx in
|
|
95
|
-
ctx.duration = 0.1
|
|
96
|
-
window.animator().alphaValue = 1.0
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Animate the rings expanding using CACurrentMediaTime for state
|
|
101
|
-
animationStart = CACurrentMediaTime()
|
|
102
|
-
let interval = 1.0 / 60.0
|
|
103
|
-
|
|
104
|
-
animationTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { [weak self] timer in
|
|
105
|
-
guard let self else { timer.invalidate(); return }
|
|
106
|
-
let elapsed = CACurrentMediaTime() - self.animationStart
|
|
107
|
-
let progress = CGFloat(min(elapsed / self.animationDuration, 1.0))
|
|
108
|
-
|
|
109
|
-
for window in self.overlayWindows {
|
|
110
|
-
(window.contentView as? SonarView)?.progress = progress
|
|
111
|
-
window.contentView?.needsDisplay = true
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if progress >= 1.0 {
|
|
115
|
-
timer.invalidate()
|
|
116
|
-
self.animationTimer = nil
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Auto-dismiss after animation + hold
|
|
121
|
-
dismissTimer = Timer.scheduledTimer(withTimeInterval: 2.5, repeats: false) { [weak self] _ in
|
|
122
|
-
self?.fadeOut()
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private func fadeOut() {
|
|
127
|
-
let windows = overlayWindows
|
|
128
|
-
NSAnimationContext.runAnimationGroup({ ctx in
|
|
129
|
-
ctx.duration = 0.4
|
|
130
|
-
for window in windows {
|
|
131
|
-
window.animator().alphaValue = 0
|
|
132
|
-
}
|
|
133
|
-
}, completionHandler: { [weak self] in
|
|
134
|
-
self?.dismiss()
|
|
135
|
-
})
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
func dismiss() {
|
|
139
|
-
animationTimer?.invalidate()
|
|
140
|
-
animationTimer = nil
|
|
141
|
-
dismissTimer?.invalidate()
|
|
142
|
-
dismissTimer = nil
|
|
143
|
-
for window in overlayWindows {
|
|
144
|
-
window.orderOut(nil)
|
|
145
|
-
}
|
|
146
|
-
overlayWindows.removeAll()
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
private func mouseScreen() -> NSScreen {
|
|
150
|
-
let pos = NSEvent.mouseLocation
|
|
151
|
-
return NSScreen.screens.first(where: { $0.frame.contains(pos) }) ?? NSScreen.screens[0]
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// MARK: - Sonar Ring View
|
|
156
|
-
|
|
157
|
-
private class SonarView: NSView {
|
|
158
|
-
let ringCount: Int
|
|
159
|
-
let maxRadius: CGFloat
|
|
160
|
-
var progress: CGFloat = 0
|
|
161
|
-
|
|
162
|
-
init(frame: NSRect, ringCount: Int, maxRadius: CGFloat) {
|
|
163
|
-
self.ringCount = ringCount
|
|
164
|
-
self.maxRadius = maxRadius
|
|
165
|
-
super.init(frame: frame)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
required init?(coder: NSCoder) { fatalError() }
|
|
169
|
-
|
|
170
|
-
override func draw(_ dirtyRect: NSRect) {
|
|
171
|
-
guard let ctx = NSGraphicsContext.current?.cgContext else { return }
|
|
172
|
-
|
|
173
|
-
let center = CGPoint(x: bounds.midX, y: bounds.midY)
|
|
174
|
-
|
|
175
|
-
// Draw rings from outermost to innermost
|
|
176
|
-
for i in 0..<ringCount {
|
|
177
|
-
let ringDelay = CGFloat(i) * 0.15
|
|
178
|
-
let denom = 1.0 - ringDelay * CGFloat(ringCount - 1) / CGFloat(ringCount)
|
|
179
|
-
let ringProgress = max(0, min(1, (progress - ringDelay) / denom))
|
|
180
|
-
|
|
181
|
-
guard ringProgress > 0 else { continue }
|
|
182
|
-
|
|
183
|
-
// Ease out cubic
|
|
184
|
-
let eased = 1.0 - pow(1.0 - ringProgress, 3)
|
|
185
|
-
|
|
186
|
-
let radius = maxRadius * eased
|
|
187
|
-
let alpha = (1.0 - eased) * 0.8
|
|
188
|
-
|
|
189
|
-
// Ring stroke
|
|
190
|
-
ctx.setStrokeColor(NSColor(calibratedRed: 0.4, green: 0.7, blue: 1.0, alpha: alpha).cgColor)
|
|
191
|
-
ctx.setLineWidth(2.5 - CGFloat(i) * 0.5)
|
|
192
|
-
ctx.addEllipse(in: CGRect(
|
|
193
|
-
x: center.x - radius,
|
|
194
|
-
y: center.y - radius,
|
|
195
|
-
width: radius * 2,
|
|
196
|
-
height: radius * 2
|
|
197
|
-
))
|
|
198
|
-
ctx.strokePath()
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Center dot — stays visible
|
|
202
|
-
let dotRadius: CGFloat = 6
|
|
203
|
-
let dotAlpha = max(0.3, 1.0 - progress * 0.5)
|
|
204
|
-
ctx.setFillColor(NSColor(calibratedRed: 0.4, green: 0.7, blue: 1.0, alpha: dotAlpha).cgColor)
|
|
205
|
-
ctx.fillEllipse(in: CGRect(
|
|
206
|
-
x: center.x - dotRadius,
|
|
207
|
-
y: center.y - dotRadius,
|
|
208
|
-
width: dotRadius * 2,
|
|
209
|
-
height: dotRadius * 2
|
|
210
|
-
))
|
|
211
|
-
|
|
212
|
-
// Outer glow on center dot
|
|
213
|
-
ctx.setFillColor(NSColor(calibratedRed: 0.4, green: 0.7, blue: 1.0, alpha: dotAlpha * 0.2).cgColor)
|
|
214
|
-
let glowRadius: CGFloat = 12
|
|
215
|
-
ctx.fillEllipse(in: CGRect(
|
|
216
|
-
x: center.x - glowRadius,
|
|
217
|
-
y: center.y - glowRadius,
|
|
218
|
-
width: glowRadius * 2,
|
|
219
|
-
height: glowRadius * 2
|
|
220
|
-
))
|
|
221
|
-
}
|
|
222
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/app/Sources/{CommandModeWindow.swift → Core/Overlays/CommandMode/CommandModeWindow.swift}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/app/Sources/{OmniSearchState.swift → Core/Overlays/OmniSearch/OmniSearchState.swift}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/app/Sources/{TerminalSynthesizer.swift → Core/Workspace/Terminal/TerminalSynthesizer.swift}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|