@lattices/cli 0.4.2 → 0.4.5

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 (70) hide show
  1. package/README.md +3 -0
  2. package/app/Info.plist +2 -2
  3. package/app/Lattices.app/Contents/Info.plist +2 -2
  4. package/app/Lattices.app/Contents/MacOS/Lattices +0 -0
  5. package/app/Package.swift +6 -0
  6. package/app/Sources/App.swift +10 -0
  7. package/app/Sources/AppDelegate.swift +90 -34
  8. package/app/Sources/AppShellView.swift +2 -0
  9. package/app/Sources/AppTypeClassifier.swift +36 -0
  10. package/app/Sources/AppUpdater.swift +92 -0
  11. package/app/Sources/CheatSheetHUD.swift +1 -0
  12. package/app/Sources/CliActionLauncher.swift +50 -0
  13. package/app/Sources/CommandModeView.swift +4 -24
  14. package/app/Sources/CompanionActivityLog.swift +70 -0
  15. package/app/Sources/CompanionKeyboardController.swift +141 -0
  16. package/app/Sources/DesktopModel.swift +4 -0
  17. package/app/Sources/HandsOffSession.swift +15 -4
  18. package/app/Sources/HomeDashboardView.swift +18 -10
  19. package/app/Sources/HotkeyStore.swift +8 -5
  20. package/app/Sources/IntentEngine.swift +7 -1
  21. package/app/Sources/LatticesApi.swift +125 -4
  22. package/app/Sources/LatticesCompanionBridgeServer.swift +438 -0
  23. package/app/Sources/LatticesCompanionCockpit.swift +555 -0
  24. package/app/Sources/LatticesCompanionSecurityCoordinator.swift +594 -0
  25. package/app/Sources/LatticesCompanionTrackpadController.swift +204 -0
  26. package/app/Sources/LatticesDeckHost.swift +1463 -0
  27. package/app/Sources/LatticesRuntime.swift +61 -0
  28. package/app/Sources/MainView.swift +351 -191
  29. package/app/Sources/MouseFinder.swift +335 -30
  30. package/app/Sources/MouseGestureConfig.swift +364 -0
  31. package/app/Sources/MouseGestureController.swift +1203 -0
  32. package/app/Sources/MouseInputDeviceStore.swift +98 -0
  33. package/app/Sources/MouseInputEventViewer.swift +272 -0
  34. package/app/Sources/MouseShortcutStore.swift +107 -0
  35. package/app/Sources/OmniSearchView.swift +136 -2
  36. package/app/Sources/OmniSearchWindow.swift +65 -5
  37. package/app/Sources/OnboardingView.swift +30 -16
  38. package/app/Sources/PaletteCommand.swift +26 -6
  39. package/app/Sources/PermissionChecker.swift +76 -2
  40. package/app/Sources/PiAuthNextStepCard.swift +148 -0
  41. package/app/Sources/PiAuthPromptCard.swift +90 -0
  42. package/app/Sources/PiChatDock.swift +137 -74
  43. package/app/Sources/PiChatSession.swift +608 -108
  44. package/app/Sources/PiInstallCallout.swift +86 -0
  45. package/app/Sources/PiProviderSetupCallout.swift +99 -0
  46. package/app/Sources/PiWorkspaceView.swift +174 -77
  47. package/app/Sources/Preferences.swift +78 -0
  48. package/app/Sources/ScreenMapState.swift +91 -31
  49. package/app/Sources/ScreenMapView.swift +510 -524
  50. package/app/Sources/ScreenMapWindowController.swift +12 -4
  51. package/app/Sources/SettingsView.swift +869 -152
  52. package/app/Sources/SystemTelemetryMonitor.swift +273 -0
  53. package/app/Sources/VoiceCommandWindow.swift +23 -2
  54. package/app/Sources/WindowDragSnapController.swift +628 -0
  55. package/app/Sources/WindowTiler.swift +328 -65
  56. package/app/Sources/WorkspaceManager.swift +288 -0
  57. package/bin/assistant-intelligence.ts +874 -0
  58. package/bin/handsoff-infer.ts +16 -209
  59. package/bin/handsoff-worker.ts +45 -258
  60. package/bin/lattices-app.ts +62 -0
  61. package/bin/lattices-dev +4 -0
  62. package/bin/lattices.ts +125 -14
  63. package/docs/agents.md +14 -0
  64. package/docs/api.md +55 -0
  65. package/docs/app.md +3 -0
  66. package/docs/companion-deck.md +180 -0
  67. package/docs/config.md +25 -0
  68. package/docs/tiling-reference.md +55 -0
  69. package/docs/voice-error-model.md +73 -0
  70. package/package.json +2 -1
