@lattices/cli 0.4.9 → 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/DesktopModel.swift +1 -0
  31. package/{app → apps/mac}/Sources/Core/Desktop/OcrModel.swift +17 -13
  32. package/apps/mac/Sources/Core/Desktop/WindowCapture.swift +33 -0
  33. package/{app → apps/mac}/Sources/Core/Desktop/WindowDragSnapController.swift +18 -217
  34. package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewStore.swift +4 -5
  35. package/{app → apps/mac}/Sources/Core/Desktop/WindowTiler.swift +19 -13
  36. package/apps/mac/Sources/Core/Input/EventTapBreaker.swift +124 -0
  37. package/apps/mac/Sources/Core/Input/EventTapThread.swift +54 -0
  38. package/apps/mac/Sources/Core/Input/InputCaptureResetCenter.swift +20 -0
  39. package/apps/mac/Sources/Core/Input/KeyboardRemapController.swift +335 -0
  40. package/apps/mac/Sources/Core/Input/KeyboardRemapStore.swift +141 -0
  41. package/{app → apps/mac}/Sources/Core/Input/MouseGestureConfig.swift +155 -20
  42. package/apps/mac/Sources/Core/Input/MouseGestureController.swift +2259 -0
  43. package/apps/mac/Sources/Core/Input/MouseShortcutStore.swift +170 -0
  44. package/apps/mac/Sources/Core/Input/SecureEventInputMonitor.swift +39 -0
  45. package/apps/mac/Sources/Core/Input/ShapeRecognizer.swift +624 -0
  46. package/apps/mac/Sources/Core/Input/TapBudgetMeter.swift +56 -0
  47. package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapState.swift +46 -27
  48. package/{app → apps/mac}/Sources/Core/Overlays/ScreenMap/ScreenMapView.swift +580 -162
  49. package/apps/mac/Sources/Core/Overlays/ScreenOverlayCanvasController.swift +1240 -0
  50. package/{app → apps/mac}/Sources/Core/Overlays/Voice/VoiceCommandWindow.swift +11 -23
  51. package/{app → apps/mac}/Sources/Core/Pi/PiChatDock.swift +90 -43
  52. package/{app → apps/mac}/Sources/Core/Pi/PiChatSession.swift +676 -43
  53. package/{app → apps/mac}/Sources/Core/Pi/PiProviderSetupCallout.swift +5 -5
  54. package/{app → apps/mac}/Sources/Core/Pi/PiWorkspaceView.swift +93 -44
  55. package/apps/mac/Sources/Core/System/Capability.swift +79 -0
  56. package/{app → apps/mac}/Sources/Core/System/PermissionChecker.swift +43 -8
  57. package/{app → apps/mac}/Sources/Core/Voice/AudioProvider.swift +225 -56
  58. package/bin/handsoff-infer.ts +14 -5
  59. package/bin/handsoff-worker.ts +11 -7
  60. package/bin/infer.ts +406 -0
  61. package/bin/lattices-app.ts +57 -7
  62. package/bin/lattices-dev +40 -1
  63. package/bin/lattices.ts +1 -1
  64. package/docs/agent-execution-plan.md +9 -9
  65. package/docs/api.md +119 -0
  66. package/docs/app.md +1 -0
  67. package/docs/companion-deck.md +1 -1
  68. package/docs/gesture-customization-proposal.md +520 -0
  69. package/docs/mouse-gestures.md +79 -0
  70. package/docs/overview.md +2 -2
  71. package/docs/presentation-execution-review.md +9 -9
  72. package/docs/proposals/LAT-001-gesture-visual-customization.md +522 -0
  73. package/docs/proposals/LAT-002-shared-overlay-canvas.md +353 -0
  74. package/docs/proposals/LAT-003-menu-bar-controller-architecture.md +291 -0
  75. package/docs/proposals/LAT-004-interactive-overlay-actors.md +534 -0
  76. package/docs/reference/dewey.config.ts +74 -0
  77. package/docs/reference/install-agent.md +79 -0
  78. package/docs/repo-structure.md +100 -0
  79. package/docs/voice-error-model.md +7 -7
  80. package/docs/voice.md +18 -0
  81. package/package.json +23 -13
  82. package/swift/Package.swift +20 -0
  83. package/swift/Sources/DeckKit/DeckAction.swift +51 -0
  84. package/swift/Sources/DeckKit/DeckBridgeSecurity.swift +152 -0
  85. package/swift/Sources/DeckKit/DeckCockpit.swift +82 -0
  86. package/swift/Sources/DeckKit/DeckHost.swift +7 -0
  87. package/swift/Sources/DeckKit/DeckManifest.swift +145 -0
  88. package/swift/Sources/DeckKit/DeckRuntimeSnapshot.swift +533 -0
  89. package/swift/Sources/DeckKit/DeckTrackpad.swift +63 -0
  90. package/swift/Sources/DeckKit/DeckValue.swift +93 -0
  91. package/swift/Sources/DeckKit/DeckVoiceError.swift +88 -0
  92. package/swift/Tests/DeckKitTests/DeckKitTests.swift +286 -0
  93. package/app/Sources/AppShell/AppDelegate.swift +0 -408
  94. package/app/Sources/Core/Input/KeyboardRemapController.swift +0 -184
  95. package/app/Sources/Core/Input/KeyboardRemapStore.swift +0 -84
  96. package/app/Sources/Core/Input/MouseGestureController.swift +0 -1203
  97. package/app/Sources/Core/Input/MouseShortcutStore.swift +0 -107
  98. /package/{app → apps/mac}/Info.plist +0 -0
  99. /package/{app → apps/mac}/Lattices.app/Contents/Resources/AppIcon.icns +0 -0
  100. /package/{app → apps/mac}/Lattices.app/Contents/Resources/tap.wav +0 -0
  101. /package/{app → apps/mac}/Lattices.app/Contents/_CodeSignature/CodeResources +0 -0
  102. /package/{app → apps/mac}/Lattices.entitlements +0 -0
  103. /package/{app → apps/mac}/Resources/tap.wav +0 -0
  104. /package/{app → apps/mac}/Sources/AppShell/App.swift +0 -0
  105. /package/{app → apps/mac}/Sources/AppShell/CliActionLauncher.swift +0 -0
  106. /package/{app → apps/mac}/Sources/AppShell/HomeDashboardView.swift +0 -0
  107. /package/{app → apps/mac}/Sources/AppShell/KeyRecorderView.swift +0 -0
  108. /package/{app → apps/mac}/Sources/AppShell/MainWindow.swift +0 -0
  109. /package/{app → apps/mac}/Sources/Core/Actions/HotkeyManager.swift +0 -0
  110. /package/{app → apps/mac}/Sources/Core/Actions/IntentSchema.swift +0 -0
  111. /package/{app → apps/mac}/Sources/Core/Actions/Intents/CreateLayerIntent.swift +0 -0
  112. /package/{app → apps/mac}/Sources/Core/Actions/Intents/DistributeIntent.swift +0 -0
  113. /package/{app → apps/mac}/Sources/Core/Actions/Intents/FocusIntent.swift +0 -0
  114. /package/{app → apps/mac}/Sources/Core/Actions/Intents/HelpIntent.swift +0 -0
  115. /package/{app → apps/mac}/Sources/Core/Actions/Intents/KillIntent.swift +0 -0
  116. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LatticeIntent.swift +0 -0
  117. /package/{app → apps/mac}/Sources/Core/Actions/Intents/LaunchIntent.swift +0 -0
  118. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListSessionsIntent.swift +0 -0
  119. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ListWindowsIntent.swift +0 -0
  120. /package/{app → apps/mac}/Sources/Core/Actions/Intents/ScanIntent.swift +0 -0
  121. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SearchIntent.swift +0 -0
  122. /package/{app → apps/mac}/Sources/Core/Actions/Intents/SwitchLayerIntent.swift +0 -0
  123. /package/{app → apps/mac}/Sources/Core/Actions/Intents/TileIntent.swift +0 -0
  124. /package/{app → apps/mac}/Sources/Core/Actions/PaletteCommand.swift +0 -0
  125. /package/{app → apps/mac}/Sources/Core/Actions/VoiceIntentResolver.swift +0 -0
  126. /package/{app → apps/mac}/Sources/Core/Companion/CompanionActivityLog.swift +0 -0
  127. /package/{app → apps/mac}/Sources/Core/Companion/CompanionKeyboardController.swift +0 -0
  128. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionBridgeServer.swift +0 -0
  129. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionCockpit.swift +0 -0
  130. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionSecurityCoordinator.swift +0 -0
  131. /package/{app → apps/mac}/Sources/Core/Companion/LatticesCompanionTrackpadController.swift +0 -0
  132. /package/{app → apps/mac}/Sources/Core/Companion/LatticesDeckHost.swift +0 -0
  133. /package/{app → apps/mac}/Sources/Core/Daemon/DaemonProtocol.swift +0 -0
  134. /package/{app → apps/mac}/Sources/Core/Desktop/AccessibilityTextExtractor.swift +0 -0
  135. /package/{app → apps/mac}/Sources/Core/Desktop/AppTypeClassifier.swift +0 -0
  136. /package/{app → apps/mac}/Sources/Core/Desktop/DesktopModelTypes.swift +0 -0
  137. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryManager.swift +0 -0
  138. /package/{app → apps/mac}/Sources/Core/Desktop/InventoryPath.swift +0 -0
  139. /package/{app → apps/mac}/Sources/Core/Desktop/MouseFinder.swift +0 -0
  140. /package/{app → apps/mac}/Sources/Core/Desktop/OcrStore.swift +0 -0
  141. /package/{app → apps/mac}/Sources/Core/Desktop/PlacementSpec.swift +0 -0
  142. /package/{app → apps/mac}/Sources/Core/Desktop/SessionWindowLocator.swift +0 -0
  143. /package/{app → apps/mac}/Sources/Core/Desktop/TilePickerView.swift +0 -0
  144. /package/{app → apps/mac}/Sources/Core/Desktop/WindowPreviewCard.swift +0 -0
  145. /package/{app → apps/mac}/Sources/Core/Desktop/WindowSelectionStore.swift +0 -0
  146. /package/{app → apps/mac}/Sources/Core/Input/KeyboardRemapConfig.swift +0 -0
  147. /package/{app → apps/mac}/Sources/Core/Input/MouseInputDeviceStore.swift +0 -0
  148. /package/{app → apps/mac}/Sources/Core/Input/MouseInputEventViewer.swift +0 -0
  149. /package/{app → apps/mac}/Sources/Core/Overlays/AppWindowShell.swift +0 -0
  150. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeState.swift +0 -0
  151. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeView.swift +0 -0
  152. /package/{app → apps/mac}/Sources/Core/Overlays/CommandMode/CommandModeWindow.swift +0 -0
  153. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteView.swift +0 -0
  154. /package/{app → apps/mac}/Sources/Core/Overlays/CommandPalette/CommandPaletteWindow.swift +0 -0
  155. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/CheatSheetHUD.swift +0 -0
  156. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDBottomBar.swift +0 -0
  157. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDController.swift +0 -0
  158. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDLeftBar.swift +0 -0
  159. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDMinimap.swift +0 -0
  160. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDRightBar.swift +0 -0
  161. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDState.swift +0 -0
  162. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/HUDTopBar.swift +0 -0
  163. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LauncherHUD.swift +0 -0
  164. /package/{app → apps/mac}/Sources/Core/Overlays/HUD/LayerBezel.swift +0 -0
  165. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchState.swift +0 -0
  166. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchView.swift +0 -0
  167. /package/{app → apps/mac}/Sources/Core/Overlays/OmniSearch/OmniSearchWindow.swift +0 -0
  168. /package/{app → apps/mac}/Sources/Core/Overlays/OverlayPanelShell.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
