@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,192 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
/// A scrolling chat log for voice mode. Shows the running conversation between
|
|
4
|
+
/// user (transcripts), assistant (spoken responses), and system (silent info like
|
|
5
|
+
/// executed actions or search results).
|
|
6
|
+
///
|
|
7
|
+
/// Embeddable in both the standalone voice bar and the full HUD.
|
|
8
|
+
struct VoiceChatView: View {
|
|
9
|
+
@ObservedObject var session: HandsOffSession
|
|
10
|
+
|
|
11
|
+
var body: some View {
|
|
12
|
+
ScrollViewReader { proxy in
|
|
13
|
+
ScrollView(.vertical, showsIndicators: false) {
|
|
14
|
+
LazyVStack(alignment: .leading, spacing: 6) {
|
|
15
|
+
ForEach(session.chatLog) { entry in
|
|
16
|
+
chatBubble(entry)
|
|
17
|
+
.id(entry.id)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Live state indicator
|
|
21
|
+
if session.state == .listening {
|
|
22
|
+
listeningIndicator
|
|
23
|
+
} else if session.state == .thinking {
|
|
24
|
+
thinkingIndicator
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
.padding(.horizontal, 12)
|
|
28
|
+
.padding(.vertical, 8)
|
|
29
|
+
}
|
|
30
|
+
.onChange(of: session.chatLog.count) { _ in
|
|
31
|
+
// Auto-scroll to bottom
|
|
32
|
+
if let last = session.chatLog.last {
|
|
33
|
+
withAnimation(.easeOut(duration: 0.15)) {
|
|
34
|
+
proxy.scrollTo(last.id, anchor: .bottom)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// MARK: - Chat bubble
|
|
42
|
+
|
|
43
|
+
@ViewBuilder
|
|
44
|
+
private func chatBubble(_ entry: VoiceChatEntry) -> some View {
|
|
45
|
+
switch entry.role {
|
|
46
|
+
case .user:
|
|
47
|
+
HStack(alignment: .top, spacing: 6) {
|
|
48
|
+
Text("you")
|
|
49
|
+
.font(Typo.monoBold(9))
|
|
50
|
+
.foregroundColor(Palette.text)
|
|
51
|
+
.frame(width: 28, alignment: .trailing)
|
|
52
|
+
Text(entry.text)
|
|
53
|
+
.font(Typo.mono(11))
|
|
54
|
+
.foregroundColor(Palette.text)
|
|
55
|
+
.textSelection(.enabled)
|
|
56
|
+
Spacer(minLength: 0)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
case .assistant:
|
|
60
|
+
HStack(alignment: .top, spacing: 6) {
|
|
61
|
+
Text("lat")
|
|
62
|
+
.font(Typo.monoBold(9))
|
|
63
|
+
.foregroundColor(Palette.running)
|
|
64
|
+
.frame(width: 28, alignment: .trailing)
|
|
65
|
+
Text(entry.text)
|
|
66
|
+
.font(Typo.mono(11))
|
|
67
|
+
.foregroundColor(Palette.textMuted)
|
|
68
|
+
.textSelection(.enabled)
|
|
69
|
+
Spacer(minLength: 0)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
case .system:
|
|
73
|
+
HStack(alignment: .top, spacing: 6) {
|
|
74
|
+
Image(systemName: "bolt.fill")
|
|
75
|
+
.font(.system(size: 7))
|
|
76
|
+
.foregroundColor(Palette.running.opacity(0.6))
|
|
77
|
+
.frame(width: 28, alignment: .trailing)
|
|
78
|
+
Text(entry.text)
|
|
79
|
+
.font(Typo.mono(9))
|
|
80
|
+
.foregroundColor(Palette.textDim)
|
|
81
|
+
.textSelection(.enabled)
|
|
82
|
+
if let detail = entry.detail {
|
|
83
|
+
Text(detail)
|
|
84
|
+
.font(Typo.mono(9))
|
|
85
|
+
.foregroundColor(Palette.textDim.opacity(0.6))
|
|
86
|
+
}
|
|
87
|
+
Spacer(minLength: 0)
|
|
88
|
+
}
|
|
89
|
+
.opacity(0.7)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// MARK: - Live indicators
|
|
94
|
+
|
|
95
|
+
private var listeningIndicator: some View {
|
|
96
|
+
HStack(spacing: 6) {
|
|
97
|
+
Text("you")
|
|
98
|
+
.font(Typo.monoBold(9))
|
|
99
|
+
.foregroundColor(Palette.text)
|
|
100
|
+
.frame(width: 28, alignment: .trailing)
|
|
101
|
+
|
|
102
|
+
if let partial = session.lastTranscript, session.state == .listening {
|
|
103
|
+
Text(partial)
|
|
104
|
+
.font(Typo.mono(11))
|
|
105
|
+
.foregroundColor(Palette.text.opacity(0.5))
|
|
106
|
+
} else {
|
|
107
|
+
HStack(spacing: 3) {
|
|
108
|
+
ForEach(0..<3, id: \.self) { i in
|
|
109
|
+
Circle()
|
|
110
|
+
.fill(Palette.text)
|
|
111
|
+
.frame(width: 4, height: 4)
|
|
112
|
+
.opacity(0.4)
|
|
113
|
+
.animation(
|
|
114
|
+
.easeInOut(duration: 0.5)
|
|
115
|
+
.repeatForever()
|
|
116
|
+
.delay(Double(i) * 0.15),
|
|
117
|
+
value: session.state
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
Spacer(minLength: 0)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private var thinkingIndicator: some View {
|
|
127
|
+
HStack(spacing: 6) {
|
|
128
|
+
Text("lat")
|
|
129
|
+
.font(Typo.monoBold(9))
|
|
130
|
+
.foregroundColor(Palette.running)
|
|
131
|
+
.frame(width: 28, alignment: .trailing)
|
|
132
|
+
HStack(spacing: 3) {
|
|
133
|
+
ForEach(0..<3, id: \.self) { i in
|
|
134
|
+
Circle()
|
|
135
|
+
.fill(Palette.running)
|
|
136
|
+
.frame(width: 4, height: 4)
|
|
137
|
+
.opacity(0.4)
|
|
138
|
+
.animation(
|
|
139
|
+
.easeInOut(duration: 0.5)
|
|
140
|
+
.repeatForever()
|
|
141
|
+
.delay(Double(i) * 0.15),
|
|
142
|
+
value: session.state
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
Spacer(minLength: 0)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// MARK: - Compact variant (for top/bottom bar embedding)
|
|
152
|
+
|
|
153
|
+
struct VoiceChatCompact: View {
|
|
154
|
+
@ObservedObject var session: HandsOffSession
|
|
155
|
+
/// How many recent entries to show
|
|
156
|
+
var maxEntries: Int = 3
|
|
157
|
+
|
|
158
|
+
var body: some View {
|
|
159
|
+
VStack(alignment: .leading, spacing: 3) {
|
|
160
|
+
ForEach(Array(session.chatLog.suffix(maxEntries))) { entry in
|
|
161
|
+
HStack(spacing: 4) {
|
|
162
|
+
switch entry.role {
|
|
163
|
+
case .user:
|
|
164
|
+
Text("you")
|
|
165
|
+
.font(Typo.monoBold(8))
|
|
166
|
+
.foregroundColor(Palette.text)
|
|
167
|
+
Text(entry.text)
|
|
168
|
+
.font(Typo.mono(9))
|
|
169
|
+
.foregroundColor(Palette.text)
|
|
170
|
+
.lineLimit(1)
|
|
171
|
+
case .assistant:
|
|
172
|
+
Text("→")
|
|
173
|
+
.font(Typo.mono(9))
|
|
174
|
+
.foregroundColor(Palette.running)
|
|
175
|
+
Text(entry.text)
|
|
176
|
+
.font(Typo.mono(9))
|
|
177
|
+
.foregroundColor(Palette.textMuted)
|
|
178
|
+
.lineLimit(1)
|
|
179
|
+
case .system:
|
|
180
|
+
Text("⚡")
|
|
181
|
+
.font(.system(size: 7))
|
|
182
|
+
Text(entry.text)
|
|
183
|
+
.font(Typo.mono(8))
|
|
184
|
+
.foregroundColor(Palette.textDim)
|
|
185
|
+
.lineLimit(1)
|
|
186
|
+
}
|
|
187
|
+
Spacer(minLength: 0)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|