@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
package/docs/api.md CHANGED
@@ -160,6 +160,125 @@ try {
160
160
 
161
161
  ---
162
162
 
163
+ ## Overlay UI
164
+
165
+ The macOS app exposes a shared desktop overlay canvas for lightweight
166
+ agent-visible UI. Use `overlay.publish` for transient passive visuals,
167
+ and `overlay.actor.*` for persistent, movable actor surfaces.
168
+
169
+ Persistent actors are useful for representing agents or processes on the
170
+ desktop. Each actor has a stable `id`, can be moved independently, can be
171
+ dragged by the user, and can be hidden/restored with **Hyper+8**. Right-click
172
+ an actor to close that specific actor.
173
+
174
+ | Method | Type | Description |
175
+ |--------|------|-------------|
176
+ | `overlay.publish` | write | Publish a transient toast, label, highlight, or pet layer |
177
+ | `overlay.clear` | write | Clear one overlay layer by id, or clear an owner namespace |
178
+ | `overlay.actor.publish` | write | Create or update a persistent generative overlay actor |
179
+ | `overlay.actor.moveTo` | write | Move an actor with app-owned easing |
180
+
181
+ #### `overlay.publish`
182
+
183
+ Publish a transient layer on the screen overlay canvas.
184
+
185
+ **Params**:
186
+
187
+ | Field | Type | Required | Description |
188
+ |-------|------|----------|-------------|
189
+ | `kind` | string | yes | `toast`, `label`, `highlight`, or `pet` |
190
+ | `id` | string | no | Stable layer id; generated if omitted |
191
+ | `text` | string | no | Toast/label text or pet message fallback |
192
+ | `detail` | string | no | Secondary toast/label text |
193
+ | `message` | string | no | Pet message |
194
+ | `petId` | string | no | Bundled pet id from `apps/mac/Resources/Pets` |
195
+ | `state` | string | no | Pet animation state |
196
+ | `placement` | string | no | `top`, `bottom`, `center`, `cursor`, or `point` |
197
+ | `x`, `y` | double | no | Screen-local point for `point` placement |
198
+ | `w`, `h` | double | no | Highlight size |
199
+ | `ttlMs` | int | no | Time to live in milliseconds |
200
+ | `dismissible` | bool | no | Whether click-away dismissal removes the layer; defaults `true` |
201
+
202
+ Example:
203
+
204
+ ```js
205
+ await daemonCall('overlay.publish', {
206
+ kind: 'highlight',
207
+ x: 160,
208
+ y: 120,
209
+ w: 480,
210
+ h: 260,
211
+ text: 'Needs review',
212
+ style: 'warning',
213
+ ttlMs: 3000
214
+ })
215
+ ```
216
+
217
+ #### `overlay.actor.publish`
218
+
219
+ Create or update a generative overlay actor. Actors default to persistent:
220
+ omit `ttlMs` or pass `0`, and `dismissible` defaults to `false`.
221
+
222
+ **Params**:
223
+
224
+ | Field | Type | Required | Description |
225
+ |-------|------|----------|-------------|
226
+ | `id` | string | no | Stable actor id; generated if omitted |
227
+ | `renderer` | string | no | `sprite` is currently supported |
228
+ | `asset` | string | no | Bundled sprite asset id, such as `scout-ranger` |
229
+ | `state` | string | no | Actor state or animation name |
230
+ | `name` | string | no | Actor display name |
231
+ | `message` | string | no | Attached message text |
232
+ | `placement` | string | no | `top`, `bottom`, `center`, `cursor`, or `point` |
233
+ | `x`, `y` | double | no | Screen-local point for `point` placement |
234
+ | `ttlMs` | int | no | Time to live; `0` means persistent |
235
+ | `dismissible` | bool | no | Whether click-away dismissal removes the actor |
236
+
237
+ Example:
238
+
239
+ ```js
240
+ await daemonCall('overlay.actor.publish', {
241
+ id: 'agent-scout',
242
+ renderer: 'sprite',
243
+ asset: 'scout-ranger',
244
+ state: 'waiting',
245
+ name: 'Scout',
246
+ message: 'Waiting for feedback',
247
+ placement: 'point',
248
+ x: 640,
249
+ y: 320,
250
+ ttlMs: 0
251
+ })
252
+ ```
253
+
254
+ #### `overlay.actor.moveTo`
255
+
256
+ Move an actor with app-owned animation. The app interpolates position and
257
+ switches directional sprite states while moving.
258
+
259
+ **Params**:
260
+
261
+ | Field | Type | Required | Description |
262
+ |-------|------|----------|-------------|
263
+ | `id` | string | yes | Actor id |
264
+ | `x`, `y` | double | yes | Target screen-local point |
265
+ | `durationMs` | int | no | Animation duration |
266
+ | `easing` | string | no | `linear`, `easeInOut`, or `spring` |
267
+
268
+ Example:
269
+
270
+ ```js
271
+ await daemonCall('overlay.actor.moveTo', {
272
+ id: 'agent-scout',
273
+ x: 820,
274
+ y: 280,
275
+ durationMs: 800,
276
+ easing: 'spring'
277
+ })
278
+ ```
279
+
280
+ ---
281
+
163
282
  ## System
164
283
 
165
284
  | Method | Type | Description |
package/docs/app.md CHANGED
@@ -228,6 +228,7 @@ Shows keyboard shortcut reference:
228
228
  | Hyper+4 | Desktop inventory |
229
229
  | Hyper+5 | Omni search |
230
230
  | Hyper+6 | Cheat sheet |
231
+ | Hyper+8 | Hide/show persistent overlay actors |
231
232
  | Cmd+Option+1/2/3 | Switch workspace layer |
232
233
  | Ctrl+B D | Detach from session |
233
234
  | Ctrl+B X | Kill current pane |
@@ -115,7 +115,7 @@ The first host-side integration now lives in the Lattices macOS app.
115
115
 
116
116
  - `swift/DeckKit` continues to own the shared manifest, snapshot,
117
117
  action, and security contract.
118
- - `app/Sources/LatticesDeckHost.swift` is the first concrete Mac host.
118
+ - `apps/mac/Sources/LatticesDeckHost.swift` is the first concrete Mac host.
119
119
  - The menu bar app daemon now exposes:
120
120
  - `deck.manifest`
121
121
  - `deck.snapshot`
@@ -0,0 +1,520 @@
1
+ # LAT-001: Gesture Visual Customization and Renderer Hooks
2
+
3
+ ## Status
4
+
5
+ Proposal for maintainers.
6
+
7
+ This is the first Lattices engineering proposal in the `LAT-00n` series, following the same proposal-numbering spirit as the `SCO-00n` documents used for Scout/OpenScout planning.
8
+
9
+ This document covers how to productize the recent mouse gesture and visual customization prototypes without letting decoration leak into the recognition or action-dispatch fast path.
10
+
11
+ ## Summary
12
+
13
+ Lattices now has the bones of a gesture system that feels unusually alive for a macOS workspace tool: low-level mouse capture, shape recognition, shortcut matching, immediate native action dispatch, and a fallback overlay that can draw paths, markers, and result labels.
14
+
15
+ The next question is whether customization should become a supported product surface. The answer proposed here is yes, but with a hard boundary:
16
+
17
+ - gesture recognition and action dispatch remain native, synchronous, and fast
18
+ - custom rendering is declarative, best-effort, and optional
19
+ - user assets and external renderers never block or decide actions
20
+ - normal customization should not require recompiling the app
21
+
22
+ The first supported model should be a declarative `visual` block on mouse shortcut rules, backed by native theme presets and marker-to-animation mappings. Real Lottie playback can follow once the configuration model is stable. A plugin or XPC renderer can come later, after the native path has proven the contract.
23
+
24
+ ## Current Gesture Pipeline
25
+
26
+ The gesture pipeline lives mainly in:
27
+
28
+ - `apps/mac/Sources/Core/Input/MouseGestureController.swift`
29
+ - `apps/mac/Sources/Core/Input/MouseGestureConfig.swift`
30
+ - `apps/mac/Sources/Core/Input/MouseShortcutStore.swift`
31
+ - `apps/mac/Sources/Core/Input/ShapeRecognizer.swift`
32
+
33
+ The current/prototyped flow is:
34
+
35
+ 1. A CG event tap captures mouse button and movement events.
36
+ 2. `MouseGestureController` starts and updates gesture sessions, tracking button state, phase, and path points.
37
+ 3. Movement points are fed to `ShapeRecognizer`, which compresses raw motion into direction runs.
38
+ 4. Recognized shapes such as `l-shape-down-right` become trigger facts.
39
+ 5. `MouseShortcutStore` matches a `MouseShortcutTriggerEvent` against enabled `MouseShortcutRule` entries.
40
+ 6. The matched rule dispatches its native action immediately.
41
+ 7. `MouseGestureOverlay` and `MouseGestureOverlayView`, currently nested in `MouseGestureController.swift`, render the fallback/native gesture feedback.
42
+
43
+ The important split is already visible: input capture, recognition, rule matching, and action dispatch form the control path. Overlay drawing is feedback.
44
+
45
+ ## What Was Prototyped
46
+
47
+ Recent prototype work explored both input semantics and visual expression.
48
+
49
+ Input and matching:
50
+
51
+ - shape triggers
52
+ - right, back, forward, and middle button handling
53
+ - MX back/forward aliases
54
+ - a back-button L shape that activates iTerm
55
+ - native action dispatch that stays immediate
56
+
57
+ Visual feedback:
58
+
59
+ - path drawing instead of a single direction arrow
60
+ - Bezier/graffiti trail rendering
61
+ - guide dots inspired by Android pattern lock
62
+ - satisfying result labels such as `iTerm FOCUSED`
63
+ - a `visual` block on shortcut rules
64
+ - a native stand-in for a custom animated character
65
+
66
+ The visual customization proof of concept added optional rule metadata:
67
+
68
+ ```json
69
+ {
70
+ "visual": {
71
+ "renderer": "lottie",
72
+ "asset": "~/.lattices/gesture-assets/cat.json",
73
+ "character": "cat",
74
+ "events": {
75
+ "updated": "follow",
76
+ "recognized:l-shape-down-right": "pounce",
77
+ "completed.success": "celebrate",
78
+ "completed.failure": "confused"
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ Today, `renderer: "lottie"` is a shim/POC name, not a real Lottie dependency. The native renderer draws a small reactive cat/avatar as a stand-in for an eventual Lottie asset.
85
+
86
+ That is a good prototype shape because it tests the user-facing contract without prematurely committing to a rendering engine.
87
+
88
+ ## Architecture Principle
89
+
90
+ Recognition and action dispatch are the fast path. They must never wait on:
91
+
92
+ - custom rendering
93
+ - scripts
94
+ - Lottie playback
95
+ - XPC processes
96
+ - user-provided assets
97
+ - filesystem reads after gesture start
98
+ - network access
99
+
100
+ Visual customization is decorative. It can make gestures more legible, delightful, and personal, but it cannot become part of whether a gesture succeeds.
101
+
102
+ In practical terms:
103
+
104
+ - if a renderer fails, the action still runs
105
+ - if an asset is missing, the native fallback overlay appears
106
+ - if an external renderer is slow, it drops frames or misses the gesture
107
+ - if config is invalid, the rule can still match using native trigger/action fields
108
+ - action success/failure is reported from the action layer, not inferred from animation state
109
+
110
+ This boundary should be visible in the code. The gesture controller can emit visual events, but renderers should consume snapshots or markers asynchronously. They should not own recognition state.
111
+
112
+ ## Proposed Customization Model
113
+
114
+ ### 1. Declarative `visual` block first
115
+
116
+ Mouse shortcut rules should support a stable optional `visual` block:
117
+
118
+ ```json
119
+ {
120
+ "id": "back-l-iterm",
121
+ "enabled": true,
122
+ "device": "any",
123
+ "trigger": {
124
+ "button": "back",
125
+ "kind": "shape",
126
+ "shape": "l-shape-down-right"
127
+ },
128
+ "action": {
129
+ "type": "app.activate",
130
+ "app": "iTerm"
131
+ },
132
+ "visual": {
133
+ "renderer": "native",
134
+ "theme": "graffiti",
135
+ "markers": {
136
+ "updated": "follow",
137
+ "recognized:l-shape-down-right": "commit",
138
+ "completed.success": "success",
139
+ "completed.failure": "error"
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ The `visual` block should be optional and ignored by older versions where possible. Its first stable fields should be:
146
+
147
+ | Field | Type | Purpose |
148
+ |---|---|---|
149
+ | `renderer` | string | Selects renderer family: `native`, later `lottie`, later `external` |
150
+ | `theme` | string? | Native preset name such as `minimal`, `graffiti`, `pattern`, `avatar` |
151
+ | `asset` | string? | Local asset reference for renderer families that need it |
152
+ | `character` | string? | Optional named character/avatar inside a renderer or asset pack |
153
+ | `markers` or `events` | object | Maps gesture markers to renderer actions |
154
+
155
+ The POC uses `events`; the product model should choose one name. `markers` is slightly clearer because the keys are not all raw system events. They are renderer-facing semantic markers derived from gesture state.
156
+
157
+ ### 2. Theme presets
158
+
159
+ Before exposing arbitrary assets as the main path, ship native presets:
160
+
161
+ - `minimal`: simple path and endpoint feedback
162
+ - `graffiti`: Bezier trail with energetic completion burst
163
+ - `pattern`: guide dots and shape lock-in feedback
164
+ - `avatar`: native character-style feedback, similar to the POC cat
165
+ - `quiet`: subtle feedback for users who want confirmation without flourish
166
+
167
+ Presets give users customization without loading code or assets. They also give maintainers a reference for the renderer contract.
168
+
169
+ ### 3. Marker mapping
170
+
171
+ Renderer-facing markers should be small, named, and phase-based:
172
+
173
+ | Marker | Meaning |
174
+ |---|---|
175
+ | `started` | Gesture session began |
176
+ | `updated` | Path changed |
177
+ | `recognized:<shape>` | Recognizer has a likely shape |
178
+ | `matched:<rule-id>` | Rule matched |
179
+ | `completed.success` | Action completed successfully |
180
+ | `completed.failure` | Action failed or no rule matched |
181
+ | `cancelled` | Gesture was cancelled |
182
+
183
+ Renderers can map these to animation names, effects, or state transitions:
184
+
185
+ ```json
186
+ {
187
+ "markers": {
188
+ "started": "wake",
189
+ "updated": "follow",
190
+ "recognized:l-shape-down-right": "pounce",
191
+ "completed.success": "celebrate",
192
+ "completed.failure": "confused",
193
+ "cancelled": "hide"
194
+ }
195
+ }
196
+ ```
197
+
198
+ The control path emits facts. The renderer interprets those facts.
199
+
200
+ ### 4. Asset references
201
+
202
+ Asset references should be local file paths or app-bundled names:
203
+
204
+ ```json
205
+ {
206
+ "visual": {
207
+ "renderer": "lottie",
208
+ "asset": "~/.lattices/gesture-assets/cat.json",
209
+ "markers": {
210
+ "updated": "follow",
211
+ "completed.success": "celebrate"
212
+ }
213
+ }
214
+ }
215
+ ```
216
+
217
+ Rules:
218
+
219
+ - expand `~` explicitly
220
+ - resolve relative paths relative to `~/.lattices/`, not the current project
221
+ - do not fetch remote URLs
222
+ - validate extension and size before loading
223
+ - cache parsed assets outside the gesture hot path
224
+ - fall back to `native` if loading fails
225
+
226
+ ### 5. Real Lottie player later
227
+
228
+ The current native shim should not pretend to be production Lottie. The roadmap should be:
229
+
230
+ 1. stabilize the rule schema and marker model
231
+ 2. ship native presets
232
+ 3. add a real Lottie player behind the same renderer protocol
233
+ 4. keep Lottie playback isolated from recognition and action dispatch
234
+
235
+ This avoids coupling the configuration surface to the first graphics library chosen.
236
+
237
+ ### 6. Optional external renderer or XPC later
238
+
239
+ External renderers are powerful, but they are also where latency, crash, and security complexity enters. They should be a later feature, probably via XPC rather than arbitrary process execution.
240
+
241
+ The contract should look like a one-way visual event stream:
242
+
243
+ - Lattices sends gesture snapshots and markers.
244
+ - The renderer returns nothing that affects recognition or actions.
245
+ - The renderer may request drawing surfaces only through a narrow API.
246
+ - Timeouts and crashes are expected and non-fatal.
247
+
248
+ The open source nature of Lattices means users can always recompile experiments. Product customization should be easier and safer than that.
249
+
250
+ ## Config Examples
251
+
252
+ ### Back Button L to iTerm with Native Visual Markers
253
+
254
+ ```json
255
+ {
256
+ "id": "back-l-iterm",
257
+ "enabled": true,
258
+ "device": "any",
259
+ "trigger": {
260
+ "button": "back",
261
+ "kind": "shape",
262
+ "shape": "l-shape-down-right"
263
+ },
264
+ "action": {
265
+ "type": "app.activate",
266
+ "app": "iTerm"
267
+ },
268
+ "visual": {
269
+ "renderer": "native",
270
+ "theme": "pattern",
271
+ "markers": {
272
+ "started": "show-guides",
273
+ "updated": "draw-path",
274
+ "recognized:l-shape-down-right": "lock-shape",
275
+ "completed.success": "success-label",
276
+ "completed.failure": "miss-label"
277
+ }
278
+ }
279
+ }
280
+ ```
281
+
282
+ ### Back Button L to iTerm with Future Lottie Asset
283
+
284
+ ```json
285
+ {
286
+ "id": "back-l-iterm",
287
+ "enabled": true,
288
+ "device": "any",
289
+ "trigger": {
290
+ "button": "back",
291
+ "kind": "shape",
292
+ "shape": "l-shape-down-right"
293
+ },
294
+ "action": {
295
+ "type": "app.activate",
296
+ "app": "iTerm"
297
+ },
298
+ "visual": {
299
+ "renderer": "lottie",
300
+ "asset": "~/.lattices/gesture-assets/cat.json",
301
+ "character": "cat",
302
+ "markers": {
303
+ "started": "wake",
304
+ "updated": "follow",
305
+ "recognized:l-shape-down-right": "pounce",
306
+ "completed.success": "celebrate",
307
+ "completed.failure": "confused",
308
+ "cancelled": "hide"
309
+ }
310
+ }
311
+ }
312
+ ```
313
+
314
+ ### Quiet Native Preset
315
+
316
+ ```json
317
+ {
318
+ "id": "middle-l-palette",
319
+ "enabled": true,
320
+ "trigger": {
321
+ "button": "middle",
322
+ "kind": "shape",
323
+ "shape": "l-shape-down-right"
324
+ },
325
+ "action": {
326
+ "type": "palette.open"
327
+ },
328
+ "visual": {
329
+ "renderer": "native",
330
+ "theme": "quiet"
331
+ }
332
+ }
333
+ ```
334
+
335
+ ## Latency Considerations
336
+
337
+ Gesture UX is latency-sensitive in two places:
338
+
339
+ - recognition should keep up with pointer movement
340
+ - action dispatch should happen as soon as the gesture commits
341
+
342
+ Renderer latency is allowed to be worse than action latency. The user should never feel that an animation is in charge of the system.
343
+
344
+ Implementation guidelines:
345
+
346
+ - use immutable gesture snapshots for renderer updates
347
+ - throttle rendering updates independently from event capture
348
+ - pre-load and validate assets when config changes, not when the gesture begins
349
+ - cap path point history passed to renderers
350
+ - drop visual frames under pressure
351
+ - keep completion labels tied to action receipts, not animation callbacks
352
+
353
+ Target behavior:
354
+
355
+ - action dispatch remains effectively immediate after match
356
+ - native visual feedback tracks the pointer smoothly
357
+ - custom renderer failure is invisible except for fallback visuals or debug logs
358
+
359
+ ## Stability Considerations
360
+
361
+ The gesture system sits near global input, so failure modes must be boring.
362
+
363
+ Renderer failures should not:
364
+
365
+ - disable the event tap
366
+ - wedge gesture state
367
+ - prevent shortcut matching
368
+ - crash the app
369
+ - leave persistent overlay windows stuck on screen
370
+
371
+ Recommended boundaries:
372
+
373
+ - a `GestureVisualRenderer` protocol with small methods such as `start`, `update`, `mark`, `complete`, `cancel`
374
+ - a native fallback renderer that is always available
375
+ - renderer selection that can fail closed to `native`
376
+ - defensive validation of unknown marker names
377
+ - debug logging for invalid visuals, but no noisy user-facing alerts during gestures
378
+
379
+ ## Security Considerations
380
+
381
+ Even though Lattices is open source, normal customization should not require recompilation. That means configuration and assets become part of the product surface and need constraints.
382
+
383
+ For MVP:
384
+
385
+ - no remote asset URLs
386
+ - no shell commands in `visual`
387
+ - no arbitrary scripts
388
+ - no executable plugins
389
+ - local assets only
390
+ - size limits for loaded assets
391
+ - clear fallback when assets are missing or invalid
392
+
393
+ For a future external renderer:
394
+
395
+ - prefer XPC over raw process execution
396
+ - use a narrow, documented message protocol
397
+ - treat renderer output as pixels or visual state only
398
+ - never accept action decisions from the renderer
399
+ - add a user-visible trust/install flow if third-party renderer bundles are supported
400
+
401
+ ## Proposed Internal Shape
402
+
403
+ The implementation should keep the current architecture but name the boundary more explicitly.
404
+
405
+ Possible types:
406
+
407
+ ```swift
408
+ struct GestureVisualConfig {
409
+ let renderer: GestureVisualRendererID
410
+ let theme: String?
411
+ let asset: String?
412
+ let character: String?
413
+ let markers: [String: String]
414
+ }
415
+
416
+ struct GestureVisualSnapshot {
417
+ let sessionID: UUID
418
+ let phase: GesturePhase
419
+ let button: MouseShortcutButton
420
+ let points: [CGPoint]
421
+ let recognizedShape: String?
422
+ let matchedRuleID: String?
423
+ }
424
+
425
+ protocol GestureVisualRenderer {
426
+ func start(_ snapshot: GestureVisualSnapshot, config: GestureVisualConfig)
427
+ func update(_ snapshot: GestureVisualSnapshot)
428
+ func mark(_ marker: String, snapshot: GestureVisualSnapshot)
429
+ func complete(_ marker: String, snapshot: GestureVisualSnapshot)
430
+ func cancel(_ snapshot: GestureVisualSnapshot)
431
+ }
432
+ ```
433
+
434
+ The exact Swift names can differ. The important part is that renderers consume snapshots and markers; they do not mutate recognition state or decide actions.
435
+
436
+ ## Phased Roadmap
437
+
438
+ ### Phase 0: POC Cleanup
439
+
440
+ Goal: make the prototype understandable and safe to keep iterating.
441
+
442
+ - keep native avatar/Lottie shim clearly labeled as POC
443
+ - document current supported marker keys
444
+ - ensure missing or invalid visual config falls back to native overlay
445
+ - verify back/forward button aliases and shape matching remain independent from visuals
446
+
447
+ ### Phase 1: MVP Native Customization
448
+
449
+ Goal: support real user customization without external dependencies.
450
+
451
+ - stabilize the `visual` schema
452
+ - support `renderer: "native"`
453
+ - ship a small set of native themes
454
+ - support marker mapping for native themes
455
+ - load visual config from normal shortcut config
456
+ - add diagnostics for invalid visuals
457
+ - keep existing native overlay as fallback
458
+
459
+ ### Phase 2: Real Lottie Integration
460
+
461
+ Goal: make `renderer: "lottie"` honest.
462
+
463
+ - add a real Lottie player dependency or embedded playback implementation
464
+ - validate and cache Lottie assets outside the gesture hot path
465
+ - map markers to animation segments or named states
466
+ - enforce size and complexity limits
467
+ - provide at least one bundled example asset
468
+
469
+ ### Phase 3: Renderer Hooks and XPC
470
+
471
+ Goal: enable deeper experiments without compromising the app.
472
+
473
+ - define a one-way renderer event protocol
474
+ - run external renderers out of process
475
+ - add crash and timeout handling
476
+ - add user trust/install UX for third-party renderers
477
+ - keep all action decisions inside Lattices
478
+
479
+ ## Open Questions
480
+
481
+ - Should the field be named `events` to match the prototype, or `markers` to better describe the stable concept?
482
+ - Should visual config live only on individual rules, or should users be able to define reusable named visual profiles?
483
+ - How much of `MouseGestureOverlay` should become a renderer implementation versus remaining a fallback shell?
484
+ - Should marker names be fully free-form, or should unknown keys be rejected during config validation?
485
+ - Do we want app-level theme defaults, per-device defaults, or only per-rule visuals for MVP?
486
+ - Should `completed.failure` mean "no rule matched", "action failed", or both with more specific submarkers?
487
+ - Where should user assets live: `~/.lattices/gesture-assets/`, app support, or both?
488
+
489
+ ## Acceptance Criteria
490
+
491
+ For the MVP:
492
+
493
+ - A shortcut rule can include a `visual` block without changing trigger or action behavior.
494
+ - A back-button `l-shape-down-right` rule can activate iTerm and show native marker-based feedback.
495
+ - Invalid visual config falls back to the native overlay and does not prevent the action.
496
+ - Missing assets do not crash the app or delay gesture completion.
497
+ - Recognition and action dispatch do not wait on renderer work.
498
+ - Native themes can render started, updated, recognized, success, failure, and cancelled states.
499
+ - The config format is documented with at least one complete example.
500
+ - Debug diagnostics make renderer fallback understandable to maintainers.
501
+
502
+ For later Lottie support:
503
+
504
+ - `renderer: "lottie"` uses a real Lottie player, not the native shim.
505
+ - Lottie assets are validated and cached before gesture start.
506
+ - Marker mappings can target named animations or segments.
507
+ - Lottie renderer failure falls back to native rendering without affecting actions.
508
+
509
+ ## Recommendation
510
+
511
+ Productize visual customization, but productize it as a renderer contract rather than as a graphics feature.
512
+
513
+ The useful product surface is not "play a cat animation." It is:
514
+
515
+ - gestures have stable semantic markers
516
+ - users can bind visual feedback to those markers
517
+ - Lattices keeps input and action dispatch fast
518
+ - renderers are replaceable decoration
519
+
520
+ That gives maintainers room to ship the fun parts without letting them become load-bearing.