@@ -0,0 +1,100 @@
1
+ # Repository Structure
2
+
3
+ Lattices is a small project with several real product surfaces. The root should
4
+ make those surfaces obvious.
5
+
6
+ This document is the current maintainer-facing map and the proposed direction
7
+ for keeping file structure as architecture.
8
+
9
+ ## Current Top-Level Areas
10
+
11
+ | Path | Role |
12
+ | --- | --- |
13
+ | `apps/mac/` | Native macOS menu bar app. Swift/AppKit/SwiftUI package. |
14
+ | `bin/` | Published TypeScript CLI and app helper entry points. |
15
+ | `swift/` | Shared Swift package code used by the app. |
16
+ | `apps/ios/` | iOS companion app experiments and local build state. |
17
+ | `apps/site/` | Public marketing site and blog content. |
18
+ | `apps/docs-site/` | Astro documentation site. |
19
+ | `docs/` | Markdown docs and engineering proposals. |
20
+ | `tools/agents/skills/` | Agent skill pack for driving Lattices. |
21
+ | `assets/` | Shared release/app assets. |
22
+ | `tools/release/` | Maintainer scripts for building and shipping. |
23
+ | `tests/` | CLI, daemon, and evaluation tests. |
24
+
25
+ ## Problem
26
+
27
+ The root currently mixes categories:
28
+
29
+ - shipped product surfaces: `apps/mac/`, `bin/`, `swift/`
30
+ - websites: `apps/site/`, `apps/docs-site/`
31
+ - companion experiments: `apps/ios/`
32
+ - generated or release output: `dist/`
33
+ - maintainer and agent affordances: `docs/`, `tools/`, `tests/`
34
+
35
+ That makes the project feel larger than it is. It also makes it harder to see
36
+ which directories are architecture and which are support material.
37
+
38
+ ## Target Shape
39
+
40
+ Do not reorganize everything at once. The target is:
41
+
42
+ ```text
43
+ apps/
44
+ mac/ # macOS menu bar app
45
+ ios/ # iOS companion app
46
+ site/ # marketing site and blog content
47
+ docs-site/ # documentation site
48
+
49
+ packages/
50
+ cli/ # current bin/ plus TypeScript package surface
51
+ swift/ # current swift/
52
+
53
+ docs/
54
+ proposals/
55
+
56
+ tools/
57
+ release/ # release/build scripts
58
+ agents/skills/ # agent skill pack
59
+ ```
60
+
61
+ This is intentionally similar to the `apps/` and `packages/` split used by
62
+ small monorepos such as Flue, but adapted for Lattices' macOS app plus CLI
63
+ shape.
64
+
65
+ ## Migration Rules
66
+
67
+ - Move one category at a time.
68
+ - Keep published npm entry points stable.
69
+ - Keep app bundle and release scripts working after each move.
70
+ - Update docs and agent instructions in the same PR as any move.
71
+ - Avoid renames that only satisfy aesthetics without reducing ambiguity.
72
+ - Keep generated output ignored and out of the architectural map.
73
+
74
+ ## Near-Term Cleanup
75
+
76
+ Good first moves:
77
+
78
+ 1. Treat `dist/` as generated output only.
79
+ 2. Move blog content closer to the site that owns it, or explicitly document it
80
+ as shared content.
81
+ 3. Decide whether the iOS companion remains in this repo or moves to its own
82
+ repo once the companion work becomes active again.
83
+ 4. Split `docs/proposals/` for numbered engineering docs such as `LAT-001`.
84
+ 5. Decide whether `bin/` remains the package root for the CLI or becomes
85
+ `packages/cli/src/` before adding more exported modules.
86
+
87
+ ## What Stays Boring
88
+
89
+ Root files should be few and intentional:
90
+
91
+ - `README.md`
92
+ - `AGENTS.md`
93
+ - `package.json`
94
+ - lockfile
95
+ - TypeScript config
96
+ - license/security/contribution docs
97
+ - release/install affordances
98
+
99
+ Everything else should either be a product surface, a package, docs, content,
100
+ or tooling.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Goal + anchors
4
4
 
