@lattices/cli 0.6.0 → 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.
Files changed (44) hide show
  1. package/README.md +13 -4
  2. package/apps/mac/Info.plist +4 -2
  3. package/apps/mac/Lattices.app/Contents/Info.plist +4 -2
  4. package/apps/mac/Lattices.app/Contents/MacOS/Lattices +0 -0
  5. package/apps/mac/Lattices.app/Contents/Resources/docs/assistant-knowledge.md +130 -0
  6. package/apps/mac/Lattices.app/Contents/_CodeSignature/CodeResources +11 -0
  7. package/apps/mac/Lattices.entitlements +6 -0
  8. package/bin/assistant-intelligence.ts +41 -3
  9. package/bin/cli/capture.ts +252 -0
  10. package/bin/cli/daemon.ts +22 -0
  11. package/bin/cli/helpers.ts +105 -0
  12. package/bin/cli/layer.ts +178 -0
  13. package/bin/cli/runs.ts +43 -0
  14. package/bin/cli/search.ts +141 -0
  15. package/bin/cli/session.ts +32 -0
  16. package/bin/client.ts +2 -1
  17. package/bin/cua.ts +26 -0
  18. package/bin/infer.ts +22 -4
  19. package/bin/keychain.ts +75 -0
  20. package/bin/lattices-app.ts +111 -12
  21. package/bin/lattices-build-env.ts +77 -0
  22. package/bin/lattices-dev +29 -2
  23. package/bin/lattices.ts +729 -769
  24. package/docs/api.md +496 -3
  25. package/docs/app.md +5 -4
  26. package/docs/assistant-knowledge.md +130 -0
  27. package/docs/config.md +5 -0
  28. package/docs/hyperspace-grid-snappiness.md +210 -0
  29. package/docs/layers.md +53 -0
  30. package/docs/mouse-gestures.md +40 -3
  31. package/docs/ocr.md +3 -0
  32. package/docs/prompts/hands-off-system.md +9 -1
  33. package/docs/proposals/LAT-006-followup-gaps.md +103 -0
  34. package/docs/proposals/{LAT-006-mira-in-lattices.md → LAT-006-runs-and-capture-in-lattices.md} +83 -70
  35. package/docs/quickstart.md +3 -1
  36. package/docs/reference/dewey.config.ts +1 -1
  37. package/docs/release.md +4 -3
  38. package/docs/terminal-kit.md +87 -0
  39. package/docs/tiling-reference.md +5 -3
  40. package/docs/voice.md +3 -3
  41. package/package.json +27 -5
  42. package/packages/npm/sdk/cua.d.mts +1 -0
  43. package/packages/npm/sdk/cua.d.ts +188 -0
  44. package/packages/npm/sdk/cua.mjs +376 -0
