@lattices/cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +85 -9
  2. package/app/Package.swift +8 -1
  3. package/app/Sources/AdvisorLearningStore.swift +90 -0
  4. package/app/Sources/AgentSession.swift +377 -0
  5. package/app/Sources/AppDelegate.swift +44 -12
  6. package/app/Sources/AppShellView.swift +81 -8
  7. package/app/Sources/AudioProvider.swift +386 -0
  8. package/app/Sources/CheatSheetHUD.swift +261 -19
  9. package/app/Sources/DaemonProtocol.swift +13 -0
  10. package/app/Sources/DaemonServer.swift +8 -0
  11. package/app/Sources/DesktopModel.swift +164 -5
  12. package/app/Sources/DesktopModelTypes.swift +2 -0
  13. package/app/Sources/DiagnosticLog.swift +104 -2
  14. package/app/Sources/EventBus.swift +1 -0
  15. package/app/Sources/HUDBottomBar.swift +279 -0
  16. package/app/Sources/HUDController.swift +1158 -0
  17. package/app/Sources/HUDLeftBar.swift +849 -0
  18. package/app/Sources/HUDMinimap.swift +179 -0
  19. package/app/Sources/HUDRightBar.swift +774 -0
  20. package/app/Sources/HUDState.swift +367 -0
  21. package/app/Sources/HUDTopBar.swift +243 -0
  22. package/app/Sources/HandsOffSession.swift +733 -0
  23. package/app/Sources/HomeDashboardView.swift +125 -0
  24. package/app/Sources/HotkeyManager.swift +2 -0
  25. package/app/Sources/HotkeyStore.swift +45 -9
  26. package/app/Sources/IntentEngine.swift +925 -0
  27. package/app/Sources/Intents/CreateLayerIntent.swift +54 -0
  28. package/app/Sources/Intents/DistributeIntent.swift +56 -0
  29. package/app/Sources/Intents/FocusIntent.swift +69 -0
  30. package/app/Sources/Intents/HelpIntent.swift +41 -0
  31. package/app/Sources/Intents/KillIntent.swift +47 -0
  32. package/app/Sources/Intents/LatticeIntent.swift +78 -0
  33. package/app/Sources/Intents/LaunchIntent.swift +67 -0
  34. package/app/Sources/Intents/ListSessionsIntent.swift +32 -0
  35. package/app/Sources/Intents/ListWindowsIntent.swift +30 -0
  36. package/app/Sources/Intents/ScanIntent.swift +52 -0
  37. package/app/Sources/Intents/SearchIntent.swift +190 -0
  38. package/app/Sources/Intents/SwitchLayerIntent.swift +50 -0
  39. package/app/Sources/Intents/TileIntent.swift +61 -0
  40. package/app/Sources/LatticesApi.swift +1235 -30
  41. package/app/Sources/LauncherHUD.swift +348 -0
  42. package/app/Sources/MainView.swift +147 -44
  43. package/app/Sources/OcrModel.swift +34 -1
  44. package/app/Sources/OmniSearchState.swift +99 -102
  45. package/app/Sources/OnboardingView.swift +457 -0
  46. package/app/Sources/PermissionChecker.swift +2 -12
  47. package/app/Sources/PiChatDock.swift +454 -0
  48. package/app/Sources/PiChatSession.swift +815 -0
  49. package/app/Sources/PiWorkspaceView.swift +364 -0
  50. package/app/Sources/PlacementSpec.swift +195 -0
  51. package/app/Sources/Preferences.swift +59 -0
  52. package/app/Sources/ProjectScanner.swift +1 -1
  53. package/app/Sources/ScreenMapState.swift +701 -55
  54. package/app/Sources/ScreenMapView.swift +843 -103
  55. package/app/Sources/ScreenMapWindowController.swift +22 -0
  56. package/app/Sources/SessionLayerStore.swift +285 -0
  57. package/app/Sources/SessionManager.swift +4 -1
  58. package/app/Sources/SettingsView.swift +186 -3
  59. package/app/Sources/Theme.swift +9 -8
  60. package/app/Sources/TmuxModel.swift +7 -0
  61. package/app/Sources/TmuxQuery.swift +27 -3
  62. package/app/Sources/VoiceChatView.swift +192 -0
  63. package/app/Sources/VoiceCommandWindow.swift +1594 -0
  64. package/app/Sources/VoiceIntentResolver.swift +671 -0
  65. package/app/Sources/VoxClient.swift +454 -0
  66. package/app/Sources/WindowTiler.swift +348 -87
  67. package/app/Sources/WorkspaceManager.swift +127 -18
  68. package/bin/client.ts +16 -0
  69. package/bin/{daemon-client.js → daemon-client.ts} +49 -30
  70. package/bin/handsoff-infer.ts +280 -0
  71. package/bin/handsoff-worker.ts +731 -0
  72. package/bin/{lattices-app.js → lattices-app.ts} +67 -32
  73. package/bin/lattices-dev +160 -0
  74. package/bin/{lattices.js → lattices.ts} +600 -137
  75. package/bin/project-twin.ts +645 -0
  76. package/docs/agent-execution-plan.md +562 -0
  77. package/docs/agents.md +142 -0
  78. package/docs/api.md +153 -34
  79. package/docs/app.md +29 -1
  80. package/docs/config.md +5 -1
  81. package/docs/handsoff-test-scenarios.md +84 -0
  82. package/docs/layers.md +20 -20
  83. package/docs/ocr.md +14 -5
  84. package/docs/overview.md +5 -1
  85. package/docs/presentation-execution-review.md +491 -0
  86. package/docs/prompts/hands-off-system.md +374 -0
  87. package/docs/prompts/hands-off-turn.md +30 -0
  88. package/docs/prompts/voice-advisor.md +31 -0
  89. package/docs/prompts/voice-fallback.md +23 -0
  90. package/docs/tiling-reference.md +167 -0
  91. package/docs/twins.md +138 -0
  92. package/docs/voice-command-protocol.md +278 -0
  93. package/docs/voice.md +219 -0
  94. package/package.json +21 -10
  95. package/bin/client.js +0 -4