5
- Use one error vocabulary for Mac voice capture/execution and iPad relay/status. The canonical protocol says Lattices borrows Vox for capture and never owns the mic directly (`docs/voice-command-protocol.md:5-7`), but the shared runtime already has a cross-platform `DeckVoiceState` slot (`swift/Sources/DeckKit/DeckRuntimeSnapshot.swift:49-68`). Current Mac code exposes local strings (`VoxError`, `executionResult`) instead of structured errors (`app/Sources/VoxClient.swift:43-59`, `app/Sources/AudioProvider.swift:343-349`); iPad has only a generic `errorMessage` (`iOS/LatticesCompanion/Sources/DeckStore.swift:18`). Normalize at DeckKit, then let each surface render the same object.
5
+ Use one error vocabulary for Mac voice capture/execution and iPad relay/status. The canonical protocol says Lattices borrows Vox for capture and never owns the mic directly (`docs/voice-command-protocol.md:5-7`), but the shared runtime already has a cross-platform `DeckVoiceState` slot (`swift/Sources/DeckKit/DeckRuntimeSnapshot.swift:49-68`). Current Mac code exposes local strings (`VoxError`, `executionResult`) instead of structured errors (`apps/mac/Sources/VoxClient.swift:43-59`, `apps/mac/Sources/AudioProvider.swift:343-349`); iPad has only a generic `errorMessage` (`apps/ios/Sources/DeckStore.swift:18`). Normalize at DeckKit, then let each surface render the same object.
6
6
 