@@ -16,7 +16,7 @@ struct PiChatDock: View {
16
16
  VStack(spacing: 0) {
17
17
  topHandle
18
18
 
19
- if session.isAuthPanelVisible {
19
+ if session.hasPiBinary && session.isAuthPanelVisible {
20
20
  Rectangle()
21
21
  .fill(Palette.border)
22
22
  .frame(height: 0.5)
@@ -34,7 +34,23 @@ struct PiChatDock: View {
34
34
  .fill(Palette.border)
35
35
  .frame(height: 0.5)
36
36
 
37
- composer
37
+ if session.hasPiBinary && !session.needsProviderSetup {
38
+ composer
39
+ } else if session.needsProviderSetup {
40
+ if session.isAuthPanelVisible {
41
+ setupLockedBar
42
+ } else {
43
+ PiProviderSetupCallout(session: session, compact: true)
44
+ .padding(.horizontal, 10)
45
+ .padding(.vertical, 10)
46
+ .background(Color.black.opacity(0.62))
47
+ }
48
+ } else {
49
+ PiInstallCallout(session: session, compact: true)
50
+ .padding(.horizontal, 10)
51
+ .padding(.vertical, 10)
52
+ .background(Color.black.opacity(0.62))
53
+ }
38
54
 
39
55
  Rectangle()
40
56
  .fill(Palette.border)
@@ -59,8 +75,11 @@ struct PiChatDock: View {
59
75
  .strokeBorder(Palette.border, lineWidth: 0.5)
60
76
  )
61
77
  .onAppear {
62
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
63
- composerFocused = true
78
+ session.prepareForDisplay()
79
+ if session.hasPiBinary && !session.needsProviderSetup {
80
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
81
+ composerFocused = true
82
+ }
64
83
  }
65
84
  }
66
85
  }
@@ -113,99 +132,113 @@ struct PiChatDock: View {
113
132
 
114
133
  private var authPanel: some View {
115
134
  VStack(alignment: .leading, spacing: 10) {
116
- HStack(spacing: 8) {
117
- Text("provider")
118
- .font(Typo.geistMonoBold(9))
119
- .foregroundColor(Palette.textMuted)
135
+ if session.isAuthenticating {
136
+ VStack(alignment: .leading, spacing: 4) {
137
+ Text("Finish Setup")
138
+ .font(Typo.geistMonoBold(10))
139
+ .foregroundColor(Palette.text)
120
140
 
121
- Picker("Provider", selection: $session.authProviderID) {
122
- ForEach(session.providerOptions) { provider in
123
- Text(provider.name).tag(provider.id)
124
- }
141
+ Text("Ignore the rest for a second and just do the next step below.")
142
+ .font(Typo.mono(9))
143
+ .foregroundColor(Palette.textDim)
144
+ .fixedSize(horizontal: false, vertical: true)
125
145
  }
126
- .labelsHidden()
127
- .pickerStyle(.menu)
128
- .font(Typo.mono(10))
129
-
130
- Spacer()
131
-
132
- capsuleLabel(
133
- session.currentProvider.authMode == .oauth ? "OAUTH" : "TOKEN",
134
- tint: session.currentProvider.authMode == .oauth ? Palette.detach : Palette.running
135
- )
136
- }
137
146
 
138
- Text(session.currentProvider.helpText)
139
- .font(Typo.mono(10))
140
- .foregroundColor(Palette.textDim)
141
- .fixedSize(horizontal: false, vertical: true)
142
-
143
- if session.currentProvider.authMode == .apiKey {
144
147
  HStack(spacing: 8) {
145
- SecureField(session.currentProvider.tokenPlaceholder, text: $session.authToken)
146
- .textFieldStyle(.plain)
147
- .font(Typo.mono(11))
148
- .foregroundColor(Palette.text)
149
- .focused($authFieldFocused)
150
- .onSubmit {
151
- session.saveSelectedToken()
152
- }
148
+ capsuleLabel(session.currentProvider.name.uppercased(), tint: Palette.text)
149
+ capsuleLabel("IN PROGRESS", tint: Palette.detach)
150
+ Spacer()
151
+ }
153
152
 
154
- footerButton("save") {
155
- session.saveSelectedToken()
156
- }
153
+ if let prompt = session.pendingAuthPrompt {
154
+ PiAuthPromptCard(session: session, prompt: prompt, compact: true, focus: $authFieldFocused)
155
+ } else {
156
+ PiAuthNextStepCard(session: session, compact: true)
157
+ }
158
+ } else {
159
+ if session.needsProviderSetup {
160
+ VStack(alignment: .leading, spacing: 4) {
161
+ Text("Set Up Your AI")
162
+ .font(Typo.geistMonoBold(10))
163
+ .foregroundColor(Palette.text)
157
164
 
158
- if session.hasSelectedCredential {
159
- footerButton("clear") {
160
- session.removeSelectedCredential()
161
- }
165
+ Text("Choose a provider, connect it once, and the chat box unlocks automatically.")
166
+ .font(Typo.mono(9))
167
+ .foregroundColor(Palette.textDim)
168
+ .fixedSize(horizontal: false, vertical: true)
162
169
  }
163
170
  }
164
- .padding(.horizontal, 10)
165
- .padding(.vertical, 8)
166
- .background(authCardBackground(tint: Palette.running))
167
- } else {
171
+
168
172
  HStack(spacing: 8) {
169
- footerButton(session.isAuthenticating ? "cancel" : "login") {
170
- if session.isAuthenticating {
171
- session.cancelAuthFlow()
172
- } else {
173
- session.startSelectedAuthFlow()
174
- }
175
- }
173
+ Text(session.needsProviderSetup ? "choose provider" : "provider")
174
+ .font(Typo.geistMonoBold(9))
175
+ .foregroundColor(Palette.textMuted)
176
176
 
177
- if session.hasSelectedCredential {
178
- footerButton("clear") {
179
- session.removeSelectedCredential()
177
+ Picker("Provider", selection: $session.authProviderID) {
178
+ ForEach(session.providerOptions) { provider in
179
+ Text(provider.name).tag(provider.id)
180
180
  }
181
181
  }
182
+ .labelsHidden()
183
+ .pickerStyle(.menu)
184
+ .font(Typo.mono(10))
185
+
186
+ Spacer()
187
+
188
+ capsuleLabel(
189
+ session.currentProvider.authMode == .oauth ? "OAUTH" : "TOKEN",
190
+ tint: session.currentProvider.authMode == .oauth ? Palette.detach : Palette.running
191
+ )
182
192
  }
183
- .padding(.horizontal, 10)
184
- .padding(.vertical, 8)
185
- .background(authCardBackground(tint: session.isAuthenticating ? Palette.detach : Palette.running))
186
193
 
187
- if let prompt = session.pendingAuthPrompt {
194
+ Text(session.currentProvider.helpText)
195
+ .font(Typo.mono(10))
196
+ .foregroundColor(Palette.textDim)
197
+ .fixedSize(horizontal: false, vertical: true)
198
+
199
+ if session.currentProvider.authMode == .apiKey {
188
200
  HStack(spacing: 8) {
189
- TextField(prompt.placeholder ?? prompt.message, text: $session.authPromptInput)
201
+ SecureField(session.currentProvider.tokenPlaceholder, text: $session.authToken)
190
202
  .textFieldStyle(.plain)
191
203
  .font(Typo.mono(11))
192
204
  .foregroundColor(Palette.text)
193
205
  .focused($authFieldFocused)
194
206
  .onSubmit {
195
- session.submitAuthPrompt()
207
+ session.saveSelectedToken()
196
208
  }
197
209
 
198
- footerButton("continue") {
199
- session.submitAuthPrompt()
210
+ footerButton("save key") {
211
+ session.saveSelectedToken()
212
+ }
213
+
214
+ if session.hasSelectedCredential {
215
+ footerButton("clear") {
216
+ session.removeSelectedCredential()
217
+ }
218
+ }
219
+ }
220
+ .padding(.horizontal, 10)
221
+ .padding(.vertical, 8)
222
+ .background(authCardBackground(tint: Palette.running))
223
+ } else {
224
+ HStack(spacing: 8) {
225
+ footerButton("connect") {
226
+ session.startSelectedAuthFlow()
227
+ }
228
+
229
+ if session.hasSelectedCredential {
230
+ footerButton("clear") {
231
+ session.removeSelectedCredential()
232
+ }
200
233
  }
201
234
  }
202
235
  .padding(.horizontal, 10)
203
236
  .padding(.vertical, 8)
204
- .background(authCardBackground(tint: Palette.detach))
237
+ .background(authCardBackground(tint: Palette.running))
205
238
  }
206
239
  }
207
240
 
208
- if let notice = session.authNoticeText, !notice.isEmpty {
241
+ if !session.isAuthenticating, let notice = session.authNoticeText, !notice.isEmpty {
209
242
  Text(notice)
210
243
  .font(Typo.mono(9))
211
244
  .foregroundColor(Palette.textDim)
@@ -362,8 +395,10 @@ struct PiChatDock: View {
362
395
 
363
396
  Spacer()
364
397
 
365
- footerButton(session.isAuthPanelVisible ? "auth -" : "auth +") {
366
- session.toggleAuthPanel()
398
+ if session.hasPiBinary && !session.needsProviderSetup {
399
+ footerButton(session.isAuthPanelVisible ? "auth -" : "auth +") {
400
+ session.toggleAuthPanel()
401
+ }
367
402
  }
368
403
 
369
404
  footerButton("reset") {
@@ -376,8 +411,8 @@ struct PiChatDock: View {
376
411
  }
377
412
 
378
413
  private var footerStatusText: String {
379
- if session.statusText == "idle" {
380
- return session.currentProvider.name
414
+ if session.statusText == "idle" || session.needsProviderSetup || session.isAuthenticating || !session.hasPiBinary {
415
+ return session.setupStatusSummary
381
416
  }
382
417
  return "\(session.currentProvider.name) · \(session.statusText)"
383
418
  }
@@ -390,6 +425,32 @@ struct PiChatDock: View {
390
425
  }
391
426
  }
392
427
 
428
+ private var setupLockedBar: some View {
429
+ HStack(alignment: .center, spacing: 8) {
430
+ Circle()
431
+ .fill(Palette.detach)
432
+ .frame(width: 6, height: 6)
433
+
434
+ VStack(alignment: .leading, spacing: 2) {
435
+ Text("SETUP IN PROGRESS")
436
+ .font(Typo.geistMonoBold(9))
437
+ .foregroundColor(Palette.text)
438
+
439
+ Text(session.isAuthenticating
440
+ ? "Stay with the setup panel above for now. The chat box unlocks as soon as you finish that step."
441
+ : "Finish the setup panel above to unlock the chat box.")
442
+ .font(Typo.mono(9))
443
+ .foregroundColor(Palette.textDim)
444
+ .fixedSize(horizontal: false, vertical: true)
445
+ }
446
+
447
+ Spacer()
448
+ }
449
+ .padding(.horizontal, 10)
450
+ .padding(.vertical, 10)
451
+ .background(Color.black.opacity(0.62))
452
+ }
453
+
393
454
  private func roleLabel(for role: PiChatMessage.Role) -> String {
394
455
  switch role {
395
456
  case .system: return "system"
@@ -426,11 +487,11 @@ struct PiChatDock: View {
426
487
  )
427
488
  }
428
489
 
429
- private func footerButton(_ label: String, tint: Color = Palette.textMuted, action: @escaping () -> Void) -> some View {
490
+ private func footerButton(_ label: String, tint: Color = Palette.textMuted, disabled: Bool = false, action: @escaping () -> Void) -> some View {
430
491
  Button(label, action: action)
431
492
  .buttonStyle(.plain)
432
493
  .font(Typo.geistMonoBold(9))
433
- .foregroundColor(tint)
494
+ .foregroundColor(disabled ? Palette.textMuted : tint)
434
495
  .padding(.horizontal, 8)
435
496
  .padding(.vertical, 5)
436
497
  .background(
@@ -441,6 +502,8 @@ struct PiChatDock: View {
441
502
  .strokeBorder(Palette.border, lineWidth: 0.5)
442
503
  )
443
504
  )
505
+ .opacity(disabled ? 0.65 : 1)
506
+ .disabled(disabled)
444
507
  }
445
508
 
446
509
  private func authCardBackground(tint: Color) -> some View {