@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.
Files changed (95) hide show
  1. package/README.md +85 -9
  2. package/app/Package.swift +8 -1
  3. package/app/Sources/AdvisorLearningStore.swift +90 -0
  4. package/app/Sources/AgentSession.swift +377 -0
  5. package/app/Sources/AppDelegate.swift +44 -12
  6. package/app/Sources/AppShellView.swift +81 -8
  7. package/app/Sources/AudioProvider.swift +386 -0
  8. package/app/Sources/CheatSheetHUD.swift +261 -19
  9. package/app/Sources/DaemonProtocol.swift +13 -0
  10. package/app/Sources/DaemonServer.swift +8 -0
  11. package/app/Sources/DesktopModel.swift +164 -5
  12. package/app/Sources/DesktopModelTypes.swift +2 -0
  13. package/app/Sources/DiagnosticLog.swift +104 -2
  14. package/app/Sources/EventBus.swift +1 -0
  15. package/app/Sources/HUDBottomBar.swift +279 -0
  16. package/app/Sources/HUDController.swift +1158 -0
  17. package/app/Sources/HUDLeftBar.swift +849 -0
  18. package/app/Sources/HUDMinimap.swift +179 -0
  19. package/app/Sources/HUDRightBar.swift +774 -0
  20. package/app/Sources/HUDState.swift +367 -0
  21. package/app/Sources/HUDTopBar.swift +243 -0
  22. package/app/Sources/HandsOffSession.swift +733 -0
  23. package/app/Sources/HomeDashboardView.swift +125 -0
  24. package/app/Sources/HotkeyManager.swift +2 -0
  25. package/app/Sources/HotkeyStore.swift +45 -9
  26. package/app/Sources/IntentEngine.swift +925 -0
  27. package/app/Sources/Intents/CreateLayerIntent.swift +54 -0
  28. package/app/Sources/Intents/DistributeIntent.swift +56 -0
  29. package/app/Sources/Intents/FocusIntent.swift +69 -0
  30. package/app/Sources/Intents/HelpIntent.swift +41 -0
  31. package/app/Sources/Intents/KillIntent.swift +47 -0
  32. package/app/Sources/Intents/LatticeIntent.swift +78 -0
  33. package/app/Sources/Intents/LaunchIntent.swift +67 -0
  34. package/app/Sources/Intents/ListSessionsIntent.swift +32 -0
  35. package/app/Sources/Intents/ListWindowsIntent.swift +30 -0
  36. package/app/Sources/Intents/ScanIntent.swift +52 -0
  37. package/app/Sources/Intents/SearchIntent.swift +190 -0
  38. package/app/Sources/Intents/SwitchLayerIntent.swift +50 -0
  39. package/app/Sources/Intents/TileIntent.swift +61 -0
  40. package/app/Sources/LatticesApi.swift +1235 -30
  41. package/app/Sources/LauncherHUD.swift +348 -0
  42. package/app/Sources/MainView.swift +147 -44
  43. package/app/Sources/OcrModel.swift +34 -1
  44. package/app/Sources/OmniSearchState.swift +99 -102
  45. package/app/Sources/OnboardingView.swift +457 -0
  46. package/app/Sources/PermissionChecker.swift +2 -12
  47. package/app/Sources/PiChatDock.swift +454 -0
  48. package/app/Sources/PiChatSession.swift +815 -0
  49. package/app/Sources/PiWorkspaceView.swift +364 -0
  50. package/app/Sources/PlacementSpec.swift +195 -0
  51. package/app/Sources/Preferences.swift +59 -0
  52. package/app/Sources/ProjectScanner.swift +1 -1
  53. package/app/Sources/ScreenMapState.swift +701 -55
  54. package/app/Sources/ScreenMapView.swift +843 -103
  55. package/app/Sources/ScreenMapWindowController.swift +22 -0
  56. package/app/Sources/SessionLayerStore.swift +285 -0
  57. package/app/Sources/SessionManager.swift +4 -1
  58. package/app/Sources/SettingsView.swift +186 -3
  59. package/app/Sources/Theme.swift +9 -8
  60. package/app/Sources/TmuxModel.swift +7 -0
  61. package/app/Sources/TmuxQuery.swift +27 -3
  62. package/app/Sources/VoiceChatView.swift +192 -0
  63. package/app/Sources/VoiceCommandWindow.swift +1594 -0
  64. package/app/Sources/VoiceIntentResolver.swift +671 -0
  65. package/app/Sources/VoxClient.swift +454 -0
  66. package/app/Sources/WindowTiler.swift +348 -87
  67. package/app/Sources/WorkspaceManager.swift +127 -18
  68. package/bin/client.ts +16 -0
  69. package/bin/{daemon-client.js → daemon-client.ts} +49 -30
  70. package/bin/handsoff-infer.ts +280 -0
  71. package/bin/handsoff-worker.ts +731 -0
  72. package/bin/{lattices-app.js → lattices-app.ts} +67 -32
  73. package/bin/lattices-dev +160 -0
  74. package/bin/{lattices.js → lattices.ts} +600 -137
  75. package/bin/project-twin.ts +645 -0
  76. package/docs/agent-execution-plan.md +562 -0
  77. package/docs/agents.md +142 -0
  78. package/docs/api.md +153 -34
  79. package/docs/app.md +29 -1
  80. package/docs/config.md +5 -1
  81. package/docs/handsoff-test-scenarios.md +84 -0
  82. package/docs/layers.md +20 -20
  83. package/docs/ocr.md +14 -5
  84. package/docs/overview.md +5 -1
  85. package/docs/presentation-execution-review.md +491 -0
  86. package/docs/prompts/hands-off-system.md +374 -0
  87. package/docs/prompts/hands-off-turn.md +30 -0
  88. package/docs/prompts/voice-advisor.md +31 -0
  89. package/docs/prompts/voice-fallback.md +23 -0
  90. package/docs/tiling-reference.md +167 -0
  91. package/docs/twins.md +138 -0
  92. package/docs/voice-command-protocol.md +278 -0
  93. package/docs/voice.md +219 -0
  94. package/package.json +21 -10
  95. 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
+ }