@@ -0,0 +1,491 @@
1
+ # Presentation And Execution Review
2
+
3
+ This note reviews the current Lattices presentation layer, the tiling and intent-to-outcome pipeline behind it, and a direction for tightening execution logic. It also pulls in relevant ideas from Hyprland and Wayland, using primary sources only.
4
+
5
+ ## Why this document exists
6
+
7
+ Lattices already has strong operator-facing surfaces:
8
+
9
+ - HUD and keyboard-driven interaction
10
+ - local voice mode
11
+ - hands-off voice mode
12
+ - command palette
13
+ - desktop inventory and search
14
+
15
+ What is still under-shaped is the execution core behind those surfaces. Today the UX is ahead of the action model.
16
+
17
+ The root issue is not "tiling quality" in isolation. The deeper issue is that Lattices has multiple control surfaces, multiple intent grammars, and multiple direct execution paths that do not converge on a single canonical planner/executor.
18
+
19
+ ## Review scope
20
+
21
+ This review is based on:
22
+
23
+ - `app/Sources/WindowTiler.swift`
24
+ - `app/Sources/WorkspaceManager.swift`
25
+ - `app/Sources/IntentEngine.swift`
26
+ - `app/Sources/VoiceIntentResolver.swift`
27
+ - `app/Sources/LatticesApi.swift`
28
+ - `app/Sources/PaletteCommand.swift`
29
+ - `app/Sources/HUDController.swift`
30
+ - `app/Sources/DesktopModel.swift`
31
+ - `app/Sources/HandsOffSession.swift`
32
+ - `docs/voice-command-protocol.md`
33
+
34
+ ## Current Architecture
35
+
36
+ ### 1. Presentation surfaces are rich, but execution is fragmented
37
+
38
+ Lattices currently has at least five operator surfaces:
39
+
40
+ | Surface | Main files | How it resolves intent | How it executes |
41
+ |---|---|---|---|
42
+ | Command palette | `PaletteCommand.swift`, `CommandPaletteView.swift` | No semantic resolution | Calls `SessionManager`, `WindowTiler`, `WorkspaceManager` directly |
43
+ | HUD | `HUDController.swift` | Hardcoded key routing | Calls `WindowTiler` and `HandsOffSession` directly |
44
+ | Local voice | `VoiceCommandWindow.swift`, `VoiceIntentResolver.swift`, `IntentEngine.swift` | NL embedding + heuristics + slot extraction | Mix of `LatticesApi` dispatch and direct `WindowTiler` calls |
45
+ | Hands-off voice | `HandsOffSession.swift` | External worker returns action list | Replays actions through `PhraseMatcher` / `IntentEngine` |
46
+ | Daemon / API | `LatticesApi.swift`, `DaemonServer.swift` | Structured request only | Calls subsystems directly |
47
+
48
+ The result is a split brain:
49
+
50
+ - presentation is centralized in the app
51
+ - execution is not centralized in one action engine
52
+
53
+ ### 2. Tiling itself is reasonably capable
54
+
55
+ `WindowTiler.swift` already has solid building blocks:
56
+
57
+ - named positions from halves up through sixths and eighths
58
+ - generic `grid:CxR:C,R` support
59
+ - frame derivation against `visibleFrame`
60
+ - fast path via `DesktopModel`
61
+ - AX fallback
62
+ - AppleScript fallback
63
+ - batch moves and raises
64
+ - space discovery and limited space movement
65
+
66
+ That is a good substrate. The problem is not the absence of tiling primitives. The problem is that these primitives are reached through different decision systems.
67
+
68
+ ### 3. Layer tiling is the closest thing to an orchestrator
69
+
70
+ `WorkspaceManager.tileLayer(...)` is the most complete execution pipeline in the app today. It already does:
71
+
72
+ 1. inventory refresh
73
+ 2. classification of running vs missing windows
74
+ 3. batched moves for known windows
75
+ 4. fallbacks for untracked windows
76
+ 5. launch queue for missing projects/apps
77
+ 6. delayed post-launch tiling
78
+
79
+ This is useful, but it is still a per-feature orchestrator, not the shared execution model for the whole product.
80
+
81
+ ### 4. Intent conversion currently exists in multiple incompatible forms
82
+
83
+ There are several distinct ways to convert a user goal into motion:
84
+
85
+ - HUD key map in `HUDController`
86
+ - local voice extraction in `VoiceIntentResolver`
87
+ - intent handlers in `IntentEngine`
88
+ - direct daemon calls in `LatticesApi`
89
+ - hands-off worker action generation in `HandsOffSession`
90
+
91
+ These systems overlap, but they are not the same system.
92
+
93
+ ## Root-Cause Findings
94
+
95
+ ### 1. There is no canonical action schema
96
+
97
+ The core missing layer is a first-class action model. Right now Lattices mostly jumps from:
98
+
99
+ - UI event -> subsystem method
100
+
101
+ instead of:
102
+
103
+ - UI event -> canonical action -> planner -> validated execution -> result
104
+
105
+ That is why each surface grows its own grammar and shortcuts.
106
+
107
+ ### 2. Intent resolution and execution are coupled too early
108
+
109
+ `IntentEngine` mixes:
110
+
111
+ - slot validation
112
+ - target resolution
113
+ - direct side effects
114
+
115
+ That makes it harder to:
116
+
117
+ - preview what will happen
118
+ - batch actions coherently
119
+ - deduplicate targets
120
+ - rollback or retry
121
+ - explain why a request failed before side effects begin
122
+
123
+ ### 3. Presentation layers still own execution semantics
124
+
125
+ Examples:
126
+
127
+ - command palette actions directly call `WindowTiler` / `SessionManager`
128
+ - HUD tile mode computes its own ad hoc grid and applies it immediately
129
+ - local voice can go through `LatticesApi` or bypass it
130
+ - hands-off voice replays actions one by one rather than committing a single execution plan
131
+
132
+ This means the product does not yet have one source of truth for "what operation means" or "what order side effects should occur in."
133
+
134
+ ### 4. The system is not transactional
135
+
136
+ Wayland's most useful idea here is not Linux-specific rendering. It is commit discipline.
137
+
138
+ Lattices currently performs many operations incrementally:
139
+
140
+ - poll desktop
141
+ - start moving known windows
142
+ - navigate to missing windows
143
+ - launch apps
144
+ - tile launched apps later
145
+
146
+ That produces useful behavior, but not an explicit transaction model. The user intent is "arrange my workspace", but implementation today is "execute a staggered set of best-effort side effects."
147
+
148
+ ### 5. Window identity is still mostly heuristic
149
+
150
+ The current system relies on:
151
+
152
+ - `[lattices:session-name]` title tags for terminal windows
153
+ - `app + title substring` matching for non-terminal windows
154
+ - a `DesktopModel` cache plus CG/AX fallbacks
155
+
156
+ This is workable, but it is not yet elevated into a durable target-resolution layer with confidence, ambiguity handling, or plan-time diagnostics.
157
+
158
+ ### 6. The product has multiple position grammars
159
+
160
+ At minimum there are separate position systems in:
161
+
162
+ - `TilePosition`
163
+ - `parseGridString(...)`
164
+ - `VoiceIntentResolver.resolvePosition(...)`
165
+ - HUD key routing
166
+ - hands-off worker output
167
+ - daemon `window.tile`
168
+
169
+ The existence of `TilePosition` suggests there should be one canonical placement language. In practice there are several.
170
+
171
+ ## What Hyprland Gets Right
172
+
173
+ ### 1. One mutation surface: dispatchers
174
+
175
+ Hyprland exposes a consistent mutation model: `hyprctl dispatch ...` calls compositor dispatchers rather than inventing a new command path for each UI. That is the right mental model for Lattices too.
176
+
177
+ For Lattices, the equivalent should be:
178
+
179
+ - one canonical action registry
180
+ - many presentation surfaces
181
+ - one executor
182
+
183
+ ### 2. Separate control from live observation
184
+
185
+ Hyprland separates:
186
+
187
+ - control/info requests via `hyprctl` / request socket
188
+ - live events via `socket2`
189
+
190
+ That split is useful for Lattices. The app already has an `EventBus`, but execution still often assumes fresh polling instead of treating live state and mutations as distinct first-class channels.
191
+
192
+ ### 3. Rules are first-class, not hidden glue
193
+
194
+ Hyprland's window rules are useful not because Lattices should copy them literally, but because they formalize policy:
195
+
196
+ - what should open where
197
+ - when rules are evaluated
198
+ - which rules are static vs dynamic
199
+
200
+ Lattices currently has pieces of this spread across:
201
+
202
+ - layer project specs
203
+ - companion `windows` entries
204
+ - session naming
205
+ - title matching
206
+ - ad hoc fallback behavior
207
+
208
+ These want to become an explicit rule engine.
209
+
210
+ ### 4. Layout engines are explicit and addressable
211
+
212
+ Hyprland treats layout strategy as a named concept:
213
+
214
+ - `master`
215
+ - `dwindle`
216
+ - per-layout config
217
+ - layout-specific dispatchers / layout messages
218
+
219
+ Lattices currently has positions, grids, layer tiling, and distribute logic, but not named layout engines with their own semantics. That is why many arrangements still feel like clever commands rather than stable workspace behaviors.
220
+
221
+ ## What Wayland Gets Right
222
+
223
+ ### 1. Clear object roles
224
+
225
+ Wayland's `wl_surface` becomes meaningful through roles such as toplevel and popup. That separation matters.
226
+
227
+ Lattices needs the same distinction between:
228
+
229
+ - raw windows
230
+ - lattices session windows
231
+ - companion app windows
232
+ - HUD utility windows
233
+ - layout targets
234
+ - execution results
235
+
236
+ Right now these concepts are present, but not formalized strongly enough in the execution model.
237
+
238
+ ### 2. Requests and events are different things
239
+
240
+ Wayland's protocol model is built around objects with requests and events. Lattices should mirror that more explicitly:
241
+
242
+ - requests mutate state
243
+ - events report state changes
244
+ - snapshots are derived, not the mutation API
245
+
246
+ Today those concerns blur together in some places.
247
+
248
+ ### 3. Pending state vs applied state
249
+
250
+ This is the biggest transferable idea.
251
+
252
+ Wayland's surface lifecycle makes state changes pending until commit. Lattices should adopt the same pattern for workspace arrangement:
253
+
254
+ - resolve targets
255
+ - compute plan
256
+ - validate plan
257
+ - commit plan
258
+ - publish result
259
+
260
+ Without this, "organize my windows" will always be less predictable than it should be.
261
+
262
+ ### 4. Configure / acknowledge / commit
263
+
264
+ Wayland's configure-and-ack flow is a good model for coordination between planner and executor:
265
+
266
+ - planner proposes a layout/result
267
+ - executor acknowledges what can be applied
268
+ - final commit produces the visible outcome
269
+
270
+ For Lattices, this suggests explicit execution receipts, not just side effects plus logging.
271
+
272
+ ## Proposed Direction For Lattices
273
+
274
+ ### 1. Introduce a canonical action model
275
+
276
+ Every surface should emit the same internal action envelope:
277
+
278
+ ```json
279
+ {
280
+ "intent": "window.tile",
281
+ "targets": [{ "kind": "wid", "value": 1234 }],
282
+ "args": { "position": "left" },
283
+ "source": "voice-local"
284
+ }
285
+ ```
286
+
287
+ Not all actions need to originate from voice. The important part is that command palette, HUD, daemon, and worker output all normalize into the same model.
288
+
289
+ ### 2. Split the pipeline into four layers
290
+
291
+ ### A. Interpretation
292
+
293
+ Converts user input into canonical actions.
294
+
295
+ Examples:
296
+
297
+ - keyboard chord -> action
298
+ - transcript -> action
299
+ - daemon JSON -> action
300
+
301
+ ### B. Planning
302
+
303
+ Resolves targets and composes a layout plan.
304
+
305
+ Examples:
306
+
307
+ - which exact window does "Chrome" mean
308
+ - which screen should `left-third` land on
309
+ - whether a missing project should be launched
310
+ - whether multiple actions should be merged into one transaction
311
+
312
+ ### C. Execution
313
+
314
+ Applies the plan through one executor.
315
+
316
+ Examples:
317
+
318
+ - batch move these windows
319
+ - focus this session
320
+ - launch these apps
321
+ - wait for these windows to appear
322
+ - commit final arrangement
323
+
324
+ ### D. Presentation
325
+
326
+ Shows:
327
+
328
+ - preview
329
+ - progress
330
+ - result
331
+ - failure
332
+
333
+ The key point is that presentation should no longer define semantics.
334
+
335
+ ### 3. Create a real arrangement transaction
336
+
337
+ Lattices should have a type along these lines:
338
+
339
+ - `ArrangementIntent`
340
+ - `ArrangementPlan`
341
+ - `ArrangementTransaction`
342
+ - `ArrangementResult`
343
+
344
+ An arrangement transaction should carry:
345
+
346
+ - requested actions
347
+ - resolved targets
348
+ - preconditions
349
+ - fallback strategy
350
+ - steps
351
+ - partial failures
352
+ - final applied state
353
+
354
+ That gives the app a place for:
355
+
356
+ - preview before commit
357
+ - retries
358
+ - rollback where possible
359
+ - voice confirmation
360
+ - better diagnostics than raw log lines
361
+
362
+ ### 4. Unify the placement grammar
363
+
364
+ There should be exactly one placement language.
365
+
366
+ That language should cover:
367
+
368
+ - named positions
369
+ - grid cells
370
+ - screen/display selection
371
+ - optional grouping semantics
372
+ - optional relative semantics like "stack" or "master"
373
+
374
+ Everything else should compile into it, including:
375
+
376
+ - HUD keys
377
+ - voice phrases
378
+ - daemon requests
379
+ - future scripting
380
+
381
+ `VoiceIntentResolver` should not own a separate smaller placement universe.
382
+
383
+ ### 5. Promote rules to a first-class subsystem
384
+
385
+ Lattices should formalize:
386
+
387
+ - static rules: applied on launch or first attach
388
+ - dynamic rules: re-evaluated when window properties or workspace state changes
389
+
390
+ Examples:
391
+
392
+ - project session window belongs on display 2 left half
393
+ - browser matching title X belongs beside project Y
394
+ - voice/HUD utility panels are never layout targets
395
+ - session windows for a layer open silently until plan commit
396
+
397
+ This is the clearest Hyprland-inspired gap in the current design.
398
+
399
+ ### 6. Treat layout strategy as a pluggable engine
400
+
401
+ Instead of "tile to coordinates" being the only real abstraction, Lattices should support named layout engines, for example:
402
+
403
+ - `stack`
404
+ - `master`
405
+ - `grid`
406
+ - `bsp`
407
+ - `focus-ring`
408
+ - `review`
409
+
410
+ Each layout engine can expose:
411
+
412
+ - configuration
413
+ - planning logic
414
+ - compact mutation messages
415
+
416
+ That is the Hyprland lesson from `master`, `dwindle`, and `layoutmsg`: layout should be semantic, not just positional.
417
+
418
+ ### 7. Make the daemon the canonical external executor boundary
419
+
420
+ The daemon already has enough shape to become the stable mutation boundary, but it should move from "RPC bag of commands" toward:
421
+
422
+ - state snapshot endpoints
423
+ - event stream
424
+ - action submission
425
+ - transaction status / receipts
426
+
427
+ The app can still call internals directly, but conceptually it should use the same execution core the daemon exposes.
428
+
429
+ ## What This Means For Existing Features
430
+
431
+ ### HUD
432
+
433
+ The HUD should remain fast and tactile, but its keys should emit canonical actions or layout messages, not direct tiler calls with private semantics.
434
+
435
+ ### Local voice
436
+
437
+ Local voice should only do:
438
+
439
+ - transcript normalization
440
+ - action extraction
441
+
442
+ It should not decide execution policy inline.
443
+
444
+ ### Hands-off voice
445
+
446
+ The worker should emit canonical actions only. Swift should not need to reinterpret those actions through a second matcher.
447
+
448
+ ### Command palette
449
+
450
+ Palette commands should become thin wrappers over canonical actions, which makes them previewable and scriptable for free.
451
+
452
+ ### Layers
453
+
454
+ `WorkspaceManager.tileLayer(...)` should evolve into a planner/executor user, not remain a special-case orchestration island.
455
+
456
+ ## Concrete Recommendation
457
+
458
+ If I had to reduce this to one architectural move, it would be:
459
+
460
+ **Build a single action planner/executor and force every surface to go through it.**
461
+
462
+ That one move solves the deepest problems:
463
+
464
+ - duplicate intent logic
465
+ - duplicate position grammars
466
+ - direct UI-owned side effects
467
+ - lack of previews and execution receipts
468
+ - hard-to-reason-about batch behavior
469
+
470
+ ## Suggested Implementation Order
471
+
472
+ 1. Define canonical action and target schemas.
473
+ 2. Extract a placement grammar module shared by voice, HUD, daemon, and layer logic.
474
+ 3. Introduce `ArrangementPlan` plus an executor that can batch, defer, and report.
475
+ 4. Migrate `window.tile`, `layout.distribute`, and layer switching onto that executor first.
476
+ 5. Make local voice and hands-off worker emit canonical actions only.
477
+ 6. Add preview/result receipts to HUD and voice surfaces.
478
+ 7. Add first-class rules and named layout engines after the core path is stable.
479
+
480
+ ## Primary References
481
+
482
+ - [Hyprland: Using hyprctl](https://wiki.hypr.land/Configuring/Using-hyprctl/)
483
+ - [Hyprland: IPC](https://wiki.hypr.land/0.54.0/IPC/)
484
+ - [Hyprland: Window Rules](https://wiki.hypr.land/0.51.0/Configuring/Window-Rules/)
485
+ - [Hyprland: Dwindle Layout](https://wiki.hypr.land/Configuring/Dwindle-Layout/)
486
+ - [Hyprland: Master Layout](https://wiki.hypr.land/Configuring/Master-Layout/)
487
+ - [Wayland project overview](https://wayland.freedesktop.org/index.html)
488
+ - [Wayland Book: Interfaces, requests, and events](https://wayland-book.com/protocol-design/interfaces-reqs-events.html)
489
+ - [Wayland Book: Surface lifecycle](https://wayland-book.com/surfaces-in-depth/lifecycle.html)
490
+ - [Wayland Book: XDG shell basics](https://wayland-book.com/xdg-shell-basics.html)
491
+ - [Wayland Book: Configuration & lifecycle](https://wayland-book.com/xdg-shell-in-depth/configuration.html)