7
7
  ## Error structure
8
8
 
@@ -48,21 +48,21 @@ Copy examples: `Mic in use by Vox — finish memo first`, `No target window`, `V
48
48
 
49
49
  ## Presentation patterns
50
50
 
51
- **Mac VoiceCommandWindow.** Keep the three-column cockpit. The top mic bar already owns live state (`connecting...`, `processing...`; `app/Sources/VoiceCommandWindow.swift:692-719`); render the active error as a compact red/amber status chip there. The center column uses `commandSection` cards (`app/Sources/VoiceCommandWindow.swift:1287-1304`): show a single `blocked`/`needs action` card only when the user can do something. The footer already has key chips (`app/Sources/VoiceCommandWindow.swift:1308-1348`); replace the generic command list with contextual remediation: `⌥ Retry`, `Return Open Vox`, `⌘, Permissions`. Logs stay in the right rail, using existing level colors (`app/Sources/VoiceCommandWindow.swift:1112-1150`).
51
+ **Mac VoiceCommandWindow.** Keep the three-column cockpit. The top mic bar already owns live state (`connecting...`, `processing...`; `apps/mac/Sources/VoiceCommandWindow.swift:692-719`); render the active error as a compact red/amber status chip there. The center column uses `commandSection` cards (`apps/mac/Sources/VoiceCommandWindow.swift:1287-1304`): show a single `blocked`/`needs action` card only when the user can do something. The footer already has key chips (`apps/mac/Sources/VoiceCommandWindow.swift:1308-1348`); replace the generic command list with contextual remediation: `⌥ Retry`, `Return Open Vox`, `⌘, Permissions`. Logs stay in the right rail, using existing level colors (`apps/mac/Sources/VoiceCommandWindow.swift:1112-1150`).
52
52
 
53
- **Mac HUD.** `HUDTopBar.voiceStatus` already has dot, label, transcript, response (`app/Sources/HUDTopBar.swift:134-198`). Add severity tint: green idle/listening, amber connecting/recoverable, red blocked. For active voice errors, HUD shows a one-line banner in the top bar; no sheet.
53
+ **Mac HUD.** `HUDTopBar.voiceStatus` already has dot, label, transcript, response (`apps/mac/Sources/HUDTopBar.swift:134-198`). Add severity tint: green idle/listening, amber connecting/recoverable, red blocked. For active voice errors, HUD shows a one-line banner in the top bar; no sheet.
54
54
 
55
- **iPad Home.** Add `HomeVoiceOverlay` as the full voice modal for active relay: title row `VOICE`, phase, transcript, Mac owner, and one remediation button. The bottom bar already has dense status slots and `hold·space` (`iOS/LatticesCompanion/Sources/Home/HomeBottomBar.swift:58-68`, `iOS/LatticesCompanion/Sources/Home/HomeBottomBar.swift:129-148`); render idle/recoverable errors inline there (`voice · reconnecting`, `voice · Vox offline`). Use a deck overlay banner only when an issued iPad action failed. Use sheets only for permissions/pairing because they need human action. This follows the chrome rule: do not remove noisy UI; replace it with state that answers “what am I controlling, who is listening, what failed?” (`/Users/arach/.claude/projects/-Users-arach-dev-lattices/memory/feedback_chrome_design.md:11-13`).
55
+ **iPad Home.** Add `HomeVoiceOverlay` as the full voice modal for active relay: title row `VOICE`, phase, transcript, Mac owner, and one remediation button. The bottom bar already has dense status slots and `hold·space` (`apps/ios/Sources/Home/HomeBottomBar.swift:58-68`, `apps/ios/Sources/Home/HomeBottomBar.swift:129-148`); render idle/recoverable errors inline there (`voice · reconnecting`, `voice · Vox offline`). Use a deck overlay banner only when an issued iPad action failed. Use sheets only for permissions/pairing because they need human action. This follows the chrome rule: do not remove noisy UI; replace it with state that answers “what am I controlling, who is listening, what failed?” (`/Users/arach/.claude/projects/-Users-arach-dev-lattices/memory/feedback_chrome_design.md:11-13`).
56
56
 
57
57
  ## Unhappy-path prescriptions
58
58
 
59
- **Launch Vox on demand.** Spec flow is detect installed/not running, open Vox, show `Starting Vox...`, wait up to 10s, retry `startDictation`, then fail with manual-open copy (`docs/voice-command-protocol.md:73-89`). Current Mac waits 2s after `connect()` (`app/Sources/VoiceCommandWindow.swift:290-313`); design target is `vox_not_running` → `vox_loading` → retry → either clear error or `vox_unreachable` with `openVox`.
59
+ **Launch Vox on demand.** Spec flow is detect installed/not running, open Vox, show `Starting Vox...`, wait up to 10s, retry `startDictation`, then fail with manual-open copy (`docs/voice-command-protocol.md:73-89`). Current Mac waits 2s after `connect()` (`apps/mac/Sources/VoiceCommandWindow.swift:290-313`); design target is `vox_not_running` → `vox_loading` → retry → either clear error or `vox_unreachable` with `openVox`.
60
60
 
61
61
  **Mic busy.** Preserve owner attribution from protocol (`docs/voice-command-protocol.md:127-135`). `mic_busy(owner: "Vox")` is warning, recoverable, retry hint `userAction`; message: `Mic in use by Vox — finish memo first`. If owner is unknown: `Mic busy — wait for current recording`.
62
62
 
63
63
  **Connection recovery.** If idle, reconnect silently and write log only. If active, show red `Connection lost`; do not auto-retry captured audio because Vox cancels dropped sockets (`docs/voice-command-protocol.md:174-188`). iPad shows `Mac voice link lost` if bridge lost, not `network` unless the iPad transport failed.
64
64
 
65
- **JSONL.** Add `~/.lattices/voice.jsonl` beside `lattices.log` (current log path is `~/.lattices/lattices.log`; `app/Sources/DiagnosticLog.swift:40-59`). Shape:
65
+ **JSONL.** Add `~/.lattices/voice.jsonl` beside `lattices.log` (current log path is `~/.lattices/lattices.log`; `apps/mac/Sources/DiagnosticLog.swift:40-59`). Shape:
66
66
 
67
67
  ```json