@@ -0,0 +1,188 @@
1
+ import type { z } from "zod";
2
+
3
+ export type ComputerTreatment = "observe" | "stage" | "present" | "execute";
4
+ export type ComputerClickTransport =
5
+ | "auto"
6
+ | "ax"
7
+ | "accessibility"
8
+ | "pointer"
9
+ | "mouse"
10
+ | "hardware";
11
+ export type CursorStyle = "spotlight" | "pulse" | "marker";
12
+ export type CursorShape =
13
+ | "arrow"
14
+ | "chevron"
15
+ | "facet"
16
+ | "shard"
17
+ | "wedge"
18
+ | "prism"
19
+ | "notch"
20
+ | "needle"
21
+ | "petal"
22
+ | "kite";
23
+ export type CursorSize = "tiny" | "small" | "regular" | "large";
24
+ export type CursorTrail = "none" | "thread" | "ribbon" | "spark" | "comet" | "route";
25
+ export type CursorMotion =
26
+ | "glide"
27
+ | "snap"
28
+ | "float"
29
+ | "rush"
30
+ | "crawl"
31
+ | "accelerate"
32
+ | "teleport"
33
+ | "spring"
34
+ | "magnet"
35
+ | "slingshot";
36
+ export type CursorTrajectory = "straight" | "soft" | "arc" | "swoop" | "overshoot";
37
+ export type CursorGlow = "none" | "soft" | "halo" | "comet";
38
+ export type CursorIdle =
39
+ | "still"
40
+ | "breathe"
41
+ | "wiggle"
42
+ | "orbit"
43
+ | "hover"
44
+ | "nod"
45
+ | "drift"
46
+ | "shimmer"
47
+ | "blink"
48
+ | "tremble";
49
+ export type CursorEdge =
50
+ | "none"
51
+ | "pulse"
52
+ | "ripple"
53
+ | "tick"
54
+ | "reticle"
55
+ | "blink"
56
+ | "spark"
57
+ | "underline"
58
+ | "echo"
59
+ | "scan"
60
+ | "pin";
61
+ export type CursorSound = "none" | "tick" | "click" | "engage" | "chime";
62
+ export type CaptionPlacement =
63
+ | "top-left"
64
+ | "top-right"
65
+ | "bottom-left"
66
+ | "bottom-right"
67
+ | "top-center"
68
+ | "top"
69
+ | "center"
70
+ | "middle"
71
+ | "near-cursor"
72
+ | "cursor";
73
+
74
+ export interface WindowTarget {
75
+ wid?: number;
76
+ app?: string;
77
+ title?: string;
78
+ }
79
+
80
+ export interface ActionBase {
81
+ treatment?: ComputerTreatment;
82
+ dryRun?: boolean;
83
+ capture?: boolean;
84
+ source?: string;
85
+ }
86
+
87
+ export interface PointTarget {
88
+ x?: number;
89
+ y?: number;
90
+ xRatio?: number;
91
+ yRatio?: number;
92
+ }
93
+
94
+ export interface ComputerClickParams extends WindowTarget, PointTarget, ActionBase {
95
+ button?: "left" | "right" | "secondary" | "context";
96
+ transport?: ComputerClickTransport;
97
+ axLabel?: string;
98
+ targetText?: string;
99
+ noFocus?: boolean;
100
+ label?: string;
101
+ }
102
+
103
+ export interface ComputerMagicCursorParams extends WindowTarget, PointTarget, ActionBase {
104
+ style?: CursorStyle;
105
+ appearance?: CursorStyle;
106
+ shape?: CursorShape;
107
+ angleDeg?: number;
108
+ size?: CursorSize;
109
+ color?: string;
110
+ durationMs?: number;
111
+ label?: string;
112
+ caption?: string;
113
+ captionTitle?: string;
114
+ captionBody?: string;
115
+ captionDetail?: string;
116
+ captionTags?: string;
117
+ captionMode?: "auto" | "selection";
118
+ captionEyebrow?: string;
119
+ captionLeadMs?: number;
120
+ captionSound?: CursorSound;
121
+ captionPlacement?: CaptionPlacement;
122
+ captionMargin?: number;
123
+ captionX?: number;
124
+ captionY?: number;
125
+ captionXRatio?: number;
126
+ captionYRatio?: number;
127
+ captionLeftRatio?: number;
128
+ captionTopRatio?: number;
129
+ sound?: CursorSound;
130
+ sfx?: CursorSound;
131
+ showCaption?: boolean;
132
+ captionSelections?: boolean;
133
+ treatmentLabel?: string;
134
+ variant?: string;
135
+ trail?: CursorTrail;
136
+ pathStyle?: CursorTrail;
137
+ motion?: CursorMotion;
138
+ trajectory?: CursorTrajectory;
139
+ glow?: CursorGlow;
140
+ bloom?: CursorGlow;
141
+ idle?: CursorIdle;
142
+ settle?: CursorIdle;
143
+ presence?: CursorIdle;
144
+ edge?: CursorEdge;
145
+ edgeEffect?: CursorEdge;
146
+ arrival?: CursorEdge;
147
+ typewriter?: boolean;
148
+ typing?: boolean;
149
+ typeIntervalMs?: number;
150
+ typingIntervalMs?: number;
151
+ text?: string;
152
+ append?: boolean;
153
+ fromX?: number;
154
+ fromY?: number;
155
+ fromXRatio?: number;
156
+ fromYRatio?: number;
157
+ }
158
+
159
+ export interface CuaClientOptions {
160
+ defaultTimeoutMs?: number;
161
+ }
162
+
163
+ export interface CuaClient {
164
+ click(params: ComputerClickParams): Promise<unknown>;
165
+ magicCursor(params: ComputerMagicCursorParams): Promise<unknown>;
166
+ }
167
+
168
+ export declare const computerTreatmentSchema: z.ZodType<ComputerTreatment>;
169
+ export declare const computerClickTransportSchema: z.ZodType<ComputerClickTransport>;
170
+ export declare const cursorStyleSchema: z.ZodType<CursorStyle>;
171
+ export declare const cursorShapeSchema: z.ZodType<CursorShape>;
172
+ export declare const cursorSizeSchema: z.ZodType<CursorSize>;
173
+ export declare const cursorTrailSchema: z.ZodType<CursorTrail>;
174
+ export declare const cursorMotionSchema: z.ZodType<CursorMotion>;
175
+ export declare const cursorTrajectorySchema: z.ZodType<CursorTrajectory>;
176
+ export declare const cursorGlowSchema: z.ZodType<CursorGlow>;
177
+ export declare const cursorIdleSchema: z.ZodType<CursorIdle>;
178
+ export declare const cursorEdgeSchema: z.ZodType<CursorEdge>;
179
+ export declare const cursorSoundSchema: z.ZodType<CursorSound>;
180
+ export declare const captionPlacementSchema: z.ZodType<CaptionPlacement>;
181
+ export declare const computerClickParamsSchema: z.ZodType<ComputerClickParams>;
182
+ export declare const computerMagicCursorParamsSchema: z.ZodType<ComputerMagicCursorParams>;
183
+
184
+ export declare function createCuaClient(options?: CuaClientOptions): CuaClient;
185
+ export declare function click(params: ComputerClickParams): Promise<unknown>;
186
+ export declare function magicCursor(params: ComputerMagicCursorParams): Promise<unknown>;
187
+
188
+ export declare const cua: CuaClient;
@@ -0,0 +1,376 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { createConnection } from "node:net";
3
+
4
+ import { z } from "zod";
5
+
6
+ const DAEMON_HOST = "127.0.0.1";
7
+ const DAEMON_PORT = 9399;
8
+
9
+ export const computerTreatmentSchema = z.enum([
10
+ "observe",
11
+ "stage",
12
+ "present",
13
+ "execute",
14
+ ]);
15
+
16
+ export const computerClickTransportSchema = z.enum([
17
+ "auto",
18
+ "ax",
19
+ "accessibility",
20
+ "pointer",
21
+ "mouse",
22
+ "hardware",
23
+ ]);
24
+
25
+ export const cursorStyleSchema = z.enum(["spotlight", "pulse", "marker"]);
26
+ export const cursorShapeSchema = z.enum([
27
+ "arrow",
28
+ "chevron",
29
+ "facet",
30
+ "shard",
31
+ "wedge",
32
+ "prism",
33
+ "notch",
34
+ "needle",
35
+ "petal",
36
+ "kite",
37
+ ]);
38
+ export const cursorSizeSchema = z.enum(["tiny", "small", "regular", "large"]);
39
+ export const cursorTrailSchema = z.enum(["none", "thread", "ribbon", "spark", "comet", "route"]);
40
+ export const cursorMotionSchema = z.enum([
41
+ "glide",
42
+ "snap",
43
+ "float",
44
+ "rush",
45
+ "crawl",
46
+ "accelerate",
47
+ "teleport",
48
+ "spring",
49
+ "magnet",
50
+ "slingshot",
51
+ ]);
52
+ export const cursorTrajectorySchema = z.enum(["straight", "soft", "arc", "swoop", "overshoot"]);
53
+ export const cursorGlowSchema = z.enum(["none", "soft", "halo", "comet"]);
54
+ export const cursorIdleSchema = z.enum([
55
+ "still",
56
+ "breathe",
57
+ "wiggle",
58
+ "orbit",
59
+ "hover",
60
+ "nod",
61
+ "drift",
62
+ "shimmer",
63
+ "blink",
64
+ "tremble",
65
+ ]);
66
+ export const cursorEdgeSchema = z.enum([
67
+ "none",
68
+ "pulse",
69
+ "ripple",
70
+ "tick",
71
+ "reticle",
72
+ "blink",
73
+ "spark",
74
+ "underline",
75
+ "echo",
76
+ "scan",
77
+ "pin",
78
+ ]);
79
+ export const cursorSoundSchema = z.enum(["none", "tick", "click", "engage", "chime"]);
80
+ export const captionPlacementSchema = z.enum([
81
+ "top-left",
82
+ "top-right",
83
+ "bottom-left",
84
+ "bottom-right",
85
+ "top-center",
86
+ "top",
87
+ "center",
88
+ "middle",
89
+ "near-cursor",
90
+ "cursor",
91
+ ]);
92
+
93
+ const ratioSchema = z.number().min(0).max(1);
94
+ const pointSchema = z.number().finite();
95
+
96
+ const windowTargetSchema = z.object({
97
+ wid: z.number().int().positive().optional(),
98
+ app: z.string().min(1).optional(),
99
+ title: z.string().optional(),
100
+ });
101
+
102
+ const actionBaseSchema = z.object({
103
+ treatment: computerTreatmentSchema.optional(),
104
+ dryRun: z.boolean().optional(),
105
+ capture: z.boolean().optional(),
106
+ source: z.string().optional(),
107
+ });
108
+
109
+ const pointTargetSchema = z.object({
110
+ x: pointSchema.optional(),
111
+ y: pointSchema.optional(),
112
+ xRatio: ratioSchema.optional(),
113
+ yRatio: ratioSchema.optional(),
114
+ });
115
+
116
+ const cursorAppearanceSchema = z.object({
117
+ style: cursorStyleSchema.optional(),
118
+ appearance: cursorStyleSchema.optional(),
119
+ shape: cursorShapeSchema.optional(),
120
+ angleDeg: z.number().finite().optional(),
121
+ size: cursorSizeSchema.optional(),
122
+ color: z.string().min(1).optional(),
123
+ durationMs: z.number().int().positive().optional(),
124
+ label: z.string().optional(),
125
+ caption: z.string().optional(),
126
+ captionTitle: z.string().optional(),
127
+ captionBody: z.string().optional(),
128
+ captionDetail: z.string().optional(),
129
+ captionTags: z.string().optional(),
130
+ captionMode: z.enum(["auto", "selection"]).optional(),
131
+ captionEyebrow: z.string().optional(),
132
+ captionLeadMs: z.number().finite().nonnegative().optional(),
133
+ captionSound: cursorSoundSchema.optional(),
134
+ captionPlacement: captionPlacementSchema.optional(),
135
+ captionMargin: z.number().finite().nonnegative().optional(),
136
+ captionX: z.number().finite().optional(),
137
+ captionY: z.number().finite().optional(),
138
+ captionXRatio: ratioSchema.optional(),
139
+ captionYRatio: ratioSchema.optional(),
140
+ captionLeftRatio: ratioSchema.optional(),
141
+ captionTopRatio: ratioSchema.optional(),
142
+ sound: cursorSoundSchema.optional(),
143
+ sfx: cursorSoundSchema.optional(),
144
+ showCaption: z.boolean().optional(),
145
+ captionSelections: z.boolean().optional(),
146
+ treatmentLabel: z.string().optional(),
147
+ variant: z.string().optional(),
148
+ trail: cursorTrailSchema.optional(),
149
+ pathStyle: cursorTrailSchema.optional(),
150
+ motion: cursorMotionSchema.optional(),
151
+ trajectory: cursorTrajectorySchema.optional(),
152
+ glow: cursorGlowSchema.optional(),
153
+ bloom: cursorGlowSchema.optional(),
154
+ idle: cursorIdleSchema.optional(),
155
+ settle: cursorIdleSchema.optional(),
156
+ presence: cursorIdleSchema.optional(),
157
+ edge: cursorEdgeSchema.optional(),
158
+ edgeEffect: cursorEdgeSchema.optional(),
159
+ arrival: cursorEdgeSchema.optional(),
160
+ typewriter: z.boolean().optional(),
161
+ typing: z.boolean().optional(),
162
+ typeIntervalMs: z.number().finite().positive().optional(),
163
+ typingIntervalMs: z.number().finite().positive().optional(),
164
+ });
165
+
166
+ export const computerClickParamsSchema = windowTargetSchema
167
+ .merge(pointTargetSchema)
168
+ .merge(actionBaseSchema)
169
+ .merge(cursorAppearanceSchema.pick({ label: true }))
170
+ .extend({
171
+ button: z.enum(["left", "right", "secondary", "context"]).optional(),
172
+ transport: computerClickTransportSchema.optional(),
173
+ axLabel: z.string().min(1).optional(),
174
+ targetText: z.string().min(1).optional(),
175
+ noFocus: z.boolean().optional(),
176
+ });
177
+
178
+ export const computerMagicCursorParamsSchema = windowTargetSchema
179
+ .merge(pointTargetSchema)
180
+ .merge(actionBaseSchema)
181
+ .merge(cursorAppearanceSchema)
182
+ .extend({
183
+ text: z.string().optional(),
184
+ append: z.boolean().optional(),
185
+ fromX: pointSchema.optional(),
186
+ fromY: pointSchema.optional(),
187
+ fromXRatio: ratioSchema.optional(),
188
+ fromYRatio: ratioSchema.optional(),
189
+ });
190
+
191
+ export function createCuaClient(options = {}) {
192
+ const defaultTimeoutMs = options.defaultTimeoutMs ?? 30_000;
193
+
194
+ async function call(method, params, timeoutMs = defaultTimeoutMs) {
195
+ return daemonCall(method, params, timeoutMs);
196
+ }
197
+
198
+ return {
199
+ click(params) {
200
+ return call("computer.click", computerClickParamsSchema.parse(params));
201
+ },
202
+ magicCursor(params) {
203
+ return call("computer.magicCursor", computerMagicCursorParamsSchema.parse(params));
204
+ },
205
+ };
206
+ }
207
+
208
+ export const cua = createCuaClient();
209
+
210
+ export function click(params) {
211
+ return cua.click(params);
212
+ }
213
+
214
+ export function magicCursor(params) {
215
+ return cua.magicCursor(params);
216
+ }
217
+
218
+ async function daemonCall(method, params = null, timeoutMs = 3000) {
219
+ const id = randomBytes(4).toString("hex");
220
+ const request = JSON.stringify({ id, method, params: params ?? null });
221
+
222
+ return new Promise((resolve, reject) => {
223
+ const socket = createConnection({ host: DAEMON_HOST, port: DAEMON_PORT });
224
+ let settled = false;
225
+ let buffer = Buffer.alloc(0);
226
+ let upgraded = false;
227
+
228
+ const timer = setTimeout(() => {
229
+ if (!settled) {
230
+ settled = true;
231
+ socket.destroy();
232
+ reject(new Error("Daemon request timed out"));
233
+ }
234
+ }, timeoutMs);
235
+
236
+ const cleanup = () => {
237
+ clearTimeout(timer);
238
+ socket.destroy();
239
+ };
240
+
241
+ socket.on("error", (err) => {
242
+ if (!settled) {
243
+ settled = true;
244
+ cleanup();
245
+ reject(err);
246
+ }
247
+ });
248
+
249
+ socket.on("connect", () => {
250
+ const key = randomBytes(16).toString("base64");
251
+ const upgrade = [
252
+ "GET / HTTP/1.1",
253
+ `Host: ${DAEMON_HOST}:${DAEMON_PORT}`,
254
+ "Upgrade: websocket",
255
+ "Connection: Upgrade",
256
+ `Sec-WebSocket-Key: ${key}`,
257
+ "Sec-WebSocket-Version: 13",
258
+ "",
259
+ "",
260
+ ].join("\r\n");
261
+ socket.write(upgrade);
262
+ });
263
+
264
+ socket.on("data", (chunk) => {
265
+ buffer = Buffer.concat([buffer, chunk]);
266
+
267
+ if (!upgraded) {
268
+ const headerEnd = buffer.indexOf("\r\n\r\n");
269
+ if (headerEnd === -1) return;
270
+ const header = buffer.subarray(0, headerEnd).toString();
271
+ if (!header.includes("101")) {
272
+ settled = true;
273
+ cleanup();
274
+ reject(new Error("WebSocket upgrade failed"));
275
+ return;
276
+ }
277
+ upgraded = true;
278
+ buffer = buffer.subarray(headerEnd + 4);
279
+ sendFrame(socket, request);
280
+ }
281
+
282
+ while (true) {
283
+ const result = parseFrame(buffer);
284
+ if (!result) break;
285
+ buffer = result.rest;
286
+
287
+ try {
288
+ const parsed = JSON.parse(result.payload);
289
+ if (parsed.event || parsed.id !== id) continue;
290
+ if (!settled) {
291
+ settled = true;
292
+ cleanup();
293
+ if (parsed.error) {
294
+ reject(new Error(parsed.error));
295
+ } else {
296
+ resolve(parsed.result);
297
+ }
298
+ }
299
+ return;
300
+ } catch {
301
+ if (!settled) {
302
+ settled = true;
303
+ cleanup();
304
+ reject(new Error("Invalid JSON response from daemon"));
305
+ }
306
+ return;
307
+ }
308
+ }
309
+ });
310
+ });
311
+ }
312
+
313
+ function sendFrame(socket, text) {
314
+ const payload = Buffer.from(text, "utf8");
315
+ const mask = randomBytes(4);
316
+ const len = payload.length;
317
+
318
+ let header;
319
+ if (len < 126) {
320
+ header = Buffer.alloc(2);
321
+ header[0] = 0x81;
322
+ header[1] = 0x80 | len;
323
+ } else if (len < 65536) {
324
+ header = Buffer.alloc(4);
325
+ header[0] = 0x81;
326
+ header[1] = 0x80 | 126;
327
+ header.writeUInt16BE(len, 2);
328
+ } else {
329
+ header = Buffer.alloc(10);
330
+ header[0] = 0x81;
331
+ header[1] = 0x80 | 127;
332
+ header.writeBigUInt64BE(BigInt(len), 2);
333
+ }
334
+
335
+ const masked = Buffer.alloc(payload.length);
336
+ for (let i = 0; i < payload.length; i++) {
337
+ masked[i] = payload[i] ^ mask[i % 4];
338
+ }
339
+
340
+ socket.write(Buffer.concat([header, mask, masked]));
341
+ }
342
+
343
+ function parseFrame(buf) {
344
+ if (buf.length < 2) return null;
345
+
346
+ const isMasked = (buf[1] & 0x80) !== 0;
347
+ let payloadLen = buf[1] & 0x7f;
348
+ let offset = 2;
349
+
350
+ if (payloadLen === 126) {
351
+ if (buf.length < 4) return null;
352
+ payloadLen = buf.readUInt16BE(2);
353
+ offset = 4;
354
+ } else if (payloadLen === 127) {
355
+ if (buf.length < 10) return null;
356
+ payloadLen = Number(buf.readBigUInt64BE(2));
357
+ offset = 10;
358
+ }
359
+
360
+ if (isMasked) offset += 4;
361
+ if (buf.length < offset + payloadLen) return null;
362
+
363
+ let payload = buf.subarray(offset, offset + payloadLen);
364
+ if (isMasked) {
365
+ const maskKey = buf.subarray(offset - 4, offset);
366
+ payload = Buffer.alloc(payloadLen);
367
+ for (let i = 0; i < payloadLen; i++) {
368
+ payload[i] = buf[offset + i] ^ maskKey[i % 4];
369
+ }
370
+ }
371
+
372
+ return {
373
+ payload: payload.toString("utf8"),
374
+ rest: buf.subarray(offset + payloadLen),
375
+ };
376
+ }