@lattices/cli 0.3.0 → 0.4.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/README.md +85 -9
- package/app/Info.plist +30 -0
- package/app/Lattices.app/Contents/Info.plist +8 -2
- package/app/Lattices.app/Contents/MacOS/Lattices +0 -0
- package/app/Lattices.app/Contents/Resources/AppIcon.icns +0 -0
- package/app/Lattices.app/Contents/Resources/tap.wav +0 -0
- package/app/Lattices.app/Contents/_CodeSignature/CodeResources +139 -0
- package/app/Lattices.entitlements +15 -0
- package/app/Package.swift +8 -1
- package/app/Resources/tap.wav +0 -0
- package/app/Sources/AdvisorLearningStore.swift +90 -0
- package/app/Sources/AgentSession.swift +377 -0
- package/app/Sources/AppDelegate.swift +45 -12
- package/app/Sources/AppShellView.swift +81 -8
- package/app/Sources/AudioProvider.swift +386 -0
- package/app/Sources/CheatSheetHUD.swift +261 -19
- package/app/Sources/DaemonProtocol.swift +13 -0
- package/app/Sources/DaemonServer.swift +8 -0
- package/app/Sources/DesktopModel.swift +189 -6
- package/app/Sources/DesktopModelTypes.swift +2 -0
- package/app/Sources/DiagnosticLog.swift +104 -2
- package/app/Sources/EventBus.swift +1 -0
- package/app/Sources/HUDBottomBar.swift +279 -0
- package/app/Sources/HUDController.swift +1158 -0
- package/app/Sources/HUDLeftBar.swift +849 -0
- package/app/Sources/HUDMinimap.swift +179 -0
- package/app/Sources/HUDRightBar.swift +774 -0
- package/app/Sources/HUDState.swift +367 -0
- package/app/Sources/HUDTopBar.swift +243 -0
- package/app/Sources/HandsOffSession.swift +802 -0
- package/app/Sources/HomeDashboardView.swift +125 -0
- package/app/Sources/HotkeyManager.swift +2 -0
- package/app/Sources/HotkeyStore.swift +49 -9
- package/app/Sources/IntentEngine.swift +962 -0
- package/app/Sources/Intents/CreateLayerIntent.swift +54 -0
- package/app/Sources/Intents/DistributeIntent.swift +56 -0
- package/app/Sources/Intents/FocusIntent.swift +69 -0
- package/app/Sources/Intents/HelpIntent.swift +41 -0
- package/app/Sources/Intents/KillIntent.swift +47 -0
- package/app/Sources/Intents/LatticeIntent.swift +78 -0
- package/app/Sources/Intents/LaunchIntent.swift +67 -0
- package/app/Sources/Intents/ListSessionsIntent.swift +32 -0
- package/app/Sources/Intents/ListWindowsIntent.swift +30 -0
- package/app/Sources/Intents/ScanIntent.swift +52 -0
- package/app/Sources/Intents/SearchIntent.swift +190 -0
- package/app/Sources/Intents/SwitchLayerIntent.swift +50 -0
- package/app/Sources/Intents/TileIntent.swift +61 -0
- package/app/Sources/LatticesApi.swift +1275 -30
- package/app/Sources/LauncherHUD.swift +348 -0
- package/app/Sources/MainView.swift +147 -44
- package/app/Sources/MouseFinder.swift +222 -0
- package/app/Sources/OcrModel.swift +34 -1
- package/app/Sources/OmniSearchState.swift +99 -102
- package/app/Sources/OnboardingView.swift +457 -0
- package/app/Sources/PermissionChecker.swift +2 -12
- package/app/Sources/PiChatDock.swift +454 -0
- package/app/Sources/PiChatSession.swift +815 -0
- package/app/Sources/PiWorkspaceView.swift +364 -0
- package/app/Sources/PlacementSpec.swift +195 -0
- package/app/Sources/Preferences.swift +59 -0
- package/app/Sources/ProjectScanner.swift +58 -45
- package/app/Sources/ScreenMapState.swift +701 -55
- package/app/Sources/ScreenMapView.swift +843 -103
- package/app/Sources/ScreenMapWindowController.swift +22 -0
- package/app/Sources/SessionLayerStore.swift +285 -0
- package/app/Sources/SessionManager.swift +4 -1
- package/app/Sources/SettingsView.swift +186 -3
- package/app/Sources/Theme.swift +9 -8
- package/app/Sources/TmuxModel.swift +7 -0
- package/app/Sources/TmuxQuery.swift +27 -3
- package/app/Sources/VoiceChatView.swift +192 -0
- package/app/Sources/VoiceCommandWindow.swift +1594 -0
- package/app/Sources/VoiceIntentResolver.swift +671 -0
- package/app/Sources/VoxClient.swift +454 -0
- package/app/Sources/WindowTiler.swift +348 -87
- package/app/Sources/WorkspaceManager.swift +127 -18
- package/app/Tests/StageDragTests.swift +333 -0
- package/app/Tests/StageJoinTests.swift +313 -0
- package/app/Tests/StageManagerTests.swift +280 -0
- package/app/Tests/StageTileTests.swift +353 -0
- package/assets/AppIcon.icns +0 -0
- package/bin/client.ts +16 -0
- package/bin/{daemon-client.js → daemon-client.ts} +49 -30
- package/bin/handsoff-infer.ts +280 -0
- package/bin/handsoff-worker.ts +740 -0
- package/bin/lattices-app.ts +338 -0
- package/bin/lattices-dev +208 -0
- package/bin/{lattices.js → lattices.ts} +777 -140
- 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 +142 -0
- package/docs/api.md +153 -34
- package/docs/app.md +29 -1
- package/docs/config.md +5 -1
- package/docs/handsoff-test-scenarios.md +84 -0
- package/docs/layers.md +20 -20
- package/docs/ocr.md +14 -5
- package/docs/overview.md +5 -1
- package/docs/presentation-execution-review.md +491 -0
- package/docs/prompts/hands-off-system.md +374 -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/tiling-reference.md +167 -0
- package/docs/twins.md +138 -0
- package/docs/voice-command-protocol.md +278 -0
- package/docs/voice.md +219 -0
- package/package.json +29 -11
- package/bin/client.js +0 -4
- package/bin/lattices-app.js +0 -221
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
# Agent Execution Plan
|
|
2
|
+
|
|
3
|
+
This document turns the architectural review into an implementation plan based on the current product priorities:
|
|
4
|
+
|
|
5
|
+
1. Predictability
|
|
6
|
+
2. Traceability
|
|
7
|
+
3. Reversibility later, but not as the first constraint
|
|
8
|
+
|
|
9
|
+
It also fixes the initial migration target:
|
|
10
|
+
|
|
11
|
+
- first-class execution path = daemon API
|
|
12
|
+
- preferred operator surface = agentic voice
|
|
13
|
+
- first use case = dictation or agent command -> daemon action -> reliable window/layer/layout outcome
|
|
14
|
+
|
|
15
|
+
This is intentionally daemon-first. If the daemon becomes the canonical execution boundary, voice, HUD, command palette, and workers can all become thinner clients.
|
|
16
|
+
|
|
17
|
+
## Product framing
|
|
18
|
+
|
|
19
|
+
There are three action families we need to support first.
|
|
20
|
+
|
|
21
|
+
### 1. Window-specific actions
|
|
22
|
+
|
|
23
|
+
These target a specific window and a destination.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
|
|
27
|
+
- "Chrome to the top right corner"
|
|
28
|
+
- "Terminal to the right third"
|
|
29
|
+
- "Move Slack to the bottom quarter"
|
|
30
|
+
- "Put Xcode in the upper third"
|
|
31
|
+
|
|
32
|
+
Core shape:
|
|
33
|
+
|
|
34
|
+
- target window
|
|
35
|
+
- destination
|
|
36
|
+
|
|
37
|
+
### 2. Layer-specific actions
|
|
38
|
+
|
|
39
|
+
These bring up an existing layer and arrange it coherently according to stored preferences.
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
|
|
43
|
+
- "Bring up review"
|
|
44
|
+
- "Switch to mobile"
|
|
45
|
+
- "Open the web layer"
|
|
46
|
+
|
|
47
|
+
Expectation:
|
|
48
|
+
|
|
49
|
+
- honor existing layer and project preferences
|
|
50
|
+
- launch or focus what is needed
|
|
51
|
+
- tile the result coherently
|
|
52
|
+
- do not invent too much intelligence beyond declared preferences
|
|
53
|
+
|
|
54
|
+
### 3. Space-optimization actions
|
|
55
|
+
|
|
56
|
+
These take the current set of visible or selected windows and make the desktop "nice."
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
|
|
60
|
+
- "Make this nice"
|
|
61
|
+
- "Organize these windows"
|
|
62
|
+
- "Clean up the layout"
|
|
63
|
+
- "Arrange this space"
|
|
64
|
+
|
|
65
|
+
Expectation:
|
|
66
|
+
|
|
67
|
+
- produce a good mosaic or grid
|
|
68
|
+
- be deterministic
|
|
69
|
+
- explain why the chosen arrangement happened
|
|
70
|
+
|
|
71
|
+
## Goals
|
|
72
|
+
|
|
73
|
+
### Must-have
|
|
74
|
+
|
|
75
|
+
- Every execution path is predictable.
|
|
76
|
+
- Every execution returns a trace explaining what happened.
|
|
77
|
+
- Every action is represented in one canonical schema.
|
|
78
|
+
- Voice and agents submit structured actions to the daemon.
|
|
79
|
+
|
|
80
|
+
### Nice-to-have later
|
|
81
|
+
|
|
82
|
+
- Undo
|
|
83
|
+
- Full transaction replay
|
|
84
|
+
- Layout previews before commit
|
|
85
|
+
- Smarter semantic layouts such as `review` or `focus`
|
|
86
|
+
|
|
87
|
+
### Non-goal for v1
|
|
88
|
+
|
|
89
|
+
- Building a fully autonomous planner that improvises layouts beyond declared rules
|
|
90
|
+
|
|
91
|
+
## Architecture decision
|
|
92
|
+
|
|
93
|
+
The daemon becomes the canonical mutation boundary.
|
|
94
|
+
|
|
95
|
+
That means:
|
|
96
|
+
|
|
97
|
+
- interpretation can happen anywhere
|
|
98
|
+
- planning and execution live behind the daemon
|
|
99
|
+
- all clients get the same semantics
|
|
100
|
+
|
|
101
|
+
In practice:
|
|
102
|
+
|
|
103
|
+
- local voice extracts actions, then calls daemon
|
|
104
|
+
- hands-off worker emits actions, then calls daemon
|
|
105
|
+
- HUD keys emit actions, then call daemon
|
|
106
|
+
- command palette emits actions, then calls daemon
|
|
107
|
+
|
|
108
|
+
This avoids multiple execution semantics in app code.
|
|
109
|
+
|
|
110
|
+
## Canonical execution model
|
|
111
|
+
|
|
112
|
+
We should introduce four core types.
|
|
113
|
+
|
|
114
|
+
### 1. `ActionRequest`
|
|
115
|
+
|
|
116
|
+
Represents what the operator asked for.
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"id": "req_123",
|
|
121
|
+
"source": "voice",
|
|
122
|
+
"intent": "window.place",
|
|
123
|
+
"targets": [{ "kind": "window_ref", "value": "frontmost" }],
|
|
124
|
+
"args": {
|
|
125
|
+
"placement": "top-right"
|
|
126
|
+
},
|
|
127
|
+
"rawUtterance": "put this in the top right corner"
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 2. `ExecutionPlan`
|
|
132
|
+
|
|
133
|
+
Represents the resolved plan before mutation.
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"id": "plan_123",
|
|
138
|
+
"requestId": "req_123",
|
|
139
|
+
"steps": [
|
|
140
|
+
{
|
|
141
|
+
"kind": "resolveWindow",
|
|
142
|
+
"result": { "wid": 38192, "app": "Google Chrome", "title": "Docs" }
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"kind": "placeWindow",
|
|
146
|
+
"result": { "display": 0, "frame": { "x": 960, "y": 0, "w": 960, "h": 540 } }
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"explanation": [
|
|
150
|
+
"Resolved 'this' to the frontmost window",
|
|
151
|
+
"Mapped 'top-right' to the top-right quarter of display 1"
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 3. `ExecutionReceipt`
|
|
157
|
+
|
|
158
|
+
Represents what actually happened.
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"id": "exec_123",
|
|
163
|
+
"requestId": "req_123",
|
|
164
|
+
"status": "ok",
|
|
165
|
+
"applied": [
|
|
166
|
+
{
|
|
167
|
+
"kind": "window.place",
|
|
168
|
+
"wid": 38192,
|
|
169
|
+
"before": { "x": 120, "y": 80, "w": 1280, "h": 900 },
|
|
170
|
+
"after": { "x": 960, "y": 0, "w": 960, "h": 540 }
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"trace": [
|
|
174
|
+
"DesktopModel matched frontmost window",
|
|
175
|
+
"Window moved by AX batch path"
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 4. `ExecutionTrace`
|
|
181
|
+
|
|
182
|
+
Represents the scrutable explanation layer.
|
|
183
|
+
|
|
184
|
+
This is the object the user should be able to inspect when they ask:
|
|
185
|
+
|
|
186
|
+
- why did you move that?
|
|
187
|
+
- why did you choose that layout?
|
|
188
|
+
- which rule applied?
|
|
189
|
+
|
|
190
|
+
This is separate from logging. It is product data.
|
|
191
|
+
|
|
192
|
+
## Initial action vocabulary
|
|
193
|
+
|
|
194
|
+
The first version should stay intentionally small.
|
|
195
|
+
|
|
196
|
+
### Window actions
|
|
197
|
+
|
|
198
|
+
- `window.place`
|
|
199
|
+
- `window.focus`
|
|
200
|
+
- `window.present`
|
|
201
|
+
|
|
202
|
+
`window.place` is the core mutation.
|
|
203
|
+
|
|
204
|
+
Arguments:
|
|
205
|
+
|
|
206
|
+
- `placement`
|
|
207
|
+
- optional `display`
|
|
208
|
+
- optional `strategy`
|
|
209
|
+
|
|
210
|
+
Targets:
|
|
211
|
+
|
|
212
|
+
- `wid`
|
|
213
|
+
- `session`
|
|
214
|
+
- `app_title`
|
|
215
|
+
- `frontmost`
|
|
216
|
+
- `selection`
|
|
217
|
+
|
|
218
|
+
### Layer actions
|
|
219
|
+
|
|
220
|
+
- `layer.activate`
|
|
221
|
+
|
|
222
|
+
Arguments:
|
|
223
|
+
|
|
224
|
+
- `mode`: `focus` or `launch`
|
|
225
|
+
- optional `force`
|
|
226
|
+
|
|
227
|
+
This should wrap current `layer.switch` / `tileLayer(...)` semantics, but return an execution receipt instead of silently doing best-effort work.
|
|
228
|
+
|
|
229
|
+
### Space actions
|
|
230
|
+
|
|
231
|
+
- `space.optimize`
|
|
232
|
+
|
|
233
|
+
Arguments:
|
|
234
|
+
|
|
235
|
+
- `scope`: `visible`, `selection`, `current_display`, `current_space`
|
|
236
|
+
- `strategy`: `mosaic`, `grid`, `balanced`
|
|
237
|
+
|
|
238
|
+
This wraps current `layout.distribute`, but with an explicit strategy and trace.
|
|
239
|
+
|
|
240
|
+
## Placement grammar
|
|
241
|
+
|
|
242
|
+
We need one shared placement grammar for all clients.
|
|
243
|
+
|
|
244
|
+
### v1 named placements
|
|
245
|
+
|
|
246
|
+
- `maximize`
|
|
247
|
+
- `center`
|
|
248
|
+
- `left`
|
|
249
|
+
- `right`
|
|
250
|
+
- `top`
|
|
251
|
+
- `bottom`
|
|
252
|
+
- `top-left`
|
|
253
|
+
- `top-right`
|
|
254
|
+
- `bottom-left`
|
|
255
|
+
- `bottom-right`
|
|
256
|
+
- `left-third`
|
|
257
|
+
- `center-third`
|
|
258
|
+
- `right-third`
|
|
259
|
+
- `top-third`
|
|
260
|
+
- `middle-third`
|
|
261
|
+
- `bottom-third`
|
|
262
|
+
- `left-quarter`
|
|
263
|
+
- `right-quarter`
|
|
264
|
+
- `top-quarter`
|
|
265
|
+
- `bottom-quarter`
|
|
266
|
+
|
|
267
|
+
Important note:
|
|
268
|
+
|
|
269
|
+
`top-third`, `middle-third`, and `bottom-third` should become real first-class placements, not inferred hacks. Right now the codebase has better support for vertical thirds than horizontal thirds. The grammar should fix that.
|
|
270
|
+
|
|
271
|
+
### v1 generic placement form
|
|
272
|
+
|
|
273
|
+
- `grid:CxR:C,R`
|
|
274
|
+
|
|
275
|
+
Examples:
|
|
276
|
+
|
|
277
|
+
- `grid:3x1:2,0`
|
|
278
|
+
- `grid:1x3:0,0`
|
|
279
|
+
- `grid:4x2:3,1`
|
|
280
|
+
|
|
281
|
+
### v1 display selector
|
|
282
|
+
|
|
283
|
+
Optional wrapper:
|
|
284
|
+
|
|
285
|
+
- `display:current:left`
|
|
286
|
+
- `display:2:grid:1x3:0,0`
|
|
287
|
+
|
|
288
|
+
If that wrapper feels too awkward for public API, keep it structured:
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
{
|
|
292
|
+
"placement": "grid:1x3:0,0",
|
|
293
|
+
"display": "current"
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Planning rules
|
|
298
|
+
|
|
299
|
+
Planning must be deterministic.
|
|
300
|
+
|
|
301
|
+
### Rule 1. Resolve target before applying placement
|
|
302
|
+
|
|
303
|
+
No side effects should start until target resolution succeeds or a launch/fallback policy is chosen.
|
|
304
|
+
|
|
305
|
+
### Rule 2. Return the matching reason
|
|
306
|
+
|
|
307
|
+
Every resolved target should include why it matched:
|
|
308
|
+
|
|
309
|
+
- frontmost
|
|
310
|
+
- exact session tag
|
|
311
|
+
- exact `wid`
|
|
312
|
+
- app + title match
|
|
313
|
+
- rule-based layer member
|
|
314
|
+
|
|
315
|
+
### Rule 3. If ambiguous, fail clearly unless policy says otherwise
|
|
316
|
+
|
|
317
|
+
For example:
|
|
318
|
+
|
|
319
|
+
- "Chrome to the right" with 4 Chrome windows should fail or request disambiguation in agent mode unless a deterministic policy exists
|
|
320
|
+
|
|
321
|
+
Possible policy order:
|
|
322
|
+
|
|
323
|
+
1. exact title match
|
|
324
|
+
2. exact session match
|
|
325
|
+
3. frontmost matching app
|
|
326
|
+
4. z-order first visible matching app
|
|
327
|
+
|
|
328
|
+
But whichever order we pick must be explicit and returned in the trace.
|
|
329
|
+
|
|
330
|
+
### Rule 4. Layer activation plans should be compositional
|
|
331
|
+
|
|
332
|
+
`layer.activate` should produce a plan containing:
|
|
333
|
+
|
|
334
|
+
- windows already running
|
|
335
|
+
- sessions to launch
|
|
336
|
+
- companion apps to launch
|
|
337
|
+
- placements to apply
|
|
338
|
+
- fallbacks for untracked windows
|
|
339
|
+
|
|
340
|
+
This is already partly present in `WorkspaceManager.tileLayer(...)`; the goal is to formalize it as plan data.
|
|
341
|
+
|
|
342
|
+
### Rule 5. Space optimization must always declare its strategy
|
|
343
|
+
|
|
344
|
+
If the system chooses a mosaic, it must say why.
|
|
345
|
+
|
|
346
|
+
Examples:
|
|
347
|
+
|
|
348
|
+
- "Used 2x2 grid because 4 windows were in scope"
|
|
349
|
+
- "Used 3-column mosaic because 5 windows fit better in landscape"
|
|
350
|
+
|
|
351
|
+
## Traceability design
|
|
352
|
+
|
|
353
|
+
Traceability is a product feature, not an internal debugging detail.
|
|
354
|
+
|
|
355
|
+
Every mutation endpoint should return:
|
|
356
|
+
|
|
357
|
+
- `request`
|
|
358
|
+
- `resolvedTargets`
|
|
359
|
+
- `appliedRules`
|
|
360
|
+
- `computedFrames`
|
|
361
|
+
- `executionPath`
|
|
362
|
+
- `failures`
|
|
363
|
+
|
|
364
|
+
### Example trace fields
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"resolvedTargets": [
|
|
369
|
+
{
|
|
370
|
+
"input": "Chrome",
|
|
371
|
+
"resolution": "wid",
|
|
372
|
+
"wid": 38192,
|
|
373
|
+
"reason": "frontmost app match"
|
|
374
|
+
}
|
|
375
|
+
],
|
|
376
|
+
"appliedRules": [
|
|
377
|
+
"placement top-right -> grid 2x2 cell 1,0",
|
|
378
|
+
"display current"
|
|
379
|
+
],
|
|
380
|
+
"executionPath": [
|
|
381
|
+
"DesktopModel",
|
|
382
|
+
"AX batch move"
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Daemon changes
|
|
388
|
+
|
|
389
|
+
We should not immediately remove existing endpoints. We should add a new execution layer and gradually migrate callers.
|
|
390
|
+
|
|
391
|
+
### New endpoints
|
|
392
|
+
|
|
393
|
+
### `actions.execute`
|
|
394
|
+
|
|
395
|
+
Primary mutation endpoint.
|
|
396
|
+
|
|
397
|
+
Input:
|
|
398
|
+
|
|
399
|
+
- one action or a batch of actions
|
|
400
|
+
|
|
401
|
+
Output:
|
|
402
|
+
|
|
403
|
+
- execution receipt with trace
|
|
404
|
+
|
|
405
|
+
### `actions.plan`
|
|
406
|
+
|
|
407
|
+
Dry-run planner.
|
|
408
|
+
|
|
409
|
+
Input:
|
|
410
|
+
|
|
411
|
+
- same as `actions.execute`
|
|
412
|
+
|
|
413
|
+
Output:
|
|
414
|
+
|
|
415
|
+
- execution plan with no side effects
|
|
416
|
+
|
|
417
|
+
This is critical for predictability and future previews.
|
|
418
|
+
|
|
419
|
+
### `actions.history`
|
|
420
|
+
|
|
421
|
+
Recent receipts.
|
|
422
|
+
|
|
423
|
+
Output:
|
|
424
|
+
|
|
425
|
+
- recent execution receipts for scrutability
|
|
426
|
+
|
|
427
|
+
This is also the future basis for undo.
|
|
428
|
+
|
|
429
|
+
### Existing endpoints to wrap first
|
|
430
|
+
|
|
431
|
+
These should internally route into the new planner/executor as early as possible:
|
|
432
|
+
|
|
433
|
+
- `window.tile`
|
|
434
|
+
- `window.present`
|
|
435
|
+
- `layout.distribute`
|
|
436
|
+
- `layer.switch`
|
|
437
|
+
|
|
438
|
+
Those existing RPC names can remain stable while their internals are replaced.
|
|
439
|
+
|
|
440
|
+
## Migration order
|
|
441
|
+
|
|
442
|
+
### Phase 1. Build the daemon execution core
|
|
443
|
+
|
|
444
|
+
Files likely involved:
|
|
445
|
+
|
|
446
|
+
- `app/Sources/LatticesApi.swift`
|
|
447
|
+
- new planner/executor files under `app/Sources/`
|
|
448
|
+
- `app/Sources/WindowTiler.swift`
|
|
449
|
+
- `app/Sources/WorkspaceManager.swift`
|
|
450
|
+
|
|
451
|
+
Deliverables:
|
|
452
|
+
|
|
453
|
+
- `ActionRequest`
|
|
454
|
+
- `ExecutionPlan`
|
|
455
|
+
- `ExecutionReceipt`
|
|
456
|
+
- shared placement parser
|
|
457
|
+
- `actions.plan`
|
|
458
|
+
- `actions.execute`
|
|
459
|
+
|
|
460
|
+
### Phase 2. Migrate existing daemon mutations
|
|
461
|
+
|
|
462
|
+
Replace internal implementations for:
|
|
463
|
+
|
|
464
|
+
- `window.tile`
|
|
465
|
+
- `layout.distribute`
|
|
466
|
+
- `layer.switch`
|
|
467
|
+
|
|
468
|
+
Deliverables:
|
|
469
|
+
|
|
470
|
+
- stable behavior through old API names
|
|
471
|
+
- receipts and traces returned in responses
|
|
472
|
+
|
|
473
|
+
### Phase 3. Make voice call the daemon directly
|
|
474
|
+
|
|
475
|
+
Files likely involved:
|
|
476
|
+
|
|
477
|
+
- `app/Sources/VoiceIntentResolver.swift`
|
|
478
|
+
- `app/Sources/IntentEngine.swift`
|
|
479
|
+
- `app/Sources/HandsOffSession.swift`
|
|
480
|
+
|
|
481
|
+
Deliverables:
|
|
482
|
+
|
|
483
|
+
- local voice emits canonical actions
|
|
484
|
+
- hands-off worker emits canonical actions
|
|
485
|
+
- no second interpretation pass for worker actions
|
|
486
|
+
|
|
487
|
+
### Phase 4. Migrate HUD and command palette
|
|
488
|
+
|
|
489
|
+
Files likely involved:
|
|
490
|
+
|
|
491
|
+
- `app/Sources/HUDController.swift`
|
|
492
|
+
- `app/Sources/PaletteCommand.swift`
|
|
493
|
+
|
|
494
|
+
Deliverables:
|
|
495
|
+
|
|
496
|
+
- all surfaces use the same planner/executor
|
|
497
|
+
- same traces available no matter how action was triggered
|
|
498
|
+
|
|
499
|
+
## Immediate implementation slice
|
|
500
|
+
|
|
501
|
+
The first practical slice should be:
|
|
502
|
+
|
|
503
|
+
1. Add a shared placement parser with first-class support for:
|
|
504
|
+
- existing `TilePosition` names
|
|
505
|
+
- `grid:CxR:C,R`
|
|
506
|
+
- new `top-third`, `middle-third`, `bottom-third`
|
|
507
|
+
- new quarter aliases
|
|
508
|
+
2. Add `actions.plan` and `actions.execute` for:
|
|
509
|
+
- `window.place`
|
|
510
|
+
- `space.optimize`
|
|
511
|
+
- `layer.activate`
|
|
512
|
+
3. Reimplement `window.tile` as a wrapper around `window.place`
|
|
513
|
+
4. Return a structured receipt from daemon mutations
|
|
514
|
+
|
|
515
|
+
That gives immediate product value:
|
|
516
|
+
|
|
517
|
+
- voice can target the daemon directly
|
|
518
|
+
- placement semantics stop drifting
|
|
519
|
+
- "why did you do that?" has a real answer
|
|
520
|
+
|
|
521
|
+
## Example v1 utterance mappings
|
|
522
|
+
|
|
523
|
+
These should become golden examples for tests.
|
|
524
|
+
|
|
525
|
+
### Window placement
|
|
526
|
+
|
|
527
|
+
- "Put Chrome in the top right corner" -> `window.place(target=Chrome, placement=top-right)`
|
|
528
|
+
- "Move Terminal to the right third" -> `window.place(target=Terminal, placement=right-third)`
|
|
529
|
+
- "Put this in the upper third" -> `window.place(target=frontmost, placement=top-third)`
|
|
530
|
+
- "Bottom quarter for Slack" -> `window.place(target=Slack, placement=bottom-quarter)`
|
|
531
|
+
|
|
532
|
+
### Layer activation
|
|
533
|
+
|
|
534
|
+
- "Bring up review" -> `layer.activate(name=review, mode=launch)`
|
|
535
|
+
- "Switch to mobile" -> `layer.activate(name=mobile, mode=focus)`
|
|
536
|
+
|
|
537
|
+
### Space optimization
|
|
538
|
+
|
|
539
|
+
- "Make this nice" -> `space.optimize(scope=visible, strategy=mosaic)`
|
|
540
|
+
- "Organize these windows" -> `space.optimize(scope=selection_or_visible, strategy=balanced)`
|
|
541
|
+
|
|
542
|
+
## Definition of success
|
|
543
|
+
|
|
544
|
+
This initiative is successful when:
|
|
545
|
+
|
|
546
|
+
- the daemon can plan and execute all three action families
|
|
547
|
+
- voice can issue those actions without direct subsystem calls
|
|
548
|
+
- every execution returns a scrutable receipt
|
|
549
|
+
- placement vocabulary is shared across all clients
|
|
550
|
+
- layout outcomes stop depending on which interface triggered them
|
|
551
|
+
|
|
552
|
+
## Recommendation
|
|
553
|
+
|
|
554
|
+
Start with daemon execution for `window.place`.
|
|
555
|
+
|
|
556
|
+
Why:
|
|
557
|
+
|
|
558
|
+
- it is the smallest useful vertical slice
|
|
559
|
+
- it serves voice immediately
|
|
560
|
+
- it forces the placement grammar to become canonical
|
|
561
|
+
- it establishes the receipt/trace model early
|
|
562
|
+
- it unlocks layer and optimize-space actions without rework
|