@lattices/cli 0.3.0 → 0.4.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.
- package/README.md +85 -9
- package/app/Package.swift +8 -1
- package/app/Sources/AdvisorLearningStore.swift +90 -0
- package/app/Sources/AgentSession.swift +377 -0
- package/app/Sources/AppDelegate.swift +44 -12
- package/app/Sources/AppShellView.swift +81 -8
- package/app/Sources/AudioProvider.swift +386 -0
- package/app/Sources/CheatSheetHUD.swift +261 -19
- package/app/Sources/DaemonProtocol.swift +13 -0
- package/app/Sources/DaemonServer.swift +8 -0
- package/app/Sources/DesktopModel.swift +164 -5
- package/app/Sources/DesktopModelTypes.swift +2 -0
- package/app/Sources/DiagnosticLog.swift +104 -2
- package/app/Sources/EventBus.swift +1 -0
- package/app/Sources/HUDBottomBar.swift +279 -0
- package/app/Sources/HUDController.swift +1158 -0
- package/app/Sources/HUDLeftBar.swift +849 -0
- package/app/Sources/HUDMinimap.swift +179 -0
- package/app/Sources/HUDRightBar.swift +774 -0
- package/app/Sources/HUDState.swift +367 -0
- package/app/Sources/HUDTopBar.swift +243 -0
- package/app/Sources/HandsOffSession.swift +733 -0
- package/app/Sources/HomeDashboardView.swift +125 -0
- package/app/Sources/HotkeyManager.swift +2 -0
- package/app/Sources/HotkeyStore.swift +45 -9
- package/app/Sources/IntentEngine.swift +925 -0
- package/app/Sources/Intents/CreateLayerIntent.swift +54 -0
- package/app/Sources/Intents/DistributeIntent.swift +56 -0
- package/app/Sources/Intents/FocusIntent.swift +69 -0
- package/app/Sources/Intents/HelpIntent.swift +41 -0
- package/app/Sources/Intents/KillIntent.swift +47 -0
- package/app/Sources/Intents/LatticeIntent.swift +78 -0
- package/app/Sources/Intents/LaunchIntent.swift +67 -0
- package/app/Sources/Intents/ListSessionsIntent.swift +32 -0
- package/app/Sources/Intents/ListWindowsIntent.swift +30 -0
- package/app/Sources/Intents/ScanIntent.swift +52 -0
- package/app/Sources/Intents/SearchIntent.swift +190 -0
- package/app/Sources/Intents/SwitchLayerIntent.swift +50 -0
- package/app/Sources/Intents/TileIntent.swift +61 -0
- package/app/Sources/LatticesApi.swift +1235 -30
- package/app/Sources/LauncherHUD.swift +348 -0
- package/app/Sources/MainView.swift +147 -44
- package/app/Sources/OcrModel.swift +34 -1
- package/app/Sources/OmniSearchState.swift +99 -102
- package/app/Sources/OnboardingView.swift +457 -0
- package/app/Sources/PermissionChecker.swift +2 -12
- package/app/Sources/PiChatDock.swift +454 -0
- package/app/Sources/PiChatSession.swift +815 -0
- package/app/Sources/PiWorkspaceView.swift +364 -0
- package/app/Sources/PlacementSpec.swift +195 -0
- package/app/Sources/Preferences.swift +59 -0
- package/app/Sources/ProjectScanner.swift +1 -1
- package/app/Sources/ScreenMapState.swift +701 -55
- package/app/Sources/ScreenMapView.swift +843 -103
- package/app/Sources/ScreenMapWindowController.swift +22 -0
- package/app/Sources/SessionLayerStore.swift +285 -0
- package/app/Sources/SessionManager.swift +4 -1
- package/app/Sources/SettingsView.swift +186 -3
- package/app/Sources/Theme.swift +9 -8
- package/app/Sources/TmuxModel.swift +7 -0
- package/app/Sources/TmuxQuery.swift +27 -3
- package/app/Sources/VoiceChatView.swift +192 -0
- package/app/Sources/VoiceCommandWindow.swift +1594 -0
- package/app/Sources/VoiceIntentResolver.swift +671 -0
- package/app/Sources/VoxClient.swift +454 -0
- package/app/Sources/WindowTiler.swift +348 -87
- package/app/Sources/WorkspaceManager.swift +127 -18
- package/bin/client.ts +16 -0
- package/bin/{daemon-client.js → daemon-client.ts} +49 -30
- package/bin/handsoff-infer.ts +280 -0
- package/bin/handsoff-worker.ts +731 -0
- package/bin/{lattices-app.js → lattices-app.ts} +67 -32
- package/bin/lattices-dev +160 -0
- package/bin/{lattices.js → lattices.ts} +600 -137
- package/bin/project-twin.ts +645 -0
- package/docs/agent-execution-plan.md +562 -0
- package/docs/agents.md +142 -0
- package/docs/api.md +153 -34
- package/docs/app.md +29 -1
- package/docs/config.md +5 -1
- package/docs/handsoff-test-scenarios.md +84 -0
- package/docs/layers.md +20 -20
- package/docs/ocr.md +14 -5
- package/docs/overview.md +5 -1
- package/docs/presentation-execution-review.md +491 -0
- package/docs/prompts/hands-off-system.md +374 -0
- package/docs/prompts/hands-off-turn.md +30 -0
- package/docs/prompts/voice-advisor.md +31 -0
- package/docs/prompts/voice-fallback.md +23 -0
- package/docs/tiling-reference.md +167 -0
- package/docs/twins.md +138 -0
- package/docs/voice-command-protocol.md +278 -0
- package/docs/voice.md +219 -0
- package/package.json +21 -10
- package/bin/client.js +0 -4
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
// MARK: - HUDMinimap (expanded canvas-attached minimap)
|
|
4
|
+
|
|
5
|
+
struct HUDMinimap: View {
|
|
6
|
+
@ObservedObject var state: HUDState
|
|
7
|
+
@ObservedObject private var desktop = DesktopModel.shared
|
|
8
|
+
var onDismiss: () -> Void
|
|
9
|
+
let screenIndex: Int
|
|
10
|
+
|
|
11
|
+
var body: some View {
|
|
12
|
+
VStack(alignment: .leading, spacing: 0) {
|
|
13
|
+
// Header
|
|
14
|
+
HStack(spacing: 0) {
|
|
15
|
+
Image(systemName: screenIndex == 0 ? "display" : "rectangle.on.rectangle")
|
|
16
|
+
.font(.system(size: 10))
|
|
17
|
+
.foregroundColor(Palette.textMuted)
|
|
18
|
+
Text(screenIndex == 0 ? "Main" : "Display \(screenIndex + 1)")
|
|
19
|
+
.font(Typo.monoBold(10))
|
|
20
|
+
.foregroundColor(Palette.textMuted)
|
|
21
|
+
.padding(.leading, 4)
|
|
22
|
+
|
|
23
|
+
Spacer()
|
|
24
|
+
|
|
25
|
+
// Dock back into sidebar
|
|
26
|
+
Button {
|
|
27
|
+
state.minimapMode = .docked
|
|
28
|
+
} label: {
|
|
29
|
+
Image(systemName: "arrow.down.right.and.arrow.up.left")
|
|
30
|
+
.font(.system(size: 8, weight: .bold))
|
|
31
|
+
.foregroundColor(Palette.textMuted)
|
|
32
|
+
.frame(width: 20, height: 20)
|
|
33
|
+
.background(
|
|
34
|
+
RoundedRectangle(cornerRadius: 3)
|
|
35
|
+
.fill(Palette.surface)
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
.buttonStyle(.plain)
|
|
39
|
+
.help("Dock map (M)")
|
|
40
|
+
}
|
|
41
|
+
.padding(.horizontal, 12)
|
|
42
|
+
.padding(.top, 10)
|
|
43
|
+
.padding(.bottom, 6)
|
|
44
|
+
|
|
45
|
+
// Map canvas (larger in expanded mode)
|
|
46
|
+
mapCanvas
|
|
47
|
+
.padding(.horizontal, 10)
|
|
48
|
+
.padding(.bottom, 10)
|
|
49
|
+
}
|
|
50
|
+
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
51
|
+
.background(Palette.bg)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// MARK: - Map canvas
|
|
55
|
+
|
|
56
|
+
private var mapCanvas: some View {
|
|
57
|
+
GeometryReader { geo in
|
|
58
|
+
let screens = NSScreen.screens
|
|
59
|
+
let idx = clampedIndex
|
|
60
|
+
if idx < screens.count {
|
|
61
|
+
let screen = screens[idx]
|
|
62
|
+
let sw = screen.frame.width
|
|
63
|
+
let sh = screen.frame.height
|
|
64
|
+
let canvasW = geo.size.width
|
|
65
|
+
let canvasH = geo.size.height
|
|
66
|
+
|
|
67
|
+
let scaleX = canvasW / sw
|
|
68
|
+
let scaleY = canvasH / sh
|
|
69
|
+
let scale = min(scaleX, scaleY)
|
|
70
|
+
let drawW = sw * scale
|
|
71
|
+
let drawH = sh * scale
|
|
72
|
+
let offsetX = (canvasW - drawW) / 2
|
|
73
|
+
let offsetY = (canvasH - drawH) / 2
|
|
74
|
+
|
|
75
|
+
let origin = screenCGOrigin(screen)
|
|
76
|
+
let wins = windowsOnScreen(idx)
|
|
77
|
+
|
|
78
|
+
ZStack(alignment: .topLeading) {
|
|
79
|
+
// Screen background
|
|
80
|
+
RoundedRectangle(cornerRadius: 6)
|
|
81
|
+
.fill(Palette.surface.opacity(0.4))
|
|
82
|
+
.frame(width: drawW, height: drawH)
|
|
83
|
+
.offset(x: offsetX, y: offsetY)
|
|
84
|
+
|
|
85
|
+
// Windows (back-to-front)
|
|
86
|
+
ForEach(wins.reversed()) { win in
|
|
87
|
+
let rx = (CGFloat(win.frame.x) - origin.x) * scale + offsetX
|
|
88
|
+
let ry = (CGFloat(win.frame.y) - origin.y) * scale + offsetY
|
|
89
|
+
let rw = CGFloat(win.frame.w) * scale
|
|
90
|
+
let rh = CGFloat(win.frame.h) * scale
|
|
91
|
+
let isSelected = state.selectedItem == .window(win)
|
|
92
|
+
|
|
93
|
+
RoundedRectangle(cornerRadius: 2)
|
|
94
|
+
.fill(appColor(win.app).opacity(isSelected ? 0.5 : 0.15))
|
|
95
|
+
.overlay(
|
|
96
|
+
RoundedRectangle(cornerRadius: 2)
|
|
97
|
+
.strokeBorder(
|
|
98
|
+
isSelected ? Palette.running : appColor(win.app).opacity(0.35),
|
|
99
|
+
lineWidth: isSelected ? 1.5 : 0.5
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
.overlay(
|
|
103
|
+
Group {
|
|
104
|
+
if rw > 30 && rh > 18 {
|
|
105
|
+
VStack(spacing: 1) {
|
|
106
|
+
Text(String(win.app.prefix(1)))
|
|
107
|
+
.font(Typo.geistMonoBold(max(7, min(11, rh * 0.3))))
|
|
108
|
+
.foregroundColor(appColor(win.app).opacity(isSelected ? 1.0 : 0.5))
|
|
109
|
+
if rh > 30 && rw > 50 {
|
|
110
|
+
Text(win.title.prefix(12).description)
|
|
111
|
+
.font(Typo.mono(max(5, min(7, rh * 0.12))))
|
|
112
|
+
.foregroundColor(Palette.textDim.opacity(0.6))
|
|
113
|
+
.lineLimit(1)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
.frame(width: max(rw, 4), height: max(rh, 3))
|
|
120
|
+
.offset(x: rx, y: ry)
|
|
121
|
+
.onTapGesture {
|
|
122
|
+
state.selectedItem = .window(win)
|
|
123
|
+
state.focus = .list
|
|
124
|
+
if let flatIdx = state.flatItems.firstIndex(of: .window(win)) {
|
|
125
|
+
state.selectedIndex = flatIdx
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
.frame(width: canvasW, height: canvasH)
|
|
131
|
+
.clipShape(RoundedRectangle(cornerRadius: 6))
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// MARK: - Helpers
|
|
137
|
+
|
|
138
|
+
private var clampedIndex: Int {
|
|
139
|
+
min(screenIndex, NSScreen.screens.count - 1)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private func screenCGOrigin(_ screen: NSScreen) -> (x: CGFloat, y: CGFloat) {
|
|
143
|
+
let primaryH = NSScreen.screens.first?.frame.height ?? 900
|
|
144
|
+
return (screen.frame.origin.x, primaryH - screen.frame.origin.y - screen.frame.height)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private func windowsOnScreen(_ screenIdx: Int) -> [WindowEntry] {
|
|
148
|
+
let screens = NSScreen.screens
|
|
149
|
+
guard screenIdx < screens.count else { return [] }
|
|
150
|
+
let screen = screens[screenIdx]
|
|
151
|
+
let origin = screenCGOrigin(screen)
|
|
152
|
+
let sw = Double(screen.frame.width)
|
|
153
|
+
let sh = Double(screen.frame.height)
|
|
154
|
+
|
|
155
|
+
return desktop.allWindows().filter { win in
|
|
156
|
+
let cx = win.frame.x + win.frame.w / 2
|
|
157
|
+
let cy = win.frame.y + win.frame.h / 2
|
|
158
|
+
return cx >= Double(origin.x) && cx < Double(origin.x) + sw &&
|
|
159
|
+
cy >= Double(origin.y) && cy < Double(origin.y) + sh &&
|
|
160
|
+
win.app != "Lattices"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private func appColor(_ app: String) -> Color {
|
|
165
|
+
if ["iTerm2", "Terminal", "WezTerm", "Alacritty", "kitty"].contains(app) {
|
|
166
|
+
return Palette.running
|
|
167
|
+
}
|
|
168
|
+
if ["Google Chrome", "Safari", "Arc", "Firefox", "Brave Browser"].contains(app) {
|
|
169
|
+
return Color.blue
|
|
170
|
+
}
|
|
171
|
+
if ["Xcode", "Visual Studio Code", "Cursor", "Zed"].contains(app) {
|
|
172
|
+
return Color.purple
|
|
173
|
+
}
|
|
174
|
+
if app.localizedCaseInsensitiveContains("Claude") || app.localizedCaseInsensitiveContains("Codex") {
|
|
175
|
+
return Color.orange
|
|
176
|
+
}
|
|
177
|
+
return Palette.textMuted
|
|
178
|
+
}
|
|
179
|
+
}
|