68
68
  {"ts":"2026-04-27T14:03:11.120Z","platform":"mac","sessionId":"...","phase":"listening","event":"error","error":{"code":"mic_busy","severity":"warning","recoverable":true,"source":"vox","owner":"Vox","message":"Mic in use by Vox — finish memo first"},"transcript":null,"intent":null,"durationMs":820}
@@ -70,4 +70,4 @@ Copy examples: `Mic in use by Vox — finish memo first`, `No target window`, `V
70
70
 
71
71
  ## Cross-platform conventions
72
72
 
73
- Tone: terse cockpit, no apologies. Prefer noun-state-action: `Vox offline — starting`, `No target — pick window`, `Access denied — enable Accessibility`. Tint maps to existing palettes: Mac `Palette.detach` amber and `Palette.kill` red (`app/Sources/Theme.swift:19-23`); iPad `LatsPalette.amber/red` (`iOS/LatticesCompanion/Sources/LatsDeckScreen.swift:19-25`). Icons: `mic.fill` live, `mic.slash` denied, `waveform.badge.exclamationmark` transcription, `bolt.trianglebadge.exclamationmark` execution, `wifi.exclamationmark` connection, `scope` target. Ownership: Mac owns Vox, mic, Accessibility, intent execution, and JSONL. iPad owns relay/bridge/network presentation and never claims direct mic capture.
73
+ Tone: terse cockpit, no apologies. Prefer noun-state-action: `Vox offline — starting`, `No target — pick window`, `Access denied — enable Accessibility`. Tint maps to existing palettes: Mac `Palette.detach` amber and `Palette.kill` red (`apps/mac/Sources/Theme.swift:19-23`); iPad `LatsPalette.amber/red` (`apps/ios/Sources/LatsDeckScreen.swift:19-25`). Icons: `mic.fill` live, `mic.slash` denied, `waveform.badge.exclamationmark` transcription, `bolt.trianglebadge.exclamationmark` execution, `wifi.exclamationmark` connection, `scope` target. Ownership: Mac owns Vox, mic, Accessibility, intent execution, and JSONL. iPad owns relay/bridge/network presentation and never claims direct mic capture.
package/docs/voice.md CHANGED
@@ -134,6 +134,24 @@ reaches 75% of the model's limit, the session auto-resets.
134
134
 
135
135
  Context usage and session cost are shown in the AI corner header.
136
136
 
137
+ ## Hands-off inference
138
+
139
+ Hands-off voice uses the shared inference wrapper in `bin/infer.ts`.
140
+ By default it chooses the lowest-latency configured provider and, when
141
+ Groq credentials are present, uses `groq/llama-3.1-8b-instant`.
142
+
143
+ Credentials are read from process env, `.env.local`, `.env`,
144
+ `~/.lattices/inference.json`, then `~/.config/speakeasy/settings.json`.
145
+ For Groq, either `GROQ_API_KEY` or the common typo `GROK_API_KEY` works
146
+ when the key has Groq's `gsk_` prefix.
147
+
148
+ Override the voice engine if needed:
149
+
150
+ ```bash
151
+ LATTICES_VOICE_PROVIDER=groq
152
+ LATTICES_VOICE_MODEL=llama-3.1-8b-instant
153
+ ```
154
+
137
155
  ## Configuration
138
156
 
139
157
  Open **Settings > AI** to configure:
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@lattices/cli",
3
- "version": "0.4.9",
4
- "description": "Agentic window manager for macOS — programmable workspace, smart layouts, managed tmux sessions, and a 35+-method agent API",
3
+ "version": "0.4.11",
4
+ "description": "The agentic workspace manager for macOS — turn your desktop into a coherent API",
5
+ "packageManager": "bun@1.3.11",
6
+ "engines": {
7
+ "node": ">=18"
8
+ },
5
9
  "bin": {
6
10
  "lattices": "./bin/lattices.ts",
7
11
  "lattices-app": "./bin/lattices-app.ts"
@@ -27,10 +31,13 @@
27
31
  "./project-twin": "./bin/project-twin.ts"
28
32
  },
29
33
  "scripts": {
30
- "dev": "bun --cwd docs-site dev",
31
- "test:e2e": "node --experimental-strip-types --test test/e2e-daemon.test.mjs",
32
- "test:e2e:voice": "node --experimental-strip-types test/eval-voice.js",
33
- "typecheck": "tsc --noEmit",
34
+ "dev": "bun --cwd apps/docs-site dev",
35
+ "check": "bun run check:types && bun run check:app",
36
+ "check:types": "tsc --noEmit",
37
+ "check:app": "env CLANG_MODULE_CACHE_PATH=/tmp/lattices-clang-cache SWIFTPM_TESTS_MODULECACHE=/tmp/lattices-swiftpm-cache swift build --package-path apps/mac",
38
+ "test:e2e": "node --experimental-strip-types --test tests/e2e-daemon.test.mjs",
39
+ "test:e2e:voice": "node --experimental-strip-types tests/eval-voice.js",
40
+ "typecheck": "bun run check:types",
34
41
  "build:app-bundle": "bash ./bin/lattices-dev build",
35
42
  "prepack": "bash ./bin/lattices-dev build"
36
43
  },
@@ -38,13 +45,16 @@
38
45
  "os": ["darwin"],
39
46
  "files": [
40
47
  "bin",
41
- "app/Info.plist",
42
- "app/Lattices.app",
43
- "app/Lattices.entitlements",
44
- "app/Package.swift",
45
- "app/Resources",
46
- "app/Sources",
47
- "app/Tests",
48
+ "apps/mac/Info.plist",
49
+ "apps/mac/Lattices.app",
50
+ "apps/mac/Lattices.entitlements",
51
+ "apps/mac/Package.swift",
52
+ "apps/mac/Resources",
53
+ "apps/mac/Sources",
54
+ "apps/mac/Tests",
55
+ "swift/Package.swift",
56
+ "swift/Sources",
57
+ "swift/Tests",
48
58
  "assets/AppIcon.icns",
49
59
  "docs"
50
60
  ],
@@ -0,0 +1,20 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "DeckKit",
6
+ platforms: [
7
+ .macOS(.v13),
8
+ .iOS(.v17)
9
+ ],
10
+ products: [
11
+ .library(name: "DeckKit", targets: ["DeckKit"])
12
+ ],
13
+ targets: [
14
+ .target(name: "DeckKit"),
15
+ .testTarget(
16
+ name: "DeckKitTests",
17
+ dependencies: ["DeckKit"]
18
+ )
19
+ ]
20
+ )
@@ -0,0 +1,51 @@
1
+ import Foundation
2
+
3
+ public struct DeckActionRequest: Codable, Equatable, Sendable {
4
+ public var pageID: String?
5
+ public var actionID: String
6
+ public var payload: [String: DeckValue]
7
+
8
+ public init(
9
+ pageID: String? = nil,
10
+ actionID: String,
11
+ payload: [String: DeckValue] = [:]
12
+ ) {
13
+ self.pageID = pageID
14
+ self.actionID = actionID
15
+ self.payload = payload
16
+ }
17
+ }
18
+
19
+ public struct DeckActionResult: Codable, Equatable, Sendable {
20
+ public var ok: Bool
21
+ public var summary: String
22
+ public var detail: String?
23
+ public var runtimeSnapshot: DeckRuntimeSnapshot?
24
+ public var suggestedActions: [DeckSuggestedAction]
25
+
26
+ public init(
27
+ ok: Bool,
28
+ summary: String,
29
+ detail: String? = nil,
30
+ runtimeSnapshot: DeckRuntimeSnapshot? = nil,
31
+ suggestedActions: [DeckSuggestedAction] = []
32
+ ) {
33
+ self.ok = ok
34
+ self.summary = summary
35
+ self.detail = detail
36
+ self.runtimeSnapshot = runtimeSnapshot
37
+ self.suggestedActions = suggestedActions
38
+ }
39
+ }
40
+
41
+ public struct DeckSuggestedAction: Codable, Equatable, Identifiable, Sendable {
42
+ public var id: String
43
+ public var title: String
44
+ public var iconSystemName: String?
45
+
46
+ public init(id: String, title: String, iconSystemName: String? = nil) {
47
+ self.id = id
48
+ self.title = title
49
+ self.iconSystemName = iconSystemName
50
+ }
51
+ }
@@ -0,0 +1,152 @@
1
+ import Foundation
2
+
3
+ public struct DeckPairingRequest: Codable, Equatable, Sendable {
4
+ public var deviceID: String
5
+ public var deviceName: String
6
+ public var devicePublicKey: String
7
+ public var platform: String
8
+ public var appVersion: String?
9
+ public var requestedCapabilities: [String]
10
+
11
+ public init(
12
+ deviceID: String,
13
+ deviceName: String,
14
+ devicePublicKey: String,
15
+ platform: String,
16
+ appVersion: String? = nil,
17
+ requestedCapabilities: [String] = DeckBridgeCapability.defaultCompanionCapabilities
18
+ ) {
19
+ self.deviceID = deviceID
20
+ self.deviceName = deviceName
21
+ self.devicePublicKey = devicePublicKey
22
+ self.platform = platform
23
+ self.appVersion = appVersion
24
+ self.requestedCapabilities = requestedCapabilities
25
+ }
26
+
27
+ private enum CodingKeys: String, CodingKey {
28
+ case deviceID
29
+ case deviceName
30
+ case devicePublicKey
31
+ case platform
32
+ case appVersion
33
+ case requestedCapabilities
34
+ }
35
+
36
+ public init(from decoder: Decoder) throws {
37
+ let container = try decoder.container(keyedBy: CodingKeys.self)
38
+ deviceID = try container.decode(String.self, forKey: .deviceID)
39
+ deviceName = try container.decode(String.self, forKey: .deviceName)
40
+ devicePublicKey = try container.decode(String.self, forKey: .devicePublicKey)
41
+ platform = try container.decode(String.self, forKey: .platform)
42
+ appVersion = try container.decodeIfPresent(String.self, forKey: .appVersion)
43
+ requestedCapabilities = try container.decodeIfPresent([String].self, forKey: .requestedCapabilities)
44
+ ?? DeckBridgeCapability.defaultCompanionCapabilities
45
+ }
46
+ }
47
+
48
+ public struct DeckPairingResponse: Codable, Equatable, Sendable {
49
+ public var disposition: DeckPairingDisposition
50
+ public var bridgeName: String
51
+ public var bridgePublicKey: String
52
+ public var bridgeFingerprint: String
53
+ public var requestSigningRequired: Bool
54
+ public var payloadEncryptionRequired: Bool
55
+ public var grantedCapabilities: [String]
56
+ public var detail: String?
57
+
58
+ public init(
59
+ disposition: DeckPairingDisposition,
60
+ bridgeName: String,
61
+ bridgePublicKey: String,
62
+ bridgeFingerprint: String,
63
+ requestSigningRequired: Bool,
64
+ payloadEncryptionRequired: Bool,
65
+ grantedCapabilities: [String] = DeckBridgeCapability.defaultCompanionCapabilities,
66
+ detail: String? = nil
67
+ ) {
68
+ self.disposition = disposition
69
+ self.bridgeName = bridgeName
70
+ self.bridgePublicKey = bridgePublicKey
71
+ self.bridgeFingerprint = bridgeFingerprint
72
+ self.requestSigningRequired = requestSigningRequired
73
+ self.payloadEncryptionRequired = payloadEncryptionRequired
74
+ self.grantedCapabilities = grantedCapabilities
75
+ self.detail = detail
76
+ }
77
+
78
+ private enum CodingKeys: String, CodingKey {
79
+ case disposition
80
+ case bridgeName
81
+ case bridgePublicKey
82
+ case bridgeFingerprint
83
+ case requestSigningRequired
84
+ case payloadEncryptionRequired
85
+ case grantedCapabilities
86
+ case detail
87
+ }
88
+
89
+ public init(from decoder: Decoder) throws {
90
+ let container = try decoder.container(keyedBy: CodingKeys.self)
91
+ disposition = try container.decode(DeckPairingDisposition.self, forKey: .disposition)
92
+ bridgeName = try container.decode(String.self, forKey: .bridgeName)
93
+ bridgePublicKey = try container.decode(String.self, forKey: .bridgePublicKey)
94
+ bridgeFingerprint = try container.decode(String.self, forKey: .bridgeFingerprint)
95
+ requestSigningRequired = try container.decode(Bool.self, forKey: .requestSigningRequired)
96
+ payloadEncryptionRequired = try container.decode(Bool.self, forKey: .payloadEncryptionRequired)
97
+ grantedCapabilities = try container.decodeIfPresent([String].self, forKey: .grantedCapabilities)
98
+ ?? DeckBridgeCapability.defaultCompanionCapabilities
99
+ detail = try container.decodeIfPresent(String.self, forKey: .detail)
100
+ }
101
+ }
102
+
103
+ public enum DeckPairingDisposition: String, Codable, CaseIterable, Sendable {
104
+ case approved
105
+ case alreadyTrusted
106
+ case denied
107
+ }
108
+
109
+ public struct DeckEncryptedEnvelope: Codable, Equatable, Sendable {
110
+ public var sealedBox: String
111
+
112
+ public init(sealedBox: String) {
113
+ self.sealedBox = sealedBox
114
+ }
115
+ }
116
+
117
+ public struct DeckTrustedDeviceSummary: Codable, Equatable, Identifiable, Sendable {
118
+ public var id: String
119
+ public var name: String
120
+ public var fingerprint: String
121
+ public var capabilities: [String]
122
+ public var pairedAt: Date
123
+ public var lastSeenAt: Date
124
+
125
+ public init(
126
+ id: String,
127
+ name: String,
128
+ fingerprint: String,
129
+ capabilities: [String] = [],
130
+ pairedAt: Date,
131
+ lastSeenAt: Date
132
+ ) {
133
+ self.id = id
134
+ self.name = name
135
+ self.fingerprint = fingerprint
136
+ self.capabilities = capabilities
137
+ self.pairedAt = pairedAt
138
+ self.lastSeenAt = lastSeenAt
139
+ }
140
+ }
141
+
142
+ public enum DeckBridgeCapability {
143
+ public static let deckRead = "deck.read"
144
+ public static let deckPerform = "deck.perform"
145
+ public static let inputTrackpad = "input.trackpad"
146
+
147
+ public static let defaultCompanionCapabilities = [
148
+ deckRead,
149
+ deckPerform,
150
+ inputTrackpad,
151
+ ]
152
+ }
@@ -0,0 +1,82 @@
1
+ import Foundation
2
+
3
+ public struct DeckCockpitState: Codable, Equatable, Sendable {
4
+ public var title: String?
5
+ public var detail: String?
6
+ public var pages: [DeckCockpitPage]
7
+
8
+ public init(
9
+ title: String? = nil,
10
+ detail: String? = nil,
11
+ pages: [DeckCockpitPage]
12
+ ) {
13
+ self.title = title
14
+ self.detail = detail
15
+ self.pages = pages
16
+ }
17
+ }
18
+
19
+ public struct DeckCockpitPage: Codable, Equatable, Identifiable, Sendable {
20
+ public var id: String
21
+ public var title: String
22
+ public var subtitle: String?
23
+ public var columns: Int
24
+ public var tiles: [DeckCockpitTile]
25
+
26
+ public init(
27
+ id: String,
28
+ title: String,
29
+ subtitle: String? = nil,
30
+ columns: Int = 4,
31
+ tiles: [DeckCockpitTile]
32
+ ) {
33
+ self.id = id
34
+ self.title = title
35
+ self.subtitle = subtitle
36
+ self.columns = columns
37
+ self.tiles = tiles
38
+ }
39
+ }
40
+
41
+ public struct DeckCockpitTile: Codable, Equatable, Identifiable, Sendable {
42
+ public var id: String
43
+ public var shortcutID: String
44
+ public var title: String
45
+ public var subtitle: String?
46
+ public var iconSystemName: String
47
+ public var accentToken: String?
48
+ public var deckID: String?
49
+ public var categoryTint: String?
50
+ public var actionID: String?
51
+ public var payload: [String: DeckValue]
52
+ public var isEnabled: Bool
53
+ public var isActive: Bool
54
+
55
+ public init(
56
+ id: String,
57
+ shortcutID: String,
58
+ title: String,
59
+ subtitle: String? = nil,
60
+ iconSystemName: String,
61
+ accentToken: String? = nil,
62
+ deckID: String? = nil,
63
+ categoryTint: String? = nil,
64
+ actionID: String? = nil,
65
+ payload: [String: DeckValue] = [:],
66
+ isEnabled: Bool = true,
67
+ isActive: Bool = false
68
+ ) {
69
+ self.id = id
70
+ self.shortcutID = shortcutID
71
+ self.title = title
72
+ self.subtitle = subtitle
73
+ self.iconSystemName = iconSystemName
74
+ self.accentToken = accentToken
75
+ self.deckID = deckID
76
+ self.categoryTint = categoryTint
77
+ self.actionID = actionID
78
+ self.payload = payload
79
+ self.isEnabled = isEnabled
80
+ self.isActive = isActive
81
+ }
82
+ }
@@ -0,0 +1,7 @@
1
+ import Foundation
2
+
3
+ public protocol DeckHost: Sendable {
4
+ func manifest() async throws -> DeckManifest
5
+ func runtimeSnapshot() async throws -> DeckRuntimeSnapshot
6
+ func perform(_ request: DeckActionRequest) async throws -> DeckActionResult
7
+ }