@myerscarpenter/quest-dev 1.4.1 → 2.0.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 (142) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/.github/workflows/docs.yml +45 -0
  3. package/.github/workflows/publish.yml +11 -1
  4. package/README.md +27 -0
  5. package/build/cast/decoder.d.ts +48 -0
  6. package/build/cast/decoder.d.ts.map +1 -0
  7. package/build/cast/decoder.js +152 -0
  8. package/build/cast/decoder.js.map +1 -0
  9. package/build/cast/session.d.ts +87 -0
  10. package/build/cast/session.d.ts.map +1 -0
  11. package/build/cast/session.js +565 -0
  12. package/build/cast/session.js.map +1 -0
  13. package/build/commands/logcat.d.ts.map +1 -1
  14. package/build/commands/logcat.js +7 -6
  15. package/build/commands/logcat.js.map +1 -1
  16. package/build/commands/screenshot.d.ts.map +1 -1
  17. package/build/commands/screenshot.js +17 -20
  18. package/build/commands/screenshot.js.map +1 -1
  19. package/build/commands/stay-awake.d.ts +2 -15
  20. package/build/commands/stay-awake.d.ts.map +1 -1
  21. package/build/commands/stay-awake.js +14 -77
  22. package/build/commands/stay-awake.js.map +1 -1
  23. package/build/daemon/cast-manager.d.ts +42 -0
  24. package/build/daemon/cast-manager.d.ts.map +1 -0
  25. package/build/daemon/cast-manager.js +243 -0
  26. package/build/daemon/cast-manager.js.map +1 -0
  27. package/build/daemon/client.d.ts +40 -0
  28. package/build/daemon/client.d.ts.map +1 -0
  29. package/build/daemon/client.js +133 -0
  30. package/build/daemon/client.js.map +1 -0
  31. package/build/daemon/daemon.d.ts +20 -0
  32. package/build/daemon/daemon.d.ts.map +1 -0
  33. package/build/daemon/daemon.js +130 -0
  34. package/build/daemon/daemon.js.map +1 -0
  35. package/build/daemon/deploy.d.ts +44 -0
  36. package/build/daemon/deploy.d.ts.map +1 -0
  37. package/build/daemon/deploy.js +230 -0
  38. package/build/daemon/deploy.js.map +1 -0
  39. package/build/daemon/logcat-manager.d.ts +39 -0
  40. package/build/daemon/logcat-manager.d.ts.map +1 -0
  41. package/build/daemon/logcat-manager.js +194 -0
  42. package/build/daemon/logcat-manager.js.map +1 -0
  43. package/build/daemon/server.d.ts +19 -0
  44. package/build/daemon/server.d.ts.map +1 -0
  45. package/build/daemon/server.js +482 -0
  46. package/build/daemon/server.js.map +1 -0
  47. package/build/daemon/stay-awake-manager.d.ts +22 -0
  48. package/build/daemon/stay-awake-manager.d.ts.map +1 -0
  49. package/build/daemon/stay-awake-manager.js +74 -0
  50. package/build/daemon/stay-awake-manager.js.map +1 -0
  51. package/build/index.js +272 -45
  52. package/build/index.js.map +1 -1
  53. package/build/public/dashboard.js +749 -0
  54. package/build/public/index.html +12 -0
  55. package/build/public/style.css +106 -0
  56. package/build/utils/adb.d.ts +6 -0
  57. package/build/utils/adb.d.ts.map +1 -1
  58. package/build/utils/adb.js +62 -66
  59. package/build/utils/adb.js.map +1 -1
  60. package/build/utils/casting-apk.d.ts +40 -0
  61. package/build/utils/casting-apk.d.ts.map +1 -0
  62. package/build/utils/casting-apk.js +252 -0
  63. package/build/utils/casting-apk.js.map +1 -0
  64. package/build/utils/config.d.ts +5 -3
  65. package/build/utils/config.d.ts.map +1 -1
  66. package/build/utils/config.js +18 -38
  67. package/build/utils/config.js.map +1 -1
  68. package/build/utils/exec.d.ts +5 -0
  69. package/build/utils/exec.d.ts.map +1 -1
  70. package/build/utils/exec.js +17 -0
  71. package/build/utils/exec.js.map +1 -1
  72. package/build/utils/filename.d.ts +7 -1
  73. package/build/utils/filename.d.ts.map +1 -1
  74. package/build/utils/filename.js +17 -2
  75. package/build/utils/filename.js.map +1 -1
  76. package/build/utils/filename.test.js +33 -1
  77. package/build/utils/filename.test.js.map +1 -1
  78. package/build/utils/jpeg-comment.d.ts +14 -0
  79. package/build/utils/jpeg-comment.d.ts.map +1 -0
  80. package/build/utils/jpeg-comment.js +28 -0
  81. package/build/utils/jpeg-comment.js.map +1 -0
  82. package/build/utils/test-properties.d.ts +34 -0
  83. package/build/utils/test-properties.d.ts.map +1 -0
  84. package/build/utils/test-properties.js +73 -0
  85. package/build/utils/test-properties.js.map +1 -0
  86. package/package.json +11 -5
  87. package/packages/cast2-protocol/README.md +86 -0
  88. package/packages/cast2-protocol/docs/_config.yml +4 -0
  89. package/packages/cast2-protocol/docs/feature-flags.md +102 -0
  90. package/packages/cast2-protocol/docs/index.md +24 -0
  91. package/packages/cast2-protocol/docs/open-investigations.md +149 -0
  92. package/packages/cast2-protocol/docs/protocol.md +602 -0
  93. package/packages/cast2-protocol/package.json +46 -0
  94. package/packages/cast2-protocol/src/constants.ts +65 -0
  95. package/packages/cast2-protocol/src/index.ts +7 -0
  96. package/packages/cast2-protocol/src/mgik.ts +69 -0
  97. package/packages/cast2-protocol/src/mud.ts +294 -0
  98. package/packages/cast2-protocol/src/pose.ts +99 -0
  99. package/packages/cast2-protocol/src/resolutions.ts +34 -0
  100. package/packages/cast2-protocol/src/types.ts +64 -0
  101. package/packages/cast2-protocol/src/xrsp.ts +73 -0
  102. package/packages/cast2-protocol/tests/mgik.test.ts +80 -0
  103. package/packages/cast2-protocol/tests/mud.test.ts +295 -0
  104. package/packages/cast2-protocol/tests/pose.test.ts +173 -0
  105. package/packages/cast2-protocol/tests/xrsp.test.ts +90 -0
  106. package/packages/cast2-protocol/tsconfig.json +20 -0
  107. package/pnpm-workspace.yaml +2 -0
  108. package/src/cast/decoder.ts +178 -0
  109. package/src/cast/session.ts +708 -0
  110. package/src/commands/logcat.ts +6 -5
  111. package/src/commands/screenshot.ts +19 -13
  112. package/src/commands/stay-awake.ts +22 -91
  113. package/src/daemon/adbkit-apkreader.d.ts +14 -0
  114. package/src/daemon/cast-manager.ts +282 -0
  115. package/src/daemon/client.ts +166 -0
  116. package/src/daemon/daemon.ts +169 -0
  117. package/src/daemon/deploy.ts +307 -0
  118. package/src/daemon/logcat-manager.ts +229 -0
  119. package/src/daemon/server.ts +595 -0
  120. package/src/daemon/stay-awake-manager.ts +83 -0
  121. package/src/index.ts +326 -56
  122. package/src/public/dashboard.js +288 -0
  123. package/src/public/index.html +12 -0
  124. package/src/public/style.css +106 -0
  125. package/src/utils/adb.ts +70 -57
  126. package/src/utils/casting-apk.ts +276 -0
  127. package/src/utils/config.ts +18 -36
  128. package/src/utils/exec.ts +20 -0
  129. package/src/utils/filename.test.ts +41 -1
  130. package/src/utils/filename.ts +18 -2
  131. package/src/utils/jpeg-comment.ts +30 -0
  132. package/src/utils/test-properties.ts +94 -0
  133. package/tests/cast/auto-layer.test.ts +87 -0
  134. package/tests/cast/decoder.test.ts +82 -0
  135. package/tests/cast/session-restart.test.ts +107 -0
  136. package/tests/config.test.ts +17 -22
  137. package/tests/daemon/api-status.test.ts +82 -0
  138. package/tests/daemon/cast-manager.test.ts +69 -0
  139. package/tests/daemon/mjpeg-stream.test.ts +144 -0
  140. package/tests/daemon/pose-endpoint.test.ts +63 -0
  141. package/tests/daemon/start-guard.test.ts +77 -0
  142. package/vitest.config.ts +10 -0
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Unified Fastify server for the quest-dev daemon.
3
+ * Hosts all endpoint groups: core, stay-awake, logcat, deploy, cast.
4
+ */
5
+ import Fastify from "fastify";
6
+ import fastifyStatic from "@fastify/static";
7
+ import { join, dirname } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import { loadPin, loadConfig } from "../utils/config.js";
10
+ import { getBatteryInfo } from "../utils/adb.js";
11
+ import { execCommand } from "../utils/exec.js";
12
+ import { adbArgs } from "../utils/adb.js";
13
+ import { EYE_LEFT, EYE_RIGHT, EYE_STEREO, RESOLUTIONS, resolveResolution } from "@myerscarpenter/cast2-protocol";
14
+ import { deploy } from "./deploy.js";
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ export async function createDaemonServer(options) {
17
+ const { port, host, stayAwake, logcat, castManager, onActivity, onShutdown } = options;
18
+ const config = loadConfig();
19
+ const app = Fastify({ logger: false });
20
+ // Static file serving for dashboard
21
+ const publicDir = join(__dirname, "..", "public");
22
+ await app.register(fastifyStatic, {
23
+ root: publicDir,
24
+ prefix: "/",
25
+ decorateReply: false,
26
+ });
27
+ // Activity tracking: reset idle timer on every request
28
+ app.addHook("onRequest", async () => {
29
+ onActivity();
30
+ });
31
+ // --- Core endpoints ---
32
+ app.get("/help", async (_req, reply) => {
33
+ const help = `quest-dev daemon — REST API
34
+
35
+ GET endpoints
36
+ /help This help screen
37
+ /status JSON: uptime, pid, stay_awake, cast, logcat, battery
38
+ /stay-awake/status JSON: stay-awake state
39
+ /logcat/status JSON: logcat capture state
40
+ /cast/help Cast-specific API reference
41
+ /cast/status JSON: cast session state
42
+ /cast/screenshot Latest frame as JPEG
43
+ /cast/stream MJPEG stream (multipart/x-mixed-replace)
44
+ /cast/layers JSON: available layers and active layer ID
45
+ /cast/events SSE stream: state changes and toast notifications
46
+
47
+ POST endpoints (JSON body)
48
+ /shutdown Shut down daemon
49
+ /stay-awake/enable Enable stay-awake (body: { pin? })
50
+ /stay-awake/disable Disable stay-awake
51
+ /logcat/start Start logcat capture (body: { tag? })
52
+ /logcat/stop Stop logcat capture
53
+ /cast/start Start casting (body: { resolution?, listen_port? })
54
+ /cast/stop Stop casting
55
+ /cast/restart Restart cast session
56
+ /cast/reset-view Reset camera offset to headset
57
+ /cast/home Press Home button
58
+ /cast/resolutions List available resolution presets
59
+ /cast/config Set resolution (body: { resolution } or { width, height })
60
+ /cast/eye Set eye mode (body: { mode })
61
+ /cast/pose Set/nudge camera offset from headset
62
+ /cast/click Tap at coordinates (body: { x, y })
63
+ `;
64
+ return reply.type("text/plain").send(help);
65
+ });
66
+ app.get("/status", async () => {
67
+ let battery = null;
68
+ try {
69
+ const info = await getBatteryInfo();
70
+ battery = { level: info.level, state: info.state };
71
+ }
72
+ catch {
73
+ // Device might be unavailable
74
+ }
75
+ const logcatStatus = logcat.status();
76
+ return {
77
+ uptime: Math.round(process.uptime()),
78
+ pid: process.pid,
79
+ stay_awake: stayAwake.isEnabled,
80
+ cast: { active: castManager.isActive },
81
+ logcat: {
82
+ capturing: logcatStatus.capturing,
83
+ file: logcatStatus.file,
84
+ size: logcatStatus.size,
85
+ },
86
+ battery,
87
+ };
88
+ });
89
+ app.post("/shutdown", async () => {
90
+ castManager.cleanup();
91
+ setTimeout(() => onShutdown(), 100);
92
+ return { ok: true, message: "shutting down" };
93
+ });
94
+ // --- Stay-Awake endpoints ---
95
+ app.post("/stay-awake/enable", async (req) => {
96
+ let pin;
97
+ try {
98
+ pin = loadPin(req.body?.pin);
99
+ }
100
+ catch {
101
+ return { ok: false, error: "PIN required" };
102
+ }
103
+ try {
104
+ await stayAwake.enable(pin);
105
+ return { ok: true };
106
+ }
107
+ catch (error) {
108
+ return { ok: false, error: error.message };
109
+ }
110
+ });
111
+ app.post("/stay-awake/disable", async () => {
112
+ await stayAwake.disable();
113
+ return { ok: true };
114
+ });
115
+ app.get("/stay-awake/status", async () => {
116
+ const props = await stayAwake.status();
117
+ return {
118
+ enabled: stayAwake.isEnabled,
119
+ properties: props,
120
+ };
121
+ });
122
+ // --- Logcat endpoints ---
123
+ app.post("/logcat/start", async (req) => {
124
+ const filter = req.body?.filter;
125
+ const result = await logcat.start(filter);
126
+ return { ok: true, file: result.file, pid: result.pid };
127
+ });
128
+ app.post("/logcat/stop", async () => {
129
+ logcat.stop();
130
+ return { ok: true };
131
+ });
132
+ app.get("/logcat/status", async () => {
133
+ return logcat.status();
134
+ });
135
+ app.get("/logcat/read", async (req) => {
136
+ const lineCount = parseInt(req.query.lines || "50", 10);
137
+ const lines = logcat.readTail(lineCount);
138
+ return { lines };
139
+ });
140
+ // --- Deploy endpoint ---
141
+ app.post("/deploy", async (req) => {
142
+ const { apk_path, crash_wait_ms } = req.body ?? {};
143
+ if (!apk_path) {
144
+ return { ok: false, error: "apk_path required" };
145
+ }
146
+ let pin;
147
+ try {
148
+ pin = loadPin();
149
+ }
150
+ catch {
151
+ // No PIN configured
152
+ }
153
+ const result = await deploy({ apkPath: apk_path, crashWaitMs: crash_wait_ms, pin }, stayAwake, logcat);
154
+ return result;
155
+ });
156
+ // --- Cast endpoints ---
157
+ app.post("/cast/start", async (req) => {
158
+ if (castManager.isActive) {
159
+ return { ok: true, already_running: true };
160
+ }
161
+ try {
162
+ await castManager.start({
163
+ listenPort: req.body?.listen_port,
164
+ resolution: req.body?.resolution,
165
+ width: req.body?.width,
166
+ height: req.body?.height,
167
+ });
168
+ return { ok: true };
169
+ }
170
+ catch (error) {
171
+ return { ok: false, error: error.message };
172
+ }
173
+ });
174
+ app.post("/cast/stop", async () => {
175
+ const session = castManager.getSession();
176
+ if (!session?.connected)
177
+ return { error: "cast not active" };
178
+ await castManager.stop();
179
+ castManager.broadcastToast("Casting stopped");
180
+ return { ok: true };
181
+ });
182
+ app.post("/cast/restart", async () => {
183
+ try {
184
+ await castManager.restart();
185
+ return { ok: true, msg: "restarting cast session" };
186
+ }
187
+ catch (error) {
188
+ return { ok: false, error: error.message };
189
+ }
190
+ });
191
+ app.get("/cast/events", async (_req, reply) => {
192
+ reply.raw.writeHead(200, {
193
+ "Content-Type": "text/event-stream",
194
+ "Cache-Control": "no-cache",
195
+ Connection: "keep-alive",
196
+ });
197
+ // Send full status snapshot immediately
198
+ const init = castManager.getStatus();
199
+ reply.raw.write(`event: status\ndata: ${JSON.stringify(init)}\n\n`);
200
+ castManager.addSSEClient(reply.raw);
201
+ _req.raw.on("close", () => castManager.removeSSEClient(reply.raw));
202
+ });
203
+ app.get("/cast/help", async (_req, reply) => {
204
+ const help = `quest-dev cast — REST API
205
+
206
+ GET endpoints
207
+ /cast/help This help screen
208
+ /cast/screenshot Latest frame as JPEG (503 if no frame)
209
+ /cast/stream MJPEG stream (multipart/x-mixed-replace)
210
+ /cast/status JSON: connected, running, resolution, fps, frame_count, pose
211
+ /cast/layers JSON: available layers and active layer ID
212
+ /cast/events SSE stream: state changes and toast notifications
213
+
214
+ GET endpoints (continued)
215
+ /cast/resolutions List available resolution presets
216
+
217
+ POST endpoints (JSON body)
218
+ /cast/start Start casting (optional: { resolution, listen_port })
219
+ /cast/stop Stop casting (daemon stays running)
220
+ /cast/restart Restart cast session
221
+ /cast/config Set resolution
222
+ { resolution: "720p" } or { width, height }
223
+ /cast/eye Set eye mode
224
+ { mode: "left" | "right" | "stereo" }
225
+ /cast/pose Set or nudge camera offset from headset (not world space)
226
+ Offset: { x, y, z, yaw, pitch } (relative to HMD)
227
+ Delta: { dx, dy, dz, d_yaw, d_pitch }
228
+ /cast/pose-loop Toggle periodic pose refresh (~27 Hz)
229
+ { active: true | false } (omit to toggle)
230
+ /cast/click Tap at normalised screen coordinates
231
+ { x: 0.5, y: 0.5, layer, hold_ms: 50 }
232
+ /cast/gaze Gaze-based interaction
233
+ { action: "enable" }
234
+ { action: "click", yaw, pitch, dwell_ms: 1200 }
235
+ /cast/mud Send raw MUD payload
236
+ { type: 0, payload_hex: "..." }
237
+ /cast/home Press the Home button (ADB keyevent)
238
+ /cast/reset-view Reset camera offset to headset origin, stop pose loop
239
+ `;
240
+ return reply.type("text/plain").send(help);
241
+ });
242
+ app.get("/cast/screenshot", async (_req, reply) => {
243
+ const session = castManager.getSession();
244
+ if (!session)
245
+ return reply.code(503).send({ error: "cast not active" });
246
+ const jpeg = session.getScreenshot();
247
+ if (jpeg) {
248
+ return reply.type("image/jpeg").send(jpeg);
249
+ }
250
+ return reply.code(503).send({ error: "no frame available" });
251
+ });
252
+ app.get("/cast/stream", async (_req, reply) => {
253
+ const session = castManager.getSession();
254
+ if (!session?.running) {
255
+ return reply.code(503).send({ error: "cast not active" });
256
+ }
257
+ reply.raw.writeHead(200, {
258
+ "Content-Type": "multipart/x-mixed-replace; boundary=frame",
259
+ "Cache-Control": "no-cache",
260
+ Connection: "close",
261
+ });
262
+ let cleaned = false;
263
+ const cleanup = () => {
264
+ if (cleaned)
265
+ return;
266
+ cleaned = true;
267
+ clearInterval(interval);
268
+ try {
269
+ reply.raw.end();
270
+ }
271
+ catch { /* ignore */ }
272
+ };
273
+ const interval = setInterval(() => {
274
+ const s = castManager.getSession();
275
+ if (!s?.running) {
276
+ cleanup();
277
+ return;
278
+ }
279
+ try {
280
+ const jpeg = s.getScreenshot();
281
+ if (jpeg) {
282
+ reply.raw.write(`--frame\r\nContent-Type: image/jpeg\r\nContent-Length: ${jpeg.length}\r\n\r\n`);
283
+ reply.raw.write(jpeg);
284
+ reply.raw.write("\r\n");
285
+ }
286
+ }
287
+ catch {
288
+ cleanup();
289
+ }
290
+ }, 200);
291
+ _req.raw.on("close", cleanup);
292
+ });
293
+ app.get("/cast/status", async () => {
294
+ return castManager.getStatus();
295
+ });
296
+ app.get("/cast/layers", async () => {
297
+ const session = castManager.getSession();
298
+ if (!session)
299
+ return { layers: {}, active_layer_id: 0 };
300
+ const layers = {};
301
+ for (const [id, info] of session.layers) {
302
+ layers[String(id)] = info;
303
+ }
304
+ return { layers, active_layer_id: session.layerId };
305
+ });
306
+ // --- Cast POST endpoints ---
307
+ app.post("/cast/rotate", async (req) => {
308
+ const session = castManager.getSession();
309
+ if (!session?.connected)
310
+ return { error: "cast not active" };
311
+ const { pitch = 0, yaw = 0 } = req.body ?? {};
312
+ session.sendRotation(pitch, yaw);
313
+ return { ok: true, pitch, yaw };
314
+ });
315
+ app.post("/cast/move", async (req) => {
316
+ const session = castManager.getSession();
317
+ if (!session?.connected)
318
+ return { error: "cast not active" };
319
+ const { forward = 0, strafe = 0, yaw = 0, pitch = 0 } = req.body ?? {};
320
+ session.sendRotation(pitch, yaw, forward, strafe);
321
+ return { ok: true };
322
+ });
323
+ app.get("/cast/resolutions", async () => {
324
+ return Object.fromEntries(Object.entries(RESOLUTIONS).map(([key, r]) => [key, `${r.width}x${r.height}`]));
325
+ });
326
+ app.post("/cast/config", async (req) => {
327
+ const session = castManager.getSession();
328
+ if (!session?.connected)
329
+ return { error: "cast not active" };
330
+ const { width, height } = resolveResolution(req.body?.resolution, req.body?.width ?? session.width, req.body?.height ?? session.height);
331
+ session.sendDisplayConfig(width, height);
332
+ castManager.broadcastToast(`Resolution: ${width}\u00d7${height}`);
333
+ castManager.broadcastStatus();
334
+ return { ok: true, width, height };
335
+ });
336
+ app.post("/cast/eye", async (req) => {
337
+ const session = castManager.getSession();
338
+ if (!session?.connected)
339
+ return { error: "cast not active" };
340
+ const mode = req.body?.mode ?? "left";
341
+ const eyeMap = {
342
+ left: EYE_LEFT,
343
+ right: EYE_RIGHT,
344
+ stereo: EYE_STEREO,
345
+ both: EYE_STEREO,
346
+ };
347
+ const eye = eyeMap[mode] ?? EYE_LEFT;
348
+ session.sendDisplayConfig(session.width, session.height, eye);
349
+ castManager.broadcastToast(`Eye mode: ${mode}`);
350
+ castManager.broadcastStatus();
351
+ return { ok: true, mode };
352
+ });
353
+ app.post("/cast/click", async (req) => {
354
+ const session = castManager.getSession();
355
+ if (!session?.connected)
356
+ return { error: "cast not active" };
357
+ const { x = 0.5, y = 0.5, layer, hold_ms = 50 } = req.body ?? {};
358
+ await session.sendClick(x, y, layer, hold_ms);
359
+ const layerInfo = session.layers.get(layer ?? session.layerId);
360
+ return {
361
+ ok: true,
362
+ x,
363
+ y,
364
+ layer: layer ?? session.layerId,
365
+ layer_name: layerInfo?.layer ?? "",
366
+ };
367
+ });
368
+ app.post("/cast/pose", async (req) => {
369
+ const session = castManager.getSession();
370
+ if (!session?.connected)
371
+ return { error: "cast not active" };
372
+ const data = req.body ?? {};
373
+ // Direct offset from headset (not world-space) — takes priority over deltas
374
+ if ("x" in data ||
375
+ "y" in data ||
376
+ "z" in data ||
377
+ "yaw" in data ||
378
+ "pitch" in data) {
379
+ session.setPoseOffset({
380
+ x: data.x,
381
+ y: data.y,
382
+ z: data.z,
383
+ yaw: data.yaw,
384
+ pitch: data.pitch,
385
+ });
386
+ }
387
+ else if (
388
+ // Incremental deltas — only when no offset fields present
389
+ "dx" in data ||
390
+ "dy" in data ||
391
+ "dz" in data ||
392
+ "d_yaw" in data ||
393
+ "d_pitch" in data) {
394
+ session.applyPoseDelta({
395
+ dForward: data.dz ?? 0,
396
+ dStrafe: data.dx ?? 0,
397
+ dUp: data.dy ?? 0,
398
+ dYaw: data.d_yaw ?? 0,
399
+ dPitch: data.d_pitch ?? 0,
400
+ });
401
+ }
402
+ castManager.broadcastStatus();
403
+ return { ok: true };
404
+ });
405
+ app.post("/cast/gaze", async (req) => {
406
+ const session = castManager.getSession();
407
+ if (!session?.connected)
408
+ return { error: "cast not active" };
409
+ const data = req.body ?? {};
410
+ const action = data.action ?? "enable";
411
+ if (action === "enable") {
412
+ session.ensureInputForwarding();
413
+ return { ok: true, action: "enable" };
414
+ }
415
+ if (action === "click") {
416
+ session.ensureInputForwarding();
417
+ const yaw = data.yaw ?? session.pose.yaw;
418
+ const pitch = data.pitch ?? session.pose.pitch;
419
+ const dwellMs = data.dwell_ms ?? 1200;
420
+ session.setPoseOffset({ yaw, pitch });
421
+ const steps = Math.floor(dwellMs / 16);
422
+ for (let i = 0; i < steps; i++) {
423
+ session.sendPose(session.pose);
424
+ await new Promise((r) => setTimeout(r, 16));
425
+ }
426
+ return {
427
+ ok: true,
428
+ action: "click",
429
+ yaw: Math.round(yaw * 10000) / 10000,
430
+ pitch: Math.round(pitch * 10000) / 10000,
431
+ dwell_ms: dwellMs,
432
+ };
433
+ }
434
+ return { error: `unknown action: ${action}` };
435
+ });
436
+ app.post("/cast/pose-loop", async (req) => {
437
+ const session = castManager.getSession();
438
+ if (!session?.connected)
439
+ return { error: "cast not active" };
440
+ const active = req.body?.active ?? !session.poseLoopActive;
441
+ if (active) {
442
+ session.startPoseLoop();
443
+ }
444
+ else {
445
+ session.stopPoseLoop();
446
+ }
447
+ castManager.broadcastStatus();
448
+ return { ok: true, pose_loop: session.poseLoopActive };
449
+ });
450
+ app.post("/cast/reset-view", async () => {
451
+ const session = castManager.getSession();
452
+ if (!session?.connected)
453
+ return { error: "cast not active" };
454
+ session.resetView();
455
+ castManager.broadcastToast("View reset");
456
+ castManager.broadcastStatus();
457
+ return { ok: true, mode: "normal" };
458
+ });
459
+ app.post("/cast/home", async () => {
460
+ try {
461
+ await execCommand("adb", adbArgs("shell", "input", "keyevent", "KEYCODE_HOME"));
462
+ castManager.broadcastToast("Home");
463
+ return { ok: true };
464
+ }
465
+ catch {
466
+ return { error: "failed to send home key" };
467
+ }
468
+ });
469
+ app.post("/cast/mud", async (req) => {
470
+ const session = castManager.getSession();
471
+ if (!session?.connected)
472
+ return { error: "cast not active" };
473
+ const typeId = req.body?.type ?? 0;
474
+ const payloadHex = req.body?.payload_hex ?? "";
475
+ const payload = payloadHex ? Buffer.from(payloadHex, "hex") : undefined;
476
+ session.sendMud(typeId, payload);
477
+ return { ok: true, type: typeId, payload_len: payload?.length ?? 0 };
478
+ });
479
+ await app.listen({ port, host });
480
+ return app;
481
+ }
482
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Stay-awake manager for the daemon process.
3
+ * Extracted from stay-awake.ts — manages test properties lifecycle.
4
+ */
5
+ import { type TestProperties } from "../utils/test-properties.js";
6
+ export declare class StayAwakeManager {
7
+ private enabled;
8
+ private pin;
9
+ /** Whether stay-awake is currently enabled */
10
+ get isEnabled(): boolean;
11
+ /** Enable test properties (guardian, dialogs, autosleep, proximity) */
12
+ enable(pin: string): Promise<void>;
13
+ /** Disable test properties (restore Quest to normal) */
14
+ disable(): Promise<void>;
15
+ /** Synchronous cleanup for signal handlers */
16
+ cleanupSync(): void;
17
+ /** Get current test property status */
18
+ status(): Promise<TestProperties>;
19
+ /** Format status for display */
20
+ formatStatus(props: TestProperties): string;
21
+ }
22
+ //# sourceMappingURL=stay-awake-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stay-awake-manager.d.ts","sourceRoot":"","sources":["../../src/daemon/stay-awake-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,6BAA6B,CAAC;AAKrC,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,GAAG,CAAqB;IAEhC,8CAA8C;IAC9C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,uEAAuE;IACjE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxC,wDAAwD;IAClD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAc9B,8CAA8C;IAC9C,WAAW,IAAI,IAAI;IAanB,uCAAuC;IACjC,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;IAIvC,gCAAgC;IAChC,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM;CAG5C"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Stay-awake manager for the daemon process.
3
+ * Extracted from stay-awake.ts — manages test properties lifecycle.
4
+ */
5
+ import { execFileSync } from "node:child_process";
6
+ import { buildSetPropertyArgs, setTestProperties, getTestProperties, formatTestProperties, } from "../utils/test-properties.js";
7
+ import { execCommand } from "../utils/exec.js";
8
+ import { verbose } from "../utils/verbose.js";
9
+ import { adbArgs, getAdbDevice } from "../utils/adb.js";
10
+ export class StayAwakeManager {
11
+ enabled = false;
12
+ pin;
13
+ /** Whether stay-awake is currently enabled */
14
+ get isEnabled() {
15
+ return this.enabled;
16
+ }
17
+ /** Enable test properties (guardian, dialogs, autosleep, proximity) */
18
+ async enable(pin) {
19
+ if (this.enabled) {
20
+ verbose("stay-awake already enabled");
21
+ return;
22
+ }
23
+ this.pin = pin;
24
+ await setTestProperties(pin, true);
25
+ this.enabled = true;
26
+ // Wake screen
27
+ try {
28
+ await execCommand("adb", adbArgs("shell", "input", "keyevent", "KEYCODE_WAKEUP"));
29
+ }
30
+ catch {
31
+ // Non-fatal
32
+ }
33
+ console.log("Stay-awake enabled (guardian, dialogs, autosleep disabled)");
34
+ }
35
+ /** Disable test properties (restore Quest to normal) */
36
+ async disable() {
37
+ if (!this.enabled || !this.pin) {
38
+ verbose("stay-awake not enabled, nothing to disable");
39
+ return;
40
+ }
41
+ try {
42
+ await setTestProperties(this.pin, false);
43
+ console.log("Stay-awake disabled (guardian, dialogs, autosleep restored)");
44
+ }
45
+ catch (error) {
46
+ console.error("Failed to disable stay-awake:", error.message);
47
+ }
48
+ this.enabled = false;
49
+ }
50
+ /** Synchronous cleanup for signal handlers */
51
+ cleanupSync() {
52
+ if (!this.enabled || !this.pin)
53
+ return;
54
+ try {
55
+ const args = buildSetPropertyArgs(this.pin, false);
56
+ const device = getAdbDevice();
57
+ const adb = device ? ["-s", device, ...args] : args;
58
+ execFileSync("adb", adb, { stdio: "ignore" });
59
+ }
60
+ catch {
61
+ // Best-effort
62
+ }
63
+ this.enabled = false;
64
+ }
65
+ /** Get current test property status */
66
+ async status() {
67
+ return getTestProperties();
68
+ }
69
+ /** Format status for display */
70
+ formatStatus(props) {
71
+ return formatTestProperties(props);
72
+ }
73
+ }
74
+ //# sourceMappingURL=stay-awake-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stay-awake-manager.js","sourceRoot":"","sources":["../../src/daemon/stay-awake-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,GAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,OAAO,gBAAgB;IACnB,OAAO,GAAG,KAAK,CAAC;IAChB,GAAG,CAAqB;IAEhC,8CAA8C;IAC9C,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,uEAAuE;IACvE,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,4BAA4B,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,MAAM,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,cAAc;QACd,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC;QACpF,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;IAC5E,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAC/B,OAAO,CAAC,4CAA4C,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;QAC7E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED,8CAA8C;IAC9C,WAAW;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAO;QACvC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACpD,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED,uCAAuC;IACvC,KAAK,CAAC,MAAM;QACV,OAAO,iBAAiB,EAAE,CAAC;IAC7B,CAAC;IAED,gCAAgC;IAChC,YAAY,CAAC,KAAqB;QAChC,OAAO,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;CACF"}