@lattices/cli 0.4.10 → 0.4.11

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 (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -13
  3. package/{app → apps/mac}/Lattices.app/Contents/Info.plist +10 -2
  4. package/{app → apps/mac}/Lattices.app/Contents/MacOS/Lattices +0 -0
  5. package/{app → apps/mac}/Package.swift +2 -1
  6. package/apps/mac/Resources/Pets/assistant-spark/pet.json +62 -0
  7. package/apps/mac/Resources/Pets/assistant-spark/spritesheet.webp +0 -0
  8. package/apps/mac/Resources/Pets/scout-ranger/pet.json +6 -0
  9. package/apps/mac/Resources/Pets/scout-ranger/spritesheet.webp +0 -0
  10. package/apps/mac/Sources/AppShell/AppActivationCoordinator.swift +27 -0
  11. package/apps/mac/Sources/AppShell/AppDelegate.swift +189 -0
  12. package/apps/mac/Sources/AppShell/AppServicesBootstrap.swift +25 -0
  13. package/{app → apps/mac}/Sources/AppShell/AppShellView.swift +18 -3
  14. package/{app → apps/mac}/Sources/AppShell/AppUpdater.swift +4 -3
  15. package/apps/mac/Sources/AppShell/HotkeyBootstrap.swift +87 -0
  16. package/{app → apps/mac}/Sources/AppShell/LatticesRuntime.swift +43 -0
  17. package/{app → apps/mac}/Sources/AppShell/MainView.swift +116 -63
  18. package/apps/mac/Sources/AppShell/MenuBarController.swift +177 -0
  19. package/{app → apps/mac}/Sources/AppShell/OnboardingView.swift +72 -60
  20. package/apps/mac/Sources/AppShell/PermissionsAssistantView.swift +366 -0
  21. package/apps/mac/Sources/AppShell/PermissionsAssistantWindow.swift +70 -0
  22. package/{app → apps/mac}/Sources/AppShell/Preferences.swift +37 -2
  23. package/{app → apps/mac}/Sources/AppShell/SettingsView.swift +815 -156
  24. package/{app → apps/mac}/Sources/AppShell/SettingsWindow.swift +10 -0
  25. package/apps/mac/Sources/AppShell/WorkspaceInspectorPresenter.swift +13 -0
  26. package/{app → apps/mac}/Sources/Core/Actions/HotkeyStore.swift +6 -1
  27. package/{app → apps/mac}/Sources/Core/Actions/IntentEngine.swift +2 -0
  28. package/{app → apps/mac}/Sources/Core/Daemon/DaemonServer.swift +5 -0
  29. package/{app → apps/mac}/Sources/Core/Daemon/LatticesApi.swift +365 -0
  30. package/{app → apps/mac}/Sources/Core/Desktop/OcrModel.swift +17 -13
  31. package/apps/mac/Sources/Core/Desktop/WindowCapture.swift +33 -0
  32. package/{app → apps/mac}/Sources/Core/Desktop/WindowDragSnapController.swift +18 -217
  33. package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewStore.swift +4 -5
  34. package/{app → apps/mac}/Sources/Core/Desktop/WindowTiler.swift +19 -13
  35. package/apps/mac/Sources/Core/Input/EventTapBreaker.swift +124 -0
  36. package/apps/mac/Sources/Core/Input/EventTapThread.swift +54 -0
  37. package/apps/mac/Sources/Core/Input/InputCaptureResetCenter.swift +20 -0
  38. package/apps/mac/Sources/Core/Input/KeyboardRemapController.swift +335 -0
  39. package/apps/mac/Sources/Core/Input/KeyboardRemapStore.swift +141 -0
  40. package/{app → apps/mac}/Sources/Core/Input/MouseGestureConfig.swift +155 -20
  41. package/apps/mac/Sources/Core/Input/MouseGestureController.swift +2259 -0
  42. package/apps/mac/Sources/Core/Input/MouseShortcutStore.swift +170 -0
  43. package/apps/mac/Sources/Core/Input/SecureEventInputMonitor.swift +39 -0
  44. package/apps/mac/Sources/Core/Input/ShapeRecognizer.swift +624 -0
  45. package/apps/mac/Sources/Core/Input/TapBudgetMeter.swift +56 -0
  46. package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapState.swift +8 -8
  47. package/apps/mac/Sources/Core/Overlays/ScreenOverlayCanvasController.swift +1240 -0
  48. package/{app → apps/mac}/Sources/Core/Overlays/Voice/VoiceCommandWindow.swift +11 -23
  49. package/{app → apps/mac}/Sources/Core/Pi/PiChatDock.swift +90 -43
  50. package/{app → apps/mac}/Sources/Core/Pi/PiChatSession.swift +676 -43
  51. package/{app → apps/mac}/Sources/Core/Pi/PiProviderSetupCallout.swift +5 -5
  52. package/{app → apps/mac}/Sources/Core/Pi/PiWorkspaceView.swift +93 -44
  53. package/apps/mac/Sources/Core/System/Capability.swift +79 -0
  54. package/{app → apps/mac}/Sources/Core/System/PermissionChecker.swift +43 -8
  55. package/{app → apps/mac}/Sources/Core/Voice/AudioProvider.swift +225 -56
  56. package/bin/handsoff-infer.ts +14 -5
  57. package/bin/handsoff-worker.ts +11 -7
  58. package/bin/infer.ts +406 -0
  59. package/bin/lattices-app.ts +57 -7
  60. package/bin/lattices-dev +40 -1
  61. package/bin/lattices.ts +1 -1
  62. package/docs/agent-execution-plan.md +9 -9
  63. package/docs/api.md +119 -0
  64. package/docs/app.md +1 -0
  65. package/docs/companion-deck.md +1 -1
  66. package/docs/gesture-customization-proposal.md +520 -0
  67. package/docs/mouse-gestures.md +79 -0
  68. package/docs/overview.md +2 -2
  69. package/docs/presentation-execution-review.md +9 -9
  70. package/docs/proposals/LAT-001-gesture-visual-customization.md +522 -0
  71. package/docs/proposals/LAT-002-shared-overlay-canvas.md +353 -0
  72. package/docs/proposals/LAT-003-menu-bar-controller-architecture.md +291 -0
  73. package/docs/proposals/LAT-004-interactive-overlay-actors.md +534 -0
  74. package/docs/reference/dewey.config.ts +74 -0
  75. package/docs/reference/install-agent.md +79 -0
  76. package/docs/repo-structure.md +100 -0
  77. package/docs/voice-error-model.md +7 -7
  78. package/docs/voice.md +18 -0
  79. package/package.json +23 -13
  80. package/swift/Package.swift +20 -0
  81. package/swift/Sources/DeckKit/DeckAction.swift +51 -0
  82. package/swift/Sources/DeckKit/DeckBridgeSecurity.swift +152 -0
  83. package/swift/Sources/DeckKit/DeckCockpit.swift +82 -0
  84. package/swift/Sources/DeckKit/DeckHost.swift +7 -0
  85. package/swift/Sources/DeckKit/DeckManifest.swift +145 -0
  86. package/swift/Sources/DeckKit/DeckRuntimeSnapshot.swift +533 -0
  87. package/swift/Sources/DeckKit/DeckTrackpad.swift +63 -0
  88. package/swift/Sources/DeckKit/DeckValue.swift +93 -0
  89. package/swift/Sources/DeckKit/DeckVoiceError.swift +88 -0
  90. package/swift/Tests/DeckKitTests/DeckKitTests.swift +286 -0
  91. package/app/Sources/AppShell/AppDelegate.swift +0 -408
  92. package/app/Sources/Core/Input/KeyboardRemapController.swift +0 -184
  93. package/app/Sources/Core/Input/KeyboardRemapStore.swift +0 -84
  94. package/app/Sources/Core/Input/MouseGestureController.swift +0 -1203
  95. package/app/Sources/Core/Input/MouseShortcutStore.swift +0 -107
  96. /package/{app → apps/mac}/Info.plist +0 -0
  97. /package/{app → apps/mac}/Lattices.app/Contents/Resources/AppIcon.icns +0 -0
  98. /package/{app → apps/mac}/Lattices.app/Contents/Resources/tap.wav +0 -0
  99. /package/{app → apps/mac}/Lattices.app/Contents/_CodeSignature/CodeResources +0 -0
  100. /package/{app → apps/mac}/Lattices.entitlements +0 -0
  101. /package/{app → apps/mac}/Resources/tap.wav +0 -0
  102. /package/{app → apps/mac}/Sources/AppShell/App.swift +0 -0
  103. /package/{app → apps/mac}/Sources/AppShell/CliActionLauncher.swift +0 -0
  104. /package/{app → apps/mac}/Sources/AppShell/HomeDashboardView.swift +0 -0
  105. /package/{app → apps/mac}/Sources/AppShell/KeyRecorderView.swift +0 -0
  106. /package/{app → apps/mac}/Sources/AppShell/MainWindow.swift +0 -0
  107. /package/{app → apps/mac}/Sources/Core/Actions/HotkeyManager.swift +0 -0
  108. /package/{app → apps/mac}/Sources/Core/Actions/IntentSchema.swift +0 -0
  109. /package/{app → apps/mac}/Sources/Core/Actions/Intents/CreateLayerIntent.swift +0 -0
  110. /package/{app → apps/mac}/Sources/Core/Actions/Intents/DistributeIntent.swift +0 -0
  111. /package/{app → apps/mac}/Sources/Core/Actions/Intents/FocusIntent.swift +0 -0
  112. /package/{app → apps/mac}/Sources/Core/Actions/Intents/HelpIntent.swift +0 -0
  113. /package/{app → apps/mac}/Sources/Core/Actions/Intents/KillIntent.swift +0 -0
  114. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LatticeIntent.swift +0 -0
  115. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LaunchIntent.swift +0 -0
  116. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListSessionsIntent.swift +0 -0
  117. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListWindowsIntent.swift +0 -0
  118. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ScanIntent.swift +0 -0
  119. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SearchIntent.swift +0 -0
  120. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SwitchLayerIntent.swift +0 -0
  121. /package/{app → apps/mac}/Sources/Core/Actions/Intents/TileIntent.swift +0 -0
  122. /package/{app → apps/mac}/Sources/Core/Actions/PaletteCommand.swift +0 -0
  123. /package/{app → apps/mac}/Sources/Core/Actions/VoiceIntentResolver.swift +0 -0
  124. /package/{app → apps/mac}/Sources/Core/Companion/CompanionActivityLog.swift +0 -0
  125. /package/{app → apps/mac}/Sources/Core/Companion/CompanionKeyboardController.swift +0 -0
  126. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +0 -0
  127. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionCockpit.swift +0 -0
  128. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +0 -0
  129. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +0 -0
  130. /package/{app → apps/mac}/Sources/Core/Companion/LatticesDeckHost.swift +0 -0
  131. /package/{app → apps/mac}/Sources/Core/Daemon/DaemonProtocol.swift +0 -0
  132. /package/{app → apps/mac}/Sources/Core/Desktop/AccessibilityTextExtractor.swift +0 -0
  133. /package/{app → apps/mac}/Sources/Core/Desktop/AppTypeClassifier.swift +0 -0
  134. /package/{app → apps/mac}/Sources/Core/Desktop/DesktopModel.swift +0 -0
  135. /package/{app → apps/mac}/Sources/Core/Desktop/DesktopModelTypes.swift +0 -0
  136. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryManager.swift +0 -0
  137. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryPath.swift +0 -0
  138. /package/{app → apps/mac}/Sources/Core/Desktop/MouseFinder.swift +0 -0
  139. /package/{app → apps/mac}/Sources/Core/Desktop/OcrStore.swift +0 -0
  140. /package/{app → apps/mac}/Sources/Core/Desktop/PlacementSpec.swift +0 -0
  141. /package/{app → apps/mac}/Sources/Core/Desktop/SessionWindowLocator.swift +0 -0
  142. /package/{app → apps/mac}/Sources/Core/Desktop/TilePickerView.swift +0 -0
  143. /package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewCard.swift +0 -0
  144. /package/{app → apps/mac}/Sources/Core/Desktop/WindowSelectionStore.swift +0 -0
  145. /package/{app → apps/mac}/Sources/Core/Input/KeyboardRemapConfig.swift +0 -0
  146. /package/{app → apps/mac}/Sources/Core/Input/MouseInputDeviceStore.swift +0 -0
  147. /package/{app → apps/mac}/Sources/Core/Input/MouseInputEventViewer.swift +0 -0
  148. /package/{app → apps/mac}/Sources/Core/Overlays/AppWindowShell.swift +0 -0
  149. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeState.swift +0 -0
  150. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeView.swift +0 -0
  151. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeWindow.swift +0 -0
  152. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteView.swift +0 -0
  153. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteWindow.swift +0 -0
  154. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/CheatSheetHUD.swift +0 -0
  155. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDBottomBar.swift +0 -0
  156. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDController.swift +0 -0
  157. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDLeftBar.swift +0 -0
  158. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDMinimap.swift +0 -0
  159. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDRightBar.swift +0 -0
  160. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDState.swift +0 -0
  161. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDTopBar.swift +0 -0
  162. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LauncherHUD.swift +0 -0
  163. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LayerBezel.swift +0 -0
  164. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchState.swift +0 -0
  165. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchView.swift +0 -0
  166. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchWindow.swift +0 -0
  167. /package/{app → apps/mac}/Sources/Core/Overlays/OverlayPanelShell.swift +0 -0
  168. /package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapView.swift +0 -0
  169. /package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapWindowController.swift +0 -0
  170. /package/{app → apps/mac}/Sources/Core/Pi/PiAuthNextStepCard.swift +0 -0
  171. /package/{app → apps/mac}/Sources/Core/Pi/PiAuthPromptCard.swift +0 -0
  172. /package/{app → apps/mac}/Sources/Core/Pi/PiInstallCallout.swift +0 -0
  173. /package/{app → apps/mac}/Sources/Core/System/DiagnosticLog.swift +0 -0
  174. /package/{app → apps/mac}/Sources/Core/System/EventBus.swift +0 -0
  175. /package/{app → apps/mac}/Sources/Core/System/ProcessModel.swift +0 -0
  176. /package/{app → apps/mac}/Sources/Core/System/ProcessQuery.swift +0 -0
  177. /package/{app → apps/mac}/Sources/Core/System/SystemTelemetryMonitor.swift +0 -0
  178. /package/{app → apps/mac}/Sources/Core/Voice/AdvisorLearningStore.swift +0 -0
  179. /package/{app → apps/mac}/Sources/Core/Voice/AgentSession.swift +0 -0
  180. /package/{app → apps/mac}/Sources/Core/Voice/HandsOffSession.swift +0 -0
  181. /package/{app → apps/mac}/Sources/Core/Voice/VoiceChatView.swift +0 -0
  182. /package/{app → apps/mac}/Sources/Core/Voice/VoxClient.swift +0 -0
  183. /package/{app → apps/mac}/Sources/Core/Workspace/Project.swift +0 -0
  184. /package/{app → apps/mac}/Sources/Core/Workspace/ProjectScanner.swift +0 -0
  185. /package/{app → apps/mac}/Sources/Core/Workspace/SessionLayerStore.swift +0 -0
  186. /package/{app → apps/mac}/Sources/Core/Workspace/SessionManager.swift +0 -0
  187. /package/{app → apps/mac}/Sources/Core/Workspace/Terminal/Terminal.swift +0 -0
  188. /package/{app → apps/mac}/Sources/Core/Workspace/Terminal/TerminalQuery.swift +0 -0
  189. /package/{app → apps/mac}/Sources/Core/Workspace/Terminal/TerminalSynthesizer.swift +0 -0
  190. /package/{app → apps/mac}/Sources/Core/Workspace/Tmux/TmuxModel.swift +0 -0
  191. /package/{app → apps/mac}/Sources/Core/Workspace/Tmux/TmuxQuery.swift +0 -0
  192. /package/{app → apps/mac}/Sources/Core/Workspace/WorkspaceManager.swift +0 -0
  193. /package/{app → apps/mac}/Sources/UI/ActionRow.swift +0 -0
  194. /package/{app → apps/mac}/Sources/UI/OrphanRow.swift +0 -0
  195. /package/{app → apps/mac}/Sources/UI/ProjectRow.swift +0 -0
  196. /package/{app → apps/mac}/Sources/UI/TabGroupRow.swift +0 -0
  197. /package/{app → apps/mac}/Sources/UI/Theme.swift +0 -0
  198. /package/{app → apps/mac}/Tests/StageDragTests.swift +0 -0
  199. /package/{app → apps/mac}/Tests/StageJoinTests.swift +0 -0
  200. /package/{app → apps/mac}/Tests/StageManagerTests.swift +0 -0
  201. /package/{app → apps/mac}/Tests/StageTileTests.swift +0 -0
@@ -968,15 +968,14 @@ struct VoiceCommandView: View {
968
968
  let slots = state.intentSlots.map { "\($0.key)=\($0.value)" }.joined(separator: ", ")
969
969
  let matchStr = slots.isEmpty ? matched : "\(matched)(\(slots))"
970
970
 
971
- let haiku = AgentPool.shared.haiku
972
- guard haiku.isReady else {
973
- state.appendLog("AI not ready")
971
+ let assistant = PiChatSession.shared
972
+ guard assistant.isProviderInferenceReady else {
973
+ state.appendLog("Assistant provider not ready")
974
974
  return
975
975
  }
976
976
 
977
- state.appendLog("Asking AI...")
978
- let message = "Transcript: \"\(transcript)\"\nMatched: \(matchStr)"
979
- haiku.send(message: message) { [weak state] response in
977
+ state.appendLog("Asking Assistant...")
978
+ assistant.askVoiceAdvisor(transcript: transcript, matched: matchStr) { [weak state] response in
980
979
  guard let state = state, let response = response else { return }
981
980
  state.agentResponse = response
982
981
  }
@@ -985,7 +984,7 @@ struct VoiceCommandView: View {
985
984
  private func executeSuggestion(_ suggestion: AgentResponse.AgentSuggestion) {
986
985
  var slotsDict = suggestion.slots
987
986
 
988
- // If the intent needs a query slot and Haiku didn't include one,
987
+ // If the intent needs a query slot and the assistant did not include one,
989
988
  // try to extract it from the label or fall back to the original query
990
989
  if suggestion.intent == "search" && slotsDict["query"] == nil {
991
990
  // Try extracting from label: "Deep search Vox" → "Vox"
@@ -1124,7 +1123,7 @@ struct VoiceCommandView: View {
1124
1123
 
1125
1124
  // MARK: - AI Corner (bottom-right)
1126
1125
 
1127
- @ObservedObject private var haikuSession = AgentPool.shared.haiku
1126
+ @ObservedObject private var assistantSession = PiChatSession.shared
1128
1127
 
1129
1128
  private var aiCorner: some View {
1130
1129
  VStack(spacing: 0) {
@@ -1139,20 +1138,9 @@ struct VoiceCommandView: View {
1139
1138
  .tracking(1)
1140
1139
  Spacer()
1141
1140
 
1142
- // Context usage indicator
1143
- let stats = haikuSession.sessionStats
1144
- if stats.contextWindow > 0 {
1145
- let pct = Int(stats.contextUsage * 100)
1146
- Text("\(pct)%")
1147
- .font(Typo.geistMono(8))
1148
- .foregroundColor(pct > 60 ? Palette.detach : Palette.textMuted.opacity(0.6))
1149
- }
1150
-
1151
- if stats.costUSD > 0 {
1152
- Text("$\(String(format: "%.3f", stats.costUSD))")
1153
- .font(Typo.geistMono(8))
1154
- .foregroundColor(Palette.textMuted.opacity(0.6))
1155
- }
1141
+ Text(assistantSession.currentProvider.name)
1142
+ .font(Typo.geistMono(8))
1143
+ .foregroundColor(Palette.textMuted.opacity(0.65))
1156
1144
 
1157
1145
  if state.agentResponse != nil {
1158
1146
  Button(action: { copyAIResponse() }) {
@@ -1163,7 +1151,7 @@ struct VoiceCommandView: View {
1163
1151
  .buttonStyle(.plain)
1164
1152
  }
1165
1153
 
1166
- if haikuSession.isReady {
1154
+ if assistantSession.isProviderInferenceReady {
1167
1155
  Circle()
1168
1156
  .fill(Palette.running.opacity(0.6))
1169
1157
  .frame(width: 4, height: 4)
@@ -16,18 +16,6 @@ struct PiChatDock: View {
16
16
  VStack(spacing: 0) {
17
17
  topHandle
18
18
 
19
- if session.hasPiBinary && session.isAuthPanelVisible {
20
- Rectangle()
21
- .fill(Palette.border)
22
- .frame(height: 0.5)
23
-
24
- authPanel
25
-
26
- Rectangle()
27
- .fill(Palette.border)
28
- .frame(height: 0.5)
29
- }
30
-
31
19
  transcript
32
20
 
33
21
  Rectangle()
@@ -37,14 +25,7 @@ struct PiChatDock: View {
37
25
  if session.hasPiBinary && !session.needsProviderSetup {
38
26
  composer
39
27
  } 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
- }
28
+ providerSettingsBar
48
29
  } else {
49
30
  PiInstallCallout(session: session, compact: true)
50
31
  .padding(.horizontal, 10)
@@ -197,29 +178,54 @@ struct PiChatDock: View {
197
178
  .fixedSize(horizontal: false, vertical: true)
198
179
 
199
180
  if session.currentProvider.authMode == .apiKey {
200
- HStack(spacing: 8) {
201
- SecureField(session.currentProvider.tokenPlaceholder, text: $session.authToken)
202
- .textFieldStyle(.plain)
203
- .font(Typo.mono(11))
204
- .foregroundColor(Palette.text)
205
- .focused($authFieldFocused)
206
- .onSubmit {
207
- session.saveSelectedToken()
208
- }
181
+ if session.hasSelectedCredential && !session.isEditingStoredCredential {
182
+ HStack(spacing: 8) {
183
+ Circle()
184
+ .fill(Palette.running)
185
+ .frame(width: 6, height: 6)
209
186
 
210
- footerButton("save key") {
211
- session.saveSelectedToken()
212
- }
187
+ Text("credential saved")
188
+ .font(Typo.mono(9))
189
+ .foregroundColor(Palette.textDim)
190
+
191
+ Spacer()
192
+
193
+ footerButton("replace") {
194
+ session.beginReplacingSelectedCredential()
195
+ }
213
196
 
214
- if session.hasSelectedCredential {
215
197
  footerButton("clear") {
216
198
  session.removeSelectedCredential()
217
199
  }
218
200
  }
201
+ .padding(.horizontal, 10)
202
+ .padding(.vertical, 8)
203
+ .background(authCardBackground(tint: Palette.running))
204
+ } else {
205
+ HStack(spacing: 8) {
206
+ SecureField(session.currentProvider.tokenPlaceholder, text: $session.authToken)
207
+ .textFieldStyle(.plain)
208
+ .font(Typo.mono(11))
209
+ .foregroundColor(Palette.text)
210
+ .focused($authFieldFocused)
211
+ .onSubmit {
212
+ session.saveSelectedToken()
213
+ }
214
+
215
+ footerButton("save key") {
216
+ session.saveSelectedToken()
217
+ }
218
+
219
+ if session.hasSelectedCredential {
220
+ footerButton("cancel") {
221
+ session.cancelReplacingSelectedCredential()
222
+ }
223
+ }
224
+ }
225
+ .padding(.horizontal, 10)
226
+ .padding(.vertical, 8)
227
+ .background(authCardBackground(tint: Palette.running))
219
228
  }
220
- .padding(.horizontal, 10)
221
- .padding(.vertical, 8)
222
- .background(authCardBackground(tint: Palette.running))
223
229
  } else {
224
230
  HStack(spacing: 8) {
225
231
  footerButton("connect") {
@@ -347,7 +353,7 @@ struct PiChatDock: View {
347
353
  .font(Typo.geistMonoBold(11))
348
354
  .foregroundColor(Palette.running)
349
355
 
350
- TextField("Ask Pi something lightweight...", text: $session.draft, axis: .vertical)
356
+ TextField("Ask about settings...", text: $session.draft, axis: .vertical)
351
357
  .textFieldStyle(.plain)
352
358
  .font(Typo.mono(11))
353
359
  .foregroundColor(Palette.text)
@@ -384,7 +390,7 @@ struct PiChatDock: View {
384
390
  .fill(session.hasPiBinary ? Palette.running : Palette.kill)
385
391
  .frame(width: 6, height: 6)
386
392
 
387
- Text("PI DOCK")
393
+ Text("ASSISTANT")
388
394
  .font(Typo.geistMonoBold(9))
389
395
  .foregroundColor(Palette.text)
390
396
 
@@ -395,10 +401,8 @@ struct PiChatDock: View {
395
401
 
396
402
  Spacer()
397
403
 
398
- if session.hasPiBinary && !session.needsProviderSetup {
399
- footerButton(session.isAuthPanelVisible ? "auth -" : "auth +") {
400
- session.toggleAuthPanel()
401
- }
404
+ footerIconButton(systemName: "gearshape") {
405
+ SettingsWindowController.shared.showAssistant()
402
406
  }
403
407
 
404
408
  footerButton("reset") {
@@ -410,6 +414,34 @@ struct PiChatDock: View {
410
414
  .background(Color.white.opacity(0.015))
411
415
  }
412
416
 
417
+ private var providerSettingsBar: some View {
418
+ HStack(alignment: .center, spacing: 8) {
419
+ Circle()
420
+ .fill(Palette.detach)
421
+ .frame(width: 6, height: 6)
422
+
423
+ VStack(alignment: .leading, spacing: 2) {
424
+ Text("CONNECT A PROVIDER")
425
+ .font(Typo.geistMonoBold(9))
426
+ .foregroundColor(Palette.text)
427
+
428
+ Text("Choose a chat provider in Settings.")
429
+ .font(Typo.mono(9))
430
+ .foregroundColor(Palette.textDim)
431
+ .fixedSize(horizontal: false, vertical: true)
432
+ }
433
+
434
+ Spacer()
435
+
436
+ footerButton("settings", tint: Palette.running) {
437
+ SettingsWindowController.shared.showAssistant()
438
+ }
439
+ }
440
+ .padding(.horizontal, 10)
441
+ .padding(.vertical, 10)
442
+ .background(Color.black.opacity(0.62))
443
+ }
444
+
413
445
  private var footerStatusText: String {
414
446
  if session.statusText == "idle" || session.needsProviderSetup || session.isAuthenticating || !session.hasPiBinary {
415
447
  return session.setupStatusSummary
@@ -455,7 +487,7 @@ struct PiChatDock: View {
455
487
  switch role {
456
488
  case .system: return "system"
457
489
  case .user: return "you"
458
- case .assistant: return "pi"
490
+ case .assistant: return "assistant"
459
491
  }
460
492
  }
461
493
 
@@ -506,6 +538,21 @@ struct PiChatDock: View {
506
538
  .disabled(disabled)
507
539
  }
508
540
 
541
+ private func footerIconButton(systemName: String, tint: Color = Palette.textMuted, action: @escaping () -> Void) -> some View {
542
+ Button(action: action) {
543
+ Image(systemName: systemName)
544
+ .font(.system(size: 10, weight: .semibold))
545
+ .foregroundColor(tint)
546
+ .frame(width: 24, height: 22)
547
+ .background(
548
+ Capsule()
549
+ .fill(Color.white.opacity(0.03))
550
+ .overlay(Capsule().strokeBorder(Palette.border, lineWidth: 0.5))
551
+ )
552
+ }
553
+ .buttonStyle(.plain)
554
+ }
555
+
509
556
  private func authCardBackground(tint: Color) -> some View {
510
557
  RoundedRectangle(cornerRadius: 6)
511
558
  .fill(tint.opacity(0.06))