@arach/lattices 0.2.1 → 0.6.1
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.
- package/LICENSE +21 -0
- package/README.md +144 -69
- package/apps/mac/Info.plist +43 -0
- package/apps/mac/Lattices.app/Contents/Info.plist +43 -0
- package/apps/mac/Lattices.app/Contents/MacOS/Lattices +0 -0
- package/apps/mac/Lattices.app/Contents/Resources/AppIcon.icns +0 -0
- package/apps/mac/Lattices.app/Contents/Resources/docs/assistant-knowledge.md +130 -0
- package/apps/mac/Lattices.app/Contents/Resources/tap.wav +0 -0
- package/apps/mac/Lattices.app/Contents/_CodeSignature/CodeResources +150 -0
- package/apps/mac/Lattices.entitlements +21 -0
- package/apps/mac/Resources/Pets/assistant-spark/pet.json +62 -0
- package/apps/mac/Resources/Pets/assistant-spark/spritesheet.webp +0 -0
- package/apps/mac/Resources/Pets/scout-ranger/pet.json +6 -0
- package/apps/mac/Resources/Pets/scout-ranger/spritesheet.webp +0 -0
- package/apps/mac/Resources/tap.wav +0 -0
- package/assets/AppIcon.icns +0 -0
- package/bin/assistant-intelligence.ts +912 -0
- package/bin/cli/capture.ts +252 -0
- package/bin/cli/daemon.ts +22 -0
- package/bin/cli/helpers.ts +105 -0
- package/bin/cli/layer.ts +178 -0
- package/bin/cli/runs.ts +43 -0
- package/bin/cli/search.ts +141 -0
- package/bin/cli/session.ts +32 -0
- package/bin/client.ts +17 -0
- package/bin/cua.ts +26 -0
- package/bin/{daemon-client.js → daemon-client.ts} +49 -30
- package/bin/handsoff-infer.ts +96 -0
- package/bin/handsoff-worker.ts +531 -0
- package/bin/infer.ts +424 -0
- package/bin/keychain.ts +75 -0
- package/bin/lattices-app.ts +655 -0
- package/bin/lattices-build +125 -0
- package/bin/lattices-build-env.ts +77 -0
- package/bin/lattices-dev +362 -0
- package/bin/lattices.ts +3260 -0
- package/bin/project-twin.ts +645 -0
- package/docs/agent-execution-plan.md +562 -0
- package/docs/agent-layer-guide.md +207 -0
- package/docs/agents.md +233 -0
- package/docs/ai-chat-ux-review.md +416 -0
- package/docs/api.md +1041 -47
- package/docs/app.md +96 -13
- package/docs/assistant-knowledge.md +130 -0
- package/docs/companion-deck.md +209 -0
- package/docs/component-extraction-roadmap.md +392 -0
- package/docs/concepts.md +13 -12
- package/docs/config.md +83 -10
- package/docs/gesture-customization-proposal.md +520 -0
- package/docs/handsoff-test-scenarios.md +84 -0
- package/docs/hyperspace-grid-snappiness.md +210 -0
- package/docs/layers.md +176 -28
- package/docs/mouse-gestures.md +244 -0
- package/docs/ocr.md +21 -9
- package/docs/overview.md +42 -23
- package/docs/presentation-execution-review.md +491 -0
- package/docs/prompts/hands-off-system.md +382 -0
- package/docs/prompts/hands-off-turn.md +30 -0
- package/docs/prompts/voice-advisor.md +31 -0
- package/docs/prompts/voice-fallback.md +23 -0
- package/docs/proposals/LAT-001-gesture-visual-customization.md +522 -0
- package/docs/proposals/LAT-002-shared-overlay-canvas.md +353 -0
- package/docs/proposals/LAT-003-menu-bar-controller-architecture.md +291 -0
- package/docs/proposals/LAT-004-interactive-overlay-actors.md +534 -0
- package/docs/proposals/LAT-005-action-runtime-product-spine.md +914 -0
- package/docs/proposals/LAT-006-followup-gaps.md +103 -0
- package/docs/proposals/LAT-006-runs-and-capture-in-lattices.md +566 -0
- package/docs/proposals/LAT-007-unified-app-shell.md +128 -0
- package/docs/quickstart.md +8 -12
- package/docs/reference/dewey.config.ts +74 -0
- package/docs/reference/install-agent.md +79 -0
- package/docs/release.md +172 -0
- package/docs/repo-structure.md +100 -0
- package/docs/terminal-kit.md +87 -0
- package/docs/tiling-reference.md +224 -0
- package/docs/twins.md +138 -0
- package/docs/voice-command-protocol.md +278 -0
- package/docs/voice-error-model.md +73 -0
- package/docs/voice.md +221 -0
- package/package.json +69 -16
- package/packages/npm/sdk/cua.d.mts +1 -0
- package/packages/npm/sdk/cua.d.ts +188 -0
- package/packages/npm/sdk/cua.mjs +376 -0
- package/app/Lattices.app/Contents/Info.plist +0 -24
- package/app/Package.swift +0 -13
- package/app/Sources/ActionRow.swift +0 -61
- package/app/Sources/App.swift +0 -10
- package/app/Sources/AppDelegate.swift +0 -234
- package/app/Sources/AppShellView.swift +0 -62
- package/app/Sources/AppTypeClassifier.swift +0 -70
- package/app/Sources/AppWindowShell.swift +0 -63
- package/app/Sources/CheatSheetHUD.swift +0 -332
- package/app/Sources/CommandModeState.swift +0 -1362
- package/app/Sources/CommandModeView.swift +0 -1405
- package/app/Sources/CommandModeWindow.swift +0 -192
- package/app/Sources/CommandPaletteView.swift +0 -307
- package/app/Sources/CommandPaletteWindow.swift +0 -134
- package/app/Sources/DaemonProtocol.swift +0 -101
- package/app/Sources/DaemonServer.swift +0 -414
- package/app/Sources/DesktopModel.swift +0 -121
- package/app/Sources/DesktopModelTypes.swift +0 -71
- package/app/Sources/DiagnosticLog.swift +0 -271
- package/app/Sources/EventBus.swift +0 -30
- package/app/Sources/HotkeyManager.swift +0 -250
- package/app/Sources/HotkeyStore.swift +0 -338
- package/app/Sources/InventoryManager.swift +0 -35
- package/app/Sources/InventoryPath.swift +0 -43
- package/app/Sources/KeyRecorderView.swift +0 -210
- package/app/Sources/LatticesApi.swift +0 -1125
- package/app/Sources/MainView.swift +0 -467
- package/app/Sources/MainWindow.swift +0 -83
- package/app/Sources/OcrModel.swift +0 -309
- package/app/Sources/OcrStore.swift +0 -295
- package/app/Sources/OmniSearchState.swift +0 -283
- package/app/Sources/OmniSearchView.swift +0 -288
- package/app/Sources/OmniSearchWindow.swift +0 -105
- package/app/Sources/OrphanRow.swift +0 -129
- package/app/Sources/PaletteCommand.swift +0 -419
- package/app/Sources/PermissionChecker.swift +0 -125
- package/app/Sources/Preferences.swift +0 -92
- package/app/Sources/ProcessModel.swift +0 -199
- package/app/Sources/ProcessQuery.swift +0 -151
- package/app/Sources/Project.swift +0 -28
- package/app/Sources/ProjectRow.swift +0 -368
- package/app/Sources/ProjectScanner.swift +0 -121
- package/app/Sources/ScreenMapState.swift +0 -2387
- package/app/Sources/ScreenMapView.swift +0 -2820
- package/app/Sources/ScreenMapWindowController.swift +0 -89
- package/app/Sources/SessionManager.swift +0 -72
- package/app/Sources/SettingsView.swift +0 -1053
- package/app/Sources/SettingsWindow.swift +0 -20
- package/app/Sources/TabGroupRow.swift +0 -178
- package/app/Sources/Terminal.swift +0 -259
- package/app/Sources/TerminalQuery.swift +0 -156
- package/app/Sources/TerminalSynthesizer.swift +0 -200
- package/app/Sources/Theme.swift +0 -163
- package/app/Sources/TilePickerView.swift +0 -209
- package/app/Sources/TmuxModel.swift +0 -53
- package/app/Sources/TmuxQuery.swift +0 -81
- package/app/Sources/WindowTiler.swift +0 -1755
- package/app/Sources/WorkspaceManager.swift +0 -434
- package/bin/lattices-app.js +0 -221
- package/bin/lattices.js +0 -1418
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
# Component Extraction Roadmap
|
|
2
|
+
|
|
3
|
+
This note turns a codebase review into an incremental component plan for `lattices`.
|
|
4
|
+
|
|
5
|
+
The goal is not to rewrite the app around a new architecture in one move. The goal is to extract a few reusable primitives that make future features cheaper:
|
|
6
|
+
|
|
7
|
+
- a cmdcmd-style visual window or session switcher
|
|
8
|
+
- one shared action model across hotkeys, palette, voice, daemon, and companion
|
|
9
|
+
- less duplicated window lookup, space lookup, and preview logic
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
Three pressure points showed up repeatedly:
|
|
14
|
+
|
|
15
|
+
1. `WindowTiler.swift` acts like several libraries at once.
|
|
16
|
+
2. action definitions exist in multiple parallel forms.
|
|
17
|
+
3. overlay and panel shells are repeatedly rebuilt per surface.
|
|
18
|
+
|
|
19
|
+
The result is that new UX surfaces often have to re-solve the same problems:
|
|
20
|
+
|
|
21
|
+
- how to find a target window
|
|
22
|
+
- how to map a user intent to a canonical action
|
|
23
|
+
- how to show a floating interactive surface
|
|
24
|
+
- how to capture and render previews
|
|
25
|
+
|
|
26
|
+
## Current duplication seams
|
|
27
|
+
|
|
28
|
+
### 1. Window and session lookup
|
|
29
|
+
|
|
30
|
+
The same session-tagged window matching idea appears in multiple places:
|
|
31
|
+
|
|
32
|
+
- `DesktopModel.windowForSession(...)`
|
|
33
|
+
- tag parsing during desktop polling
|
|
34
|
+
- CG window lookup paths in `WindowTiler`
|
|
35
|
+
- AX window lookup paths in `WindowTiler`
|
|
36
|
+
|
|
37
|
+
This is the strongest candidate for a single reusable locator.
|
|
38
|
+
|
|
39
|
+
### 2. Space topology and window membership
|
|
40
|
+
|
|
41
|
+
Display-space maps, current-space discovery, and window-space membership are rebuilt in several flows instead of being queried from one read model.
|
|
42
|
+
|
|
43
|
+
This makes space-aware features harder than they need to be:
|
|
44
|
+
|
|
45
|
+
- move window to space
|
|
46
|
+
- present window on the current space
|
|
47
|
+
- show where a session already lives
|
|
48
|
+
- build a visual desktop map
|
|
49
|
+
|
|
50
|
+
### 3. Window presentation and motion
|
|
51
|
+
|
|
52
|
+
`tile`, `present`, `batchMoveAndRaiseWindows`, and related paths all contain their own versions of:
|
|
53
|
+
|
|
54
|
+
- resolve target
|
|
55
|
+
- move or resize
|
|
56
|
+
- raise
|
|
57
|
+
- activate app
|
|
58
|
+
- mark interaction
|
|
59
|
+
|
|
60
|
+
That sequencing should be owned by one operation layer.
|
|
61
|
+
|
|
62
|
+
### 4. Preview capture and preview rendering
|
|
63
|
+
|
|
64
|
+
The codebase already has useful preview pieces, but they live in separate pockets:
|
|
65
|
+
|
|
66
|
+
- `WindowPreviewStore` in `HUDRightBar.swift`
|
|
67
|
+
- preview placeholder and preview card variants in HUD
|
|
68
|
+
- separate preview capture in `ScreenMapState.swift`
|
|
69
|
+
|
|
70
|
+
This is a strong signal that preview should become its own reusable subsystem.
|
|
71
|
+
|
|
72
|
+
### 5. Action definitions
|
|
73
|
+
|
|
74
|
+
Action and intent metadata currently live in several places:
|
|
75
|
+
|
|
76
|
+
- `HotkeyStore.swift`
|
|
77
|
+
- `PaletteCommand.swift`
|
|
78
|
+
- `IntentEngine.swift`
|
|
79
|
+
- `Intents/LatticeIntent.swift`
|
|
80
|
+
- `LatticesApi.swift`
|
|
81
|
+
|
|
82
|
+
The sharpest duplication is that `IntentEngine.swift` and `Intents/LatticeIntent.swift` each define their own intent schema.
|
|
83
|
+
|
|
84
|
+
### 6. Overlay and panel shells
|
|
85
|
+
|
|
86
|
+
There is already a useful shared primitive for normal app windows in `AppWindowShell.swift`, but overlay surfaces still rebuild similar shell code:
|
|
87
|
+
|
|
88
|
+
- `CommandPaletteWindow.swift`
|
|
89
|
+
- `OmniSearchWindow.swift`
|
|
90
|
+
- `VoiceCommandWindow.swift`
|
|
91
|
+
- `LauncherHUD.swift`
|
|
92
|
+
|
|
93
|
+
The repeated shell concerns are:
|
|
94
|
+
|
|
95
|
+
- `NSPanel` setup
|
|
96
|
+
- blur and rounded-mask container setup
|
|
97
|
+
- screen placement
|
|
98
|
+
- activation and dismissal behavior
|
|
99
|
+
- event monitor lifecycle
|
|
100
|
+
|
|
101
|
+
## Proposed reusable components
|
|
102
|
+
|
|
103
|
+
This is the target component map.
|
|
104
|
+
|
|
105
|
+
### Desktop substrate
|
|
106
|
+
|
|
107
|
+
#### `SessionWindowLocator`
|
|
108
|
+
|
|
109
|
+
Responsibility:
|
|
110
|
+
|
|
111
|
+
- resolve a lattices session, title tag, app target, or explicit window id into a canonical window target
|
|
112
|
+
- try fast cache lookup first
|
|
113
|
+
- fall back through CG and AX in one place
|
|
114
|
+
|
|
115
|
+
Why:
|
|
116
|
+
|
|
117
|
+
- removes repeated session-tag matching logic
|
|
118
|
+
- gives palette, daemon, voice, HUD, and future switchers the same targeting rules
|
|
119
|
+
|
|
120
|
+
#### `SpaceTopologySnapshot`
|
|
121
|
+
|
|
122
|
+
Responsibility:
|
|
123
|
+
|
|
124
|
+
- expose a single read model for displays, spaces, current space, and window-to-space membership
|
|
125
|
+
|
|
126
|
+
Why:
|
|
127
|
+
|
|
128
|
+
- prevents repeated recomputation of display-space facts
|
|
129
|
+
- makes space-aware UIs easier to build
|
|
130
|
+
|
|
131
|
+
#### `WindowPresenter`
|
|
132
|
+
|
|
133
|
+
Responsibility:
|
|
134
|
+
|
|
135
|
+
- own the canonical move, resize, raise, activate, and interaction-marking flow
|
|
136
|
+
- support both single-window and batched operations
|
|
137
|
+
|
|
138
|
+
Why:
|
|
139
|
+
|
|
140
|
+
- centralizes the side-effect sequence
|
|
141
|
+
- makes future planners and higher-level actions less fragile
|
|
142
|
+
|
|
143
|
+
#### `WindowPreviewProvider`
|
|
144
|
+
|
|
145
|
+
Responsibility:
|
|
146
|
+
|
|
147
|
+
- capture, cache, and serve still previews or live previews for windows
|
|
148
|
+
- separate capture policy from UI rendering
|
|
149
|
+
|
|
150
|
+
Why:
|
|
151
|
+
|
|
152
|
+
- avoids HUD and Screen Map each inventing preview behavior
|
|
153
|
+
- directly supports a visual selector or session fan-out
|
|
154
|
+
|
|
155
|
+
### Action substrate
|
|
156
|
+
|
|
157
|
+
#### `ActionRegistry`
|
|
158
|
+
|
|
159
|
+
Responsibility:
|
|
160
|
+
|
|
161
|
+
- define canonical verbs once
|
|
162
|
+
- own parameter metadata, user-facing labels, phrase templates, and execution hooks
|
|
163
|
+
|
|
164
|
+
Minimal shape:
|
|
165
|
+
|
|
166
|
+
```swift
|
|
167
|
+
enum ActionID: String {
|
|
168
|
+
case openPalette
|
|
169
|
+
case openSearch
|
|
170
|
+
case focusWindow
|
|
171
|
+
case placeWindow
|
|
172
|
+
case launchProject
|
|
173
|
+
case switchLayer
|
|
174
|
+
case killSession
|
|
175
|
+
case refreshProjects
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
struct ActionParam {
|
|
179
|
+
let name: String
|
|
180
|
+
let type: ActionParamType
|
|
181
|
+
let required: Bool
|
|
182
|
+
let values: [String]?
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
struct ActionDef {
|
|
186
|
+
let id: ActionID
|
|
187
|
+
let title: String
|
|
188
|
+
let params: [ActionParam]
|
|
189
|
+
let hotkey: HotkeyMeta?
|
|
190
|
+
let palette: PaletteMeta?
|
|
191
|
+
let phrases: [String]
|
|
192
|
+
let run: (ActionContext) throws -> JSON
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Why:
|
|
197
|
+
|
|
198
|
+
- one action identity across hotkeys, palette, voice, daemon, and companion
|
|
199
|
+
- palette rows become runtime bindings of a verb to a target, not bespoke actions
|
|
200
|
+
|
|
201
|
+
#### `ActionContext`
|
|
202
|
+
|
|
203
|
+
Responsibility:
|
|
204
|
+
|
|
205
|
+
- carry structured arguments plus source information like `hotkey`, `palette`, `voice-local`, `daemon`, or `companion`
|
|
206
|
+
|
|
207
|
+
Why:
|
|
208
|
+
|
|
209
|
+
- makes execution and logging more consistent
|
|
210
|
+
|
|
211
|
+
### Overlay substrate
|
|
212
|
+
|
|
213
|
+
#### `OverlayPanelShell`
|
|
214
|
+
|
|
215
|
+
Responsibility:
|
|
216
|
+
|
|
217
|
+
- build a reusable floating `NSPanel` shell from configuration
|
|
218
|
+
- own blur or plain background, corner radius, window level, collection behavior, and hosting setup
|
|
219
|
+
|
|
220
|
+
Why:
|
|
221
|
+
|
|
222
|
+
- extracts the shared Spotlight-style panel construction path
|
|
223
|
+
|
|
224
|
+
#### `OverlayPlacement`
|
|
225
|
+
|
|
226
|
+
Responsibility:
|
|
227
|
+
|
|
228
|
+
- centralize placement policies like centered, spotlight offset, top-center, or mouse-screen placement
|
|
229
|
+
|
|
230
|
+
Why:
|
|
231
|
+
|
|
232
|
+
- removes repeated `visibleFrame` math
|
|
233
|
+
|
|
234
|
+
#### `OverlayLifecycleController`
|
|
235
|
+
|
|
236
|
+
Responsibility:
|
|
237
|
+
|
|
238
|
+
- own local event monitors, Escape dismissal, deactivate behavior, and cleanup
|
|
239
|
+
|
|
240
|
+
Why:
|
|
241
|
+
|
|
242
|
+
- reduces panel-specific lifecycle glue
|
|
243
|
+
|
|
244
|
+
### UI primitives
|
|
245
|
+
|
|
246
|
+
#### `WindowPreviewCard`
|
|
247
|
+
|
|
248
|
+
Responsibility:
|
|
249
|
+
|
|
250
|
+
- render a window preview, loading state, and unavailable state consistently
|
|
251
|
+
|
|
252
|
+
Why:
|
|
253
|
+
|
|
254
|
+
- low-risk first UI extraction
|
|
255
|
+
- immediately reduces duplicated HUD preview rendering
|
|
256
|
+
|
|
257
|
+
## Recommended extraction order
|
|
258
|
+
|
|
259
|
+
The sequence below favors leverage without taking unnecessary risk.
|
|
260
|
+
|
|
261
|
+
### Slice 1: `WindowPreviewCard`
|
|
262
|
+
|
|
263
|
+
Extract the repeated preview body and placeholder logic from HUD into a shared SwiftUI component.
|
|
264
|
+
|
|
265
|
+
Why first:
|
|
266
|
+
|
|
267
|
+
- UI-only
|
|
268
|
+
- already duplicated
|
|
269
|
+
- does not disturb CGS, AX, or window mutation paths
|
|
270
|
+
|
|
271
|
+
### Slice 2: `OverlayPanelShell`
|
|
272
|
+
|
|
273
|
+
Extract the shared panel-construction path from `CommandPaletteWindow` and `OmniSearchWindow`.
|
|
274
|
+
|
|
275
|
+
Why second:
|
|
276
|
+
|
|
277
|
+
- those two surfaces are the cleanest near-duplicates
|
|
278
|
+
- builds a reusable shell for a future visual selector
|
|
279
|
+
|
|
280
|
+
### Slice 3: unify intent schema
|
|
281
|
+
|
|
282
|
+
Remove the parallel intent-definition structures by expanding or reusing the types in `Intents/LatticeIntent.swift` and pointing them at existing execution handlers.
|
|
283
|
+
|
|
284
|
+
Why third:
|
|
285
|
+
|
|
286
|
+
- high leverage
|
|
287
|
+
- removes one entire duplicate definition system
|
|
288
|
+
- proves the registry shape before migrating hotkeys or palette
|
|
289
|
+
|
|
290
|
+
### Slice 4: `SessionWindowLocator`
|
|
291
|
+
|
|
292
|
+
Centralize session-tagged lookup across DesktopModel and WindowTiler.
|
|
293
|
+
|
|
294
|
+
Why fourth:
|
|
295
|
+
|
|
296
|
+
- strongest desktop duplication seam
|
|
297
|
+
- unlocks cleaner action execution and better future switcher targeting
|
|
298
|
+
|
|
299
|
+
### Slice 5: `SpaceTopologySnapshot`
|
|
300
|
+
|
|
301
|
+
Create one query layer for display and space topology.
|
|
302
|
+
|
|
303
|
+
Why fifth:
|
|
304
|
+
|
|
305
|
+
- stabilizes space-aware features before touching more motion logic
|
|
306
|
+
|
|
307
|
+
### Slice 6: `WindowPresenter`
|
|
308
|
+
|
|
309
|
+
Unify move, resize, raise, activate, and interaction-marking flows.
|
|
310
|
+
|
|
311
|
+
Why sixth:
|
|
312
|
+
|
|
313
|
+
- this is higher risk because it sits directly on side effects
|
|
314
|
+
- it is safer after lookup and topology are centralized
|
|
315
|
+
|
|
316
|
+
### Slice 7: `WindowPreviewProvider`
|
|
317
|
+
|
|
318
|
+
Lift preview capture and caching out of HUD-specific code and reconcile it with Screen Map preview capture.
|
|
319
|
+
|
|
320
|
+
Why seventh:
|
|
321
|
+
|
|
322
|
+
- more useful after overlay shell and preview card exist
|
|
323
|
+
- becomes the substrate for a visual window or session chooser
|
|
324
|
+
|
|
325
|
+
## Features this should unlock
|
|
326
|
+
|
|
327
|
+
Once the components above exist, the app can add new surfaces with much less bespoke code.
|
|
328
|
+
|
|
329
|
+
### cmdcmd-style visual switcher
|
|
330
|
+
|
|
331
|
+
Use:
|
|
332
|
+
|
|
333
|
+
- `OverlayPanelShell`
|
|
334
|
+
- `OverlayPlacement`
|
|
335
|
+
- `SessionWindowLocator`
|
|
336
|
+
- `WindowPreviewProvider`
|
|
337
|
+
- `WindowPresenter`
|
|
338
|
+
|
|
339
|
+
Possible behavior:
|
|
340
|
+
|
|
341
|
+
- fan out lattices sessions or all windows
|
|
342
|
+
- show live or cached previews
|
|
343
|
+
- focus, tile, move to space, or close from one surface
|
|
344
|
+
|
|
345
|
+
### Shared action surfaces
|
|
346
|
+
|
|
347
|
+
Use:
|
|
348
|
+
|
|
349
|
+
- `ActionRegistry`
|
|
350
|
+
- `ActionContext`
|
|
351
|
+
|
|
352
|
+
Possible behavior:
|
|
353
|
+
|
|
354
|
+
- define `placeWindow` once
|
|
355
|
+
- trigger it from voice, hotkey, palette, daemon, or companion
|
|
356
|
+
- keep labels and phrases aligned across surfaces
|
|
357
|
+
|
|
358
|
+
### Stronger planning and preview
|
|
359
|
+
|
|
360
|
+
Use:
|
|
361
|
+
|
|
362
|
+
- `ActionRegistry`
|
|
363
|
+
- `WindowPresenter`
|
|
364
|
+
- `SpaceTopologySnapshot`
|
|
365
|
+
|
|
366
|
+
Possible behavior:
|
|
367
|
+
|
|
368
|
+
- preview a multi-window action before applying it
|
|
369
|
+
- build transactional-feeling UI around batched movement
|
|
370
|
+
|
|
371
|
+
## Things not to do yet
|
|
372
|
+
|
|
373
|
+
- do not rewrite `WindowTiler.swift` in one shot
|
|
374
|
+
- do not migrate every overlay surface onto one abstraction immediately
|
|
375
|
+
- do not force the palette to become purely registry-generated before the action model is proven
|
|
376
|
+
|
|
377
|
+
The safer path is:
|
|
378
|
+
|
|
379
|
+
1. extract small reusable pieces
|
|
380
|
+
2. move one production surface onto them
|
|
381
|
+
3. verify behavior
|
|
382
|
+
4. repeat
|
|
383
|
+
|
|
384
|
+
## Summary
|
|
385
|
+
|
|
386
|
+
The strongest architectural opportunity here is not one big framework. It is three small substrates:
|
|
387
|
+
|
|
388
|
+
- desktop targeting and motion
|
|
389
|
+
- action definition and routing
|
|
390
|
+
- overlay panel construction
|
|
391
|
+
|
|
392
|
+
If those become reusable, `lattices` gets a much cleaner path to new features without making every new surface solve the same desktop and execution problems again.
|
package/docs/concepts.md
CHANGED
|
@@ -10,11 +10,11 @@ order: 6
|
|
|
10
10
|
|------|------------|
|
|
11
11
|
| **Command Palette** | The menu bar app's primary interface (**Cmd+Shift+M**). Searchable list of actions: launch, tile, sync, restart, settings. |
|
|
12
12
|
| **Window Tiling** | Snap terminal windows to preset screen positions (halves, quarters, thirds, maximize, center). Works from the CLI (`lattices tile`) or the command palette. |
|
|
13
|
-
| **
|
|
14
|
-
| **Agent** | Any program that calls the
|
|
13
|
+
| **Agent API** | WebSocket server (`ws://127.0.0.1:9399`) inside the menu bar app. Exposes 35+ RPC methods and 5 real-time events for programmatic control. See the [API reference](/docs/api). |
|
|
14
|
+
| **Agent** | Any program that calls the agent API autonomously — an AI coding agent, a shell script, a CI pipeline, or a custom tool. |
|
|
15
15
|
| **Session** | A persistent tmux workspace that lives in the background. Survives terminal crashes, disconnects, and closing your laptop. One session per project. Requires tmux. |
|
|
16
|
-
| **Pane** | A single terminal view inside a session. A typical setup has two panes side by side —
|
|
17
|
-
| **Attach / Detach** | Attaching connects your terminal to an existing session. Detaching disconnects but keeps the session alive — your dev server
|
|
16
|
+
| **Pane** | A single terminal view inside a session. A typical setup has two panes side by side — shell on the left, dev server on the right. Requires tmux. |
|
|
17
|
+
| **Attach / Detach** | Attaching connects your terminal to an existing session. Detaching disconnects but keeps the session alive — your shell and dev server keep running. Requires tmux. |
|
|
18
18
|
| **Sync / Reconcile** | `lattices sync` brings a running session back in line with its declared config — recreates missing panes, re-applies layout, restores labels, re-runs commands in idle panes. Requires tmux. |
|
|
19
19
|
| **Ensure / Prefill** | Two modes for restoring exited commands on reattach. **Ensure** auto-reruns the command. **Prefill** types it but waits for you to press Enter. Set via `.lattices.json`. Requires tmux. |
|
|
20
20
|
| **tmux** | Terminal multiplexer (optional). Provides persistent sessions, pane layouts, and command restoration. Install with `brew install tmux` if you want session management. |
|
|
@@ -23,9 +23,9 @@ order: 6
|
|
|
23
23
|
|
|
24
24
|
1. You create a `.lattices.json` file in your project root (or run `lattices init`)
|
|
25
25
|
2. The menu bar app discovers the project and adds it to the command palette
|
|
26
|
-
3. You can tile windows, switch layers, search via OCR, and use the
|
|
27
|
-
4. With tmux installed, `lattices` also creates persistent terminal sessions:
|
|
28
|
-
- Each pane gets its command (
|
|
26
|
+
3. You can tile windows, switch layers, search via OCR, and use the agent API
|
|
27
|
+
4. With tmux installed, `lattices start` also creates persistent terminal sessions:
|
|
28
|
+
- Each pane gets its command (shell, dev server, tests, etc.)
|
|
29
29
|
- The session persists in the background until you kill it
|
|
30
30
|
- You can attach/detach from any terminal at any time
|
|
31
31
|
- If `ensure` is enabled, exited commands auto-restart on reattach
|
|
@@ -35,13 +35,14 @@ order: 6
|
|
|
35
35
|
<img src="/architecture.svg" alt="lattices architecture diagram" style="margin: 2rem 0; max-width: 100%;" />
|
|
36
36
|
|
|
37
37
|
- The menu bar app is the core. It provides the command palette,
|
|
38
|
-
window tiling, OCR, project discovery, and the
|
|
38
|
+
window tiling, OCR, project discovery, and the agent API (a WebSocket
|
|
39
39
|
server on `ws://127.0.0.1:9399`). It works with or without tmux.
|
|
40
40
|
- The CLI handles tiling, OCR queries, and (when tmux is installed)
|
|
41
41
|
session management via `tmux` shell commands.
|
|
42
|
-
- Agents and scripts connect to the
|
|
42
|
+
- Agents and scripts connect to the agent API over WebSocket. They can
|
|
43
43
|
do everything the app and CLI can do: discover projects, tile windows,
|
|
44
44
|
switch layers, read on-screen text, and subscribe to real-time events.
|
|
45
|
+
See the [Agent API reference](/docs/api).
|
|
45
46
|
- When tmux is installed, the app and CLI can also launch, sync, and
|
|
46
47
|
manage persistent terminal sessions. All layers share the same session
|
|
47
48
|
naming convention so they always agree on which session belongs to
|
|
@@ -93,7 +94,7 @@ and other macOS window managers.
|
|
|
93
94
|
|
|
94
95
|
### Ensure/prefill restoration (requires tmux)
|
|
95
96
|
|
|
96
|
-
When you run `lattices`
|
|
97
|
+
When you run `lattices start` and a session already exists:
|
|
97
98
|
|
|
98
99
|
1. lattices checks the `ensure` / `prefill` flag in `.lattices.json`
|
|
99
100
|
2. For each pane, it queries `#{pane_current_command}` via tmux
|
|
@@ -105,14 +106,14 @@ When you run `lattices` (no arguments) and a session already exists:
|
|
|
105
106
|
|
|
106
107
|
## Agent control
|
|
107
108
|
|
|
108
|
-
The
|
|
109
|
+
The agent API gives agents the same control as a human using the
|
|
109
110
|
menu bar app. An agent can list projects and windows, launch sessions,
|
|
110
111
|
tile windows to screen positions, subscribe to real-time events
|
|
111
112
|
(`windows.changed`, `tmux.changed`, `layer.switched`), and sync
|
|
112
113
|
sessions back to their declared config.
|
|
113
114
|
|
|
114
115
|
A typical orchestrator sets up a multi-project workspace in a few
|
|
115
|
-
`daemonCall()` invocations. See the [
|
|
116
|
+
`daemonCall()` invocations. See the [Agent API reference](/docs/api)
|
|
116
117
|
for the full method list and code examples.
|
|
117
118
|
|
|
118
119
|
## Key shortcuts (inside tmux)
|
package/docs/config.md
CHANGED
|
@@ -14,7 +14,7 @@ workspace layout. lattices reads this file when creating a session.
|
|
|
14
14
|
```json
|
|
15
15
|
{
|
|
16
16
|
"panes": [
|
|
17
|
-
{ "name": "
|
|
17
|
+
{ "name": "shell" },
|
|
18
18
|
{ "name": "server", "cmd": "pnpm dev" }
|
|
19
19
|
]
|
|
20
20
|
}
|
|
@@ -26,7 +26,7 @@ workspace layout. lattices reads this file when creating a session.
|
|
|
26
26
|
{
|
|
27
27
|
"ensure": true,
|
|
28
28
|
"panes": [
|
|
29
|
-
{ "name": "
|
|
29
|
+
{ "name": "shell", "size": 60 },
|
|
30
30
|
{ "name": "server", "cmd": "pnpm dev" },
|
|
31
31
|
{ "name": "tests", "cmd": "pnpm test --watch" }
|
|
32
32
|
]
|
|
@@ -72,7 +72,7 @@ lattices picks a layout based on how many panes you define:
|
|
|
72
72
|
|
|
73
73
|
```
|
|
74
74
|
┌──────────┬─────────┐
|
|
75
|
-
│
|
|
75
|
+
│ shell │ server │
|
|
76
76
|
│ (60%) │ (40%) │
|
|
77
77
|
└──────────┴─────────┘
|
|
78
78
|
```
|
|
@@ -83,7 +83,7 @@ Horizontal split. First pane on the left, second on the right.
|
|
|
83
83
|
|
|
84
84
|
```
|
|
85
85
|
┌──────────┬─────────┐
|
|
86
|
-
│
|
|
86
|
+
│ shell │ server │
|
|
87
87
|
│ (60%) ├─────────┤
|
|
88
88
|
│ │ tests │
|
|
89
89
|
└──────────┴─────────┘
|
|
@@ -96,7 +96,7 @@ on the right.
|
|
|
96
96
|
|
|
97
97
|
```
|
|
98
98
|
┌──────────┬─────────┐
|
|
99
|
-
│
|
|
99
|
+
│ shell │ server │
|
|
100
100
|
│ (60%) ├─────────┤
|
|
101
101
|
│ │ tests │
|
|
102
102
|
│ ├─────────┤
|
|
@@ -109,10 +109,10 @@ on the right.
|
|
|
109
109
|
If there's no `.lattices.json`, lattices still works. It will:
|
|
110
110
|
|
|
111
111
|
1. Create a 2-pane layout (60/40 split)
|
|
112
|
-
2.
|
|
113
|
-
3. Auto-detect your dev command from package.json scripts:
|
|
112
|
+
2. Open a shell in the left pane
|
|
113
|
+
3. Auto-detect your dev command from package.json scripts and run it on the right:
|
|
114
114
|
- Looks for: `dev`, `start`, `serve`, `watch` (in that order)
|
|
115
|
-
- Detects package manager:
|
|
115
|
+
- Detects package manager: bun > pnpm > yarn > npm
|
|
116
116
|
|
|
117
117
|
## Creating a config
|
|
118
118
|
|
|
@@ -124,17 +124,42 @@ Run `lattices init` in your project directory to generate a starter
|
|
|
124
124
|
|
|
125
125
|
| Command | Description |
|
|
126
126
|
|----------------------------|--------------------------------------------------|
|
|
127
|
-
| `lattices` |
|
|
127
|
+
| `lattices` | Show workspace status and common commands |
|
|
128
|
+
| `lattices start` | Create or attach to session for current project |
|
|
129
|
+
| `lattices tmux` | Alias for `lattices start` |
|
|
128
130
|
| `lattices init` | Generate .lattices.json config for this project |
|
|
129
131
|
| `lattices ls` | List active sessions (requires tmux) |
|
|
130
132
|
| `lattices kill [name]` | Kill a session (defaults to current project) |
|
|
131
133
|
| `lattices sync` | Reconcile session to match declared config |
|
|
132
134
|
| `lattices restart [pane]` | Restart a pane's process (by name or index) |
|
|
133
135
|
| `lattices tile <position>` | Tile the frontmost window to a screen position |
|
|
136
|
+
| `lattices tile family [app] [region]` | Smart-grid the frontmost app family, or a named app |
|
|
137
|
+
| `lattices distribute [app] [region]` | Smart-grid visible windows or just one app |
|
|
134
138
|
| `lattices group [id]` | List tab groups or launch/attach a group |
|
|
135
139
|
| `lattices groups` | List all tab groups with status |
|
|
136
140
|
| `lattices tab <group> [tab]` | Switch tab within a group (by label or index) |
|
|
137
141
|
| `lattices app` | Launch the menu bar companion app |
|
|
142
|
+
| `lattices app update` | Download the latest menu bar app and relaunch |
|
|
143
|
+
| `lattices app build` | Rebuild the menu bar app from source |
|
|
144
|
+
| `lattices app restart` | Rebuild and relaunch the menu bar app |
|
|
145
|
+
| `lattices layer [name\|index]` | Switch to a workspace layer by name or index |
|
|
146
|
+
| `lattices windows [--json]` | List all visible windows |
|
|
147
|
+
| `lattices window assign <wid> <layer>` | Tag a window to a layer |
|
|
148
|
+
| `lattices window map [--json]` | Show all window→layer assignments |
|
|
149
|
+
| `lattices actor toggle` | Hide/show persistent overlay actors |
|
|
150
|
+
| `lattices hud register [manifest]` | Register a `.lattices/hud/manifest.json` |
|
|
151
|
+
| `lattices hud publish [id\|manifest]` | Publish a static HUD actor to the desktop |
|
|
152
|
+
| `lattices hud sync` | Publish all registered HUD actors |
|
|
153
|
+
| `lattices search <query>` | Search windows by title, app, session, OCR |
|
|
154
|
+
| `lattices search <q> --deep` | Deep search: index + live terminal inspection |
|
|
155
|
+
| `lattices search <q> --all` | Same as `--deep` (all search sources) |
|
|
156
|
+
| `lattices search <q> --wid` | Print matching window IDs only (pipeable) |
|
|
157
|
+
| `lattices place <query> [pos]` | Deep search + focus + tile (default: bottom-right)|
|
|
158
|
+
| `lattices focus <session>` | Focus a session's window and switch Spaces |
|
|
159
|
+
| `lattices scan search <query>` | Search indexed screen text |
|
|
160
|
+
| `lattices diag [limit]` | Show recent diagnostic entries |
|
|
161
|
+
| `lattices app` | Launch the menu bar companion app |
|
|
162
|
+
| `lattices app update` | Download the latest menu bar app and relaunch |
|
|
138
163
|
| `lattices app build` | Rebuild the menu bar app from source |
|
|
139
164
|
| `lattices app restart` | Rebuild and relaunch the menu bar app |
|
|
140
165
|
| `lattices app quit` | Stop the menu bar app |
|
|
@@ -143,6 +168,29 @@ Run `lattices init` in your project directory to generate a starter
|
|
|
143
168
|
Aliases: `ls`/`list`, `kill`/`rm`, `sync`/`reconcile`,
|
|
144
169
|
`restart`/`respawn`, `tile`/`t`.
|
|
145
170
|
|
|
171
|
+
## Keyboard remaps
|
|
172
|
+
|
|
173
|
+
The menu bar app can create a lightweight keyboard layer from
|
|
174
|
+
`~/.lattices/keyboard-remaps.json`. The default config is:
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"rules": [
|
|
179
|
+
{
|
|
180
|
+
"enabled": true,
|
|
181
|
+
"from": "caps_lock",
|
|
182
|
+
"id": "caps_lock_hyper_escape",
|
|
183
|
+
"toIfAlone": "escape",
|
|
184
|
+
"toIfHeld": "hyper"
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
It is enabled by default and can be turned off from Settings -> General ->
|
|
191
|
+
Keyboard remaps. Hold Caps Lock to send Hyper (`Control` + `Option` +
|
|
192
|
+
`Shift` + `Command`), or tap Caps Lock alone to send Escape.
|
|
193
|
+
|
|
146
194
|
## Machine-readable output
|
|
147
195
|
|
|
148
196
|
### `--json` flag
|
|
@@ -159,7 +207,7 @@ into `jq` or consuming from scripts.
|
|
|
159
207
|
|
|
160
208
|
### Daemon responses
|
|
161
209
|
|
|
162
|
-
All
|
|
210
|
+
All agent API calls return JSON natively. If you need structured data
|
|
163
211
|
from lattices, the daemon is easier than parsing stdout. See the
|
|
164
212
|
[API reference](/docs/api).
|
|
165
213
|
|
|
@@ -233,3 +281,28 @@ Aliases: `left-half`/`left`, `right-half`/`right`, `top-half`/`top`,
|
|
|
233
281
|
|
|
234
282
|
Tiling respects the menu bar and dock. It uses the visible desktop
|
|
235
283
|
area, not the full screen.
|
|
284
|
+
|
|
285
|
+
For arbitrary cells, use compact `CxR:c,r` with 1-indexed coordinates
|
|
286
|
+
from the top-left, or canonical `grid:CxR:c,r` with 0-indexed coordinates.
|
|
287
|
+
Example: `lattices tile 4x4:1,2`.
|
|
288
|
+
|
|
289
|
+
### Smart app tiling
|
|
290
|
+
|
|
291
|
+
Use `lattices tile family` when you want lattices to arrange a whole
|
|
292
|
+
window family instead of just moving the frontmost window.
|
|
293
|
+
|
|
294
|
+
Examples:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
lattices tile family
|
|
298
|
+
lattices tile family right
|
|
299
|
+
lattices tile family iTerm2
|
|
300
|
+
lattices tile family "Google Chrome" left
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- With no app name, `family` means the **frontmost app**. If iTerm is
|
|
304
|
+
frontmost, lattices grids your visible iTerm windows.
|
|
305
|
+
- If you pass a region (`left`, `right`, `top`, `bottom`, etc.), the
|
|
306
|
+
smart grid is constrained to that part of the screen.
|
|
307
|
+
- `lattices distribute` uses the same smart grid engine, but defaults to
|
|
308
|
+
**all visible windows** instead of the current app family.
|