@myerscarpenter/quest-dev 1.2.0 → 1.3.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # quest-dev
2
2
 
3
- CLI tools for Meta Quest Browser development. Take screenshots and open URLs on your Quest device via ADB.
3
+ CLI tools for Meta Quest development stay awake, screenshots, URL opening, logcat, and battery via ADB.
4
4
 
5
5
  ## Installation
6
6
 
@@ -55,12 +55,76 @@ This command:
55
55
 
56
56
  Port forwarding is idempotent - safe to run multiple times without issues.
57
57
 
58
+ ### Stay Awake
59
+
60
+ Keep your Quest awake during development by disabling autosleep, guardian, and system dialogs using the Meta Scriptable Testing API.
61
+
62
+ ```bash
63
+ quest-dev stay-awake --pin 1234
64
+ ```
65
+
66
+ **Config file** — avoid passing `--pin` every time by creating `.quest-dev.json` in your project or `~/.config/quest-dev/config.json` globally:
67
+
68
+ ```json
69
+ {
70
+ "pin": "1234",
71
+ "idleTimeout": 300000,
72
+ "lowBattery": 10
73
+ }
74
+ ```
75
+
76
+ **Flags:**
77
+
78
+ - `--status` — show current Scriptable Testing properties without changing anything
79
+ - `--disable` — manually disable test mode (restore all properties)
80
+ - `--idle-timeout <ms>` — auto-exit after inactivity (default: 300000ms / 5min)
81
+ - `--low-battery <percent>` — auto-exit when battery drops below threshold (default: 10%)
82
+ - `--verbose` — log battery status every 60s instead of only on 5% boundary crossings
83
+
84
+ **Activity signaling** — reset the idle timer from another process:
85
+
86
+ ```bash
87
+ kill -USR1 $(cat ~/.quest-dev-stay-awake.pid)
88
+ ```
89
+
90
+ **Watchdog** — a child process monitors the parent PID and automatically restores Quest settings if the parent dies (terminal close, `kill`, etc.), preventing a drained battery.
91
+
92
+ Requires Quest OS v44+ and your Meta Store PIN.
93
+
94
+ ### Logcat
95
+
96
+ Capture Android logcat output for Quest debugging. Quest's ring buffer fills fast under VR load, so always start capture before testing.
97
+
98
+ ```bash
99
+ quest-dev logcat start # start capturing (clears ring buffer first)
100
+ quest-dev logcat start --filter "Unity:V" # capture with filter
101
+ quest-dev logcat status # check if capturing
102
+ quest-dev logcat tail # tail the current log file
103
+ quest-dev logcat stop # stop capturing, show file info
104
+ ```
105
+
106
+ Log files are saved to `./logs/logcat/` with a `latest.txt` symlink.
107
+
108
+ ### Battery
109
+
110
+ Show Quest battery level and charging status:
111
+
112
+ ```bash
113
+ quest-dev battery
114
+ ```
115
+
58
116
  ## How It Works
59
117
 
60
118
  - **screenshot**: Triggers `com.oculus.metacam/.capture.CaptureService` via ADB, waits for the JPEG to be fully written (by checking for the EOI marker), pulls the file, then deletes it from the Quest
61
119
 
62
120
  - **open**: Uses ADB for port forwarding and browser launching. If `cdp-cli` is installed, it uses CDP to intelligently reuse existing tabs instead of opening new ones.
63
121
 
122
+ - **stay-awake**: Uses the Meta Scriptable Testing API (`content://com.oculus.rc`) to disable autosleep, guardian, and dialogs. A watchdog child process ensures cleanup on exit.
123
+
124
+ - **logcat**: Spawns a background `adb logcat` process writing to timestamped files. Clears the ring buffer on start to avoid stale data.
125
+
126
+ - **battery**: Reads battery level and charging state via `adb shell dumpsys battery`.
127
+
64
128
  ## Development
65
129
 
66
130
  ```bash
@@ -2,7 +2,7 @@
2
2
  * Quest battery command
3
3
  * Shows battery percentage and charging status
4
4
  */
5
- import { checkADBPath, getBatteryStatus } from '../utils/adb.js';
5
+ import { checkADBPath, getBatteryInfo, formatBatteryInfo } from '../utils/adb.js';
6
6
  /**
7
7
  * Main battery command handler
8
8
  */
@@ -25,7 +25,7 @@ export async function batteryCommand() {
25
25
  process.exit(1);
26
26
  }
27
27
  // Get and display battery status
28
- const status = await getBatteryStatus();
29
- console.log(status);
28
+ const info = await getBatteryInfo();
29
+ console.log(formatBatteryInfo(info));
30
30
  }
31
31
  //# sourceMappingURL=battery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"battery.js","sourceRoot":"","sources":["../../src/commands/battery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAmB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAElF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,+BAA+B;IAC/B,YAAY,EAAE,CAAC;IAEf,uCAAuC;IACvC,IAAI,CAAC;QACH,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAEvF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,iCAAiC;IACjC,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}
1
+ {"version":3,"file":"battery.js","sourceRoot":"","sources":["../../src/commands/battery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAElF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,+BAA+B;IAC/B,YAAY,EAAE,CAAC;IAEf,uCAAuC;IACvC,IAAI,CAAC;QACH,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAEvF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,iCAAiC;IACjC,MAAM,IAAI,GAAG,MAAM,cAAc,EAAE,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"logcat.d.ts","sourceRoot":"","sources":["../../src/commands/logcat.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8GH;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEjE;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA+BjD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAgCnD;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBjD"}
1
+ {"version":3,"file":"logcat.d.ts","sourceRoot":"","sources":["../../src/commands/logcat.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8GH;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEjE;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA+BjD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAkCnD;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBjD"}
@@ -9,7 +9,7 @@ import { join } from 'path';
9
9
  import { readFileSync, writeFileSync, unlinkSync, existsSync, mkdirSync, symlinkSync, statSync, readlinkSync, openSync } from 'fs';
10
10
  import { spawn } from 'child_process';
11
11
  import { checkADBPath, checkADBDevices } from '../utils/adb.js';
12
- import { execCommand, execCommandFull } from '../utils/exec.js';
12
+ import { execCommand } from '../utils/exec.js';
13
13
  const LOG_DIR = process.env.LOG_DIR || 'logs/logcat';
14
14
  const PID_FILE = join(LOG_DIR, '.logcat_pid');
15
15
  const LOGFILE_LINK = join(LOG_DIR, 'latest.txt');
@@ -226,11 +226,13 @@ export async function statusCommand() {
226
226
  console.log('');
227
227
  console.log('Recent logs:');
228
228
  try {
229
- const result = await execCommandFull('ls', ['-lht', join(LOG_DIR, '*.txt')]);
230
- if (result.code === 0) {
231
- const lines = result.stdout.trim().split('\n').slice(0, 5);
232
- lines.forEach(line => console.log(' ' + line));
233
- }
229
+ const { readdirSync } = await import('fs');
230
+ const files = readdirSync(LOG_DIR)
231
+ .filter(f => f.endsWith('.txt'))
232
+ .map(f => ({ name: f, mtime: statSync(join(LOG_DIR, f)).mtimeMs }))
233
+ .sort((a, b) => b.mtime - a.mtime)
234
+ .slice(0, 5);
235
+ files.forEach(f => console.log(' ' + f.name));
234
236
  }
235
237
  catch {
236
238
  // Ignore
@@ -1 +1 @@
1
- {"version":3,"file":"logcat.js","sourceRoot":"","sources":["../../src/commands/logcat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logcat.js","sourceRoot":"","sources":["../../src/commands/logcat.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,41 @@
1
1
  /**
2
2
  * Quest stay-awake command
3
- * Keeps Quest screen awake by setting screen timeout to 24 hours
4
- * Restores original timeout on exit (Ctrl-C)
3
+ * Uses Meta Scriptable Testing API (content://com.oculus.rc) to disable
4
+ * autosleep, guardian, and system dialogs for automated testing.
5
+ *
6
+ * Cleanup is critical: with autosleep disabled, the headset drains battery
7
+ * quickly. A watchdog child process ensures cleanup happens even if the
8
+ * parent is killed (TaskStop, terminal close, claude code exit).
5
9
  */
10
+ export interface TestProperties {
11
+ disable_guardian: boolean;
12
+ disable_dialogs: boolean;
13
+ disable_autosleep: boolean;
14
+ set_proximity_close: boolean;
15
+ }
16
+ /**
17
+ * Build ADB args for SET_PROPERTY call
18
+ */
19
+ export declare function buildSetPropertyArgs(pin: string, enabled: boolean): string[];
20
+ /**
21
+ * Parse GET_PROPERTY Bundle output into structured data
22
+ * Input: "Bundle[{disable_guardian=true, set_proximity_close=true, disable_dialogs=true, disable_autosleep=true}]"
23
+ */
24
+ export declare function parseTestProperties(output: string): TestProperties;
25
+ /**
26
+ * Show current test properties status
27
+ */
28
+ export declare function stayAwakeStatus(): Promise<void>;
29
+ /**
30
+ * Manually disable test mode (restore all properties)
31
+ */
32
+ export declare function stayAwakeDisable(cliPin?: string): Promise<void>;
6
33
  /**
7
34
  * Child watchdog process - polls for parent death and cleans up
8
35
  */
9
- export declare function stayAwakeWatchdog(parentPid: number, originalTimeout: number): Promise<void>;
36
+ export declare function stayAwakeWatchdog(parentPid: number, pin: string): Promise<void>;
10
37
  /**
11
38
  * Main stay-awake command handler
12
39
  */
13
- export declare function stayAwakeCommand(idleTimeout?: number): Promise<void>;
40
+ export declare function stayAwakeCommand(cliPin?: string, cliIdleTimeout?: number, cliLowBattery?: number, verbose?: boolean): Promise<void>;
14
41
  //# sourceMappingURL=stay-awake.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stay-awake.d.ts","sourceRoot":"","sources":["../../src/commands/stay-awake.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA6CH;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCjG;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,GAAE,MAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmKlF"}
1
+ {"version":3,"file":"stay-awake.d.ts","sourceRoot":"","sources":["../../src/commands/stay-awake.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAW5E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAoBlE;AA0CD;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAKrD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBrF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,CAAC,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,EACvB,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,GAAE,OAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAiLf"}
@@ -1,38 +1,85 @@
1
1
  /**
2
2
  * Quest stay-awake command
3
- * Keeps Quest screen awake by setting screen timeout to 24 hours
4
- * Restores original timeout on exit (Ctrl-C)
3
+ * Uses Meta Scriptable Testing API (content://com.oculus.rc) to disable
4
+ * autosleep, guardian, and system dialogs for automated testing.
5
+ *
6
+ * Cleanup is critical: with autosleep disabled, the headset drains battery
7
+ * quickly. A watchdog child process ensures cleanup happens even if the
8
+ * parent is killed (TaskStop, terminal close, claude code exit).
5
9
  */
6
- import { checkADBPath } from '../utils/adb.js';
7
- import { execCommand } from '../utils/exec.js';
10
+ import { checkADBPath, getBatteryInfo, formatBatteryInfo } from '../utils/adb.js';
11
+ import { loadPin, loadConfig } from '../utils/config.js';
12
+ import { execCommand, execCommandFull } from '../utils/exec.js';
8
13
  import { execSync, spawn } from 'child_process';
9
14
  import * as os from 'os';
10
15
  import * as fs from 'fs';
11
16
  /**
12
- * Get current screen timeout setting
17
+ * Build ADB args for SET_PROPERTY call
13
18
  */
14
- async function getScreenTimeout() {
15
- const output = await execCommand('adb', ['shell', 'settings', 'get', 'system', 'screen_off_timeout']);
16
- return parseInt(output.trim(), 10);
19
+ export function buildSetPropertyArgs(pin, enabled) {
20
+ return [
21
+ 'shell', 'content', 'call',
22
+ '--uri', 'content://com.oculus.rc',
23
+ '--method', 'SET_PROPERTY',
24
+ '--extra', `disable_guardian:b:${enabled}`,
25
+ '--extra', `disable_dialogs:b:${enabled}`,
26
+ '--extra', `disable_autosleep:b:${enabled}`,
27
+ '--extra', `set_proximity_close:b:${enabled}`,
28
+ '--extra', `PIN:s:${pin}`,
29
+ ];
17
30
  }
18
31
  /**
19
- * Set screen timeout (in milliseconds)
32
+ * Parse GET_PROPERTY Bundle output into structured data
33
+ * Input: "Bundle[{disable_guardian=true, set_proximity_close=true, disable_dialogs=true, disable_autosleep=true}]"
20
34
  */
21
- async function setScreenTimeout(timeout) {
22
- await execCommand('adb', ['shell', 'settings', 'put', 'system', 'screen_off_timeout', timeout.toString()]);
35
+ export function parseTestProperties(output) {
36
+ const defaults = {
37
+ disable_guardian: false,
38
+ disable_dialogs: false,
39
+ disable_autosleep: false,
40
+ set_proximity_close: false,
41
+ };
42
+ const match = output.match(/Bundle\[\{(.+)\}\]/);
43
+ if (!match)
44
+ return defaults;
45
+ const pairs = match[1].split(',').map(s => s.trim());
46
+ for (const pair of pairs) {
47
+ const [key, value] = pair.split('=');
48
+ if (key && value && key in defaults) {
49
+ defaults[key] = value === 'true';
50
+ }
51
+ }
52
+ return defaults;
53
+ }
54
+ /**
55
+ * Call SET_PROPERTY to enable or disable test mode
56
+ */
57
+ async function setTestProperties(pin, enabled) {
58
+ const args = buildSetPropertyArgs(pin, enabled);
59
+ await execCommand('adb', args);
23
60
  }
24
61
  /**
25
- * Disable Quest proximity sensor (keeps screen on even when not worn)
62
+ * Call GET_PROPERTY and return parsed test properties
26
63
  */
27
- async function disableProximitySensor() {
28
- await execCommand('adb', ['shell', 'am', 'broadcast', '-a', 'com.oculus.vrpowermanager.prox_close']);
64
+ async function getTestProperties() {
65
+ const result = await execCommandFull('adb', [
66
+ 'shell', 'content', 'call',
67
+ '--uri', 'content://com.oculus.rc',
68
+ '--method', 'GET_PROPERTY',
69
+ ]);
70
+ return parseTestProperties(result.stdout);
29
71
  }
30
72
  /**
31
- * Enable Quest proximity sensor (re-enable normal behavior)
32
- * Note: automation_disable actually RE-ENABLES normal proximity sensor automation
73
+ * Format test properties for display
33
74
  */
34
- async function enableProximitySensor() {
35
- await execCommand('adb', ['shell', 'am', 'broadcast', '-a', 'com.oculus.vrpowermanager.automation_disable']);
75
+ function formatTestProperties(props) {
76
+ const lines = [
77
+ ` Guardian disabled: ${props.disable_guardian}`,
78
+ ` Dialogs disabled: ${props.disable_dialogs}`,
79
+ ` Autosleep disabled: ${props.disable_autosleep}`,
80
+ ` Proximity close: ${props.set_proximity_close}`,
81
+ ];
82
+ return lines.join('\n');
36
83
  }
37
84
  /**
38
85
  * Wake the Quest screen
@@ -40,33 +87,45 @@ async function enableProximitySensor() {
40
87
  async function wakeScreen() {
41
88
  await execCommand('adb', ['shell', 'input', 'keyevent', 'KEYCODE_WAKEUP']);
42
89
  }
90
+ /**
91
+ * Show current test properties status
92
+ */
93
+ export async function stayAwakeStatus() {
94
+ checkADBPath();
95
+ const props = await getTestProperties();
96
+ console.log('Scriptable Testing properties:');
97
+ console.log(formatTestProperties(props));
98
+ }
99
+ /**
100
+ * Manually disable test mode (restore all properties)
101
+ */
102
+ export async function stayAwakeDisable(cliPin) {
103
+ checkADBPath();
104
+ const pin = loadPin(cliPin);
105
+ await setTestProperties(pin, false);
106
+ console.log('Test mode disabled — guardian, dialogs, and autosleep restored');
107
+ }
43
108
  /**
44
109
  * Child watchdog process - polls for parent death and cleans up
45
110
  */
46
- export async function stayAwakeWatchdog(parentPid, originalTimeout) {
47
- const pollInterval = 5000; // Check every 5 seconds
111
+ export async function stayAwakeWatchdog(parentPid, pin) {
112
+ const pollInterval = 5000;
48
113
  const checkParent = setInterval(() => {
49
114
  try {
50
- // Check if parent process still exists
51
115
  process.kill(parentPid, 0);
52
- // Parent still alive, continue polling
53
116
  }
54
117
  catch {
55
- // Parent is dead - perform cleanup
56
118
  console.log('Parent process died, restoring Quest settings...');
57
119
  clearInterval(checkParent);
58
- // Restore settings synchronously
59
120
  try {
60
- execSync(`adb shell settings put system screen_off_timeout ${originalTimeout}`, { stdio: 'ignore' });
61
- execSync(`adb shell am broadcast -a com.oculus.vrpowermanager.automation_disable`, { stdio: 'ignore' });
62
- // Cleanup PID file
121
+ const args = buildSetPropertyArgs(pin, false);
122
+ execSync(`adb ${args.join(' ')}`, { stdio: 'ignore' });
63
123
  const pidFile = `${os.homedir()}/.quest-dev-stay-awake.pid`;
64
124
  try {
65
125
  fs.unlinkSync(pidFile);
66
126
  }
67
127
  catch { }
68
- console.log(`Screen timeout restored to ${originalTimeout}ms (${Math.round(originalTimeout / 1000)}s)`);
69
- console.log('Proximity sensor re-enabled');
128
+ console.log('Test mode disabled guardian, dialogs, and autosleep restored');
70
129
  }
71
130
  catch (err) {
72
131
  console.error('Failed to restore settings:', err.message);
@@ -78,10 +137,9 @@ export async function stayAwakeWatchdog(parentPid, originalTimeout) {
78
137
  /**
79
138
  * Main stay-awake command handler
80
139
  */
81
- export async function stayAwakeCommand(idleTimeout = 300000) {
82
- // Check prerequisites
140
+ export async function stayAwakeCommand(cliPin, cliIdleTimeout, cliLowBattery, verbose = false) {
83
141
  checkADBPath();
84
- // Check devices without verbose output
142
+ // Check devices
85
143
  try {
86
144
  const output = await execCommand('adb', ['devices']);
87
145
  const lines = output.trim().split('\n').slice(1);
@@ -95,77 +153,82 @@ export async function stayAwakeCommand(idleTimeout = 300000) {
95
153
  console.error('Error: Failed to list ADB devices');
96
154
  process.exit(1);
97
155
  }
156
+ const config = loadConfig();
157
+ const pin = loadPin(cliPin);
158
+ const idleTimeout = cliIdleTimeout ?? config.idleTimeout ?? 300000;
159
+ const lowBattery = cliLowBattery ?? config.lowBattery ?? 10;
98
160
  // PID file management
99
161
  const pidFilePath = `${os.homedir()}/.quest-dev-stay-awake.pid`;
100
- // Check for existing process
101
162
  if (fs.existsSync(pidFilePath)) {
102
163
  const existingPid = parseInt(fs.readFileSync(pidFilePath, 'utf-8'));
103
164
  try {
104
- process.kill(existingPid, 0); // Test if process exists
165
+ process.kill(existingPid, 0);
105
166
  console.error(`Error: stay-awake is already running (PID: ${existingPid})`);
106
167
  process.exit(1);
107
168
  }
108
169
  catch {
109
- // Process dead, cleanup stale PID file
110
170
  fs.unlinkSync(pidFilePath);
111
171
  }
112
172
  }
113
- // Get original timeout
114
- let originalTimeout;
115
- try {
116
- originalTimeout = await getScreenTimeout();
117
- console.log(`Original screen timeout: ${originalTimeout}ms (${Math.round(originalTimeout / 1000)}s)`);
118
- }
119
- catch (error) {
120
- console.error('Failed to get current screen timeout');
121
- process.exit(1);
122
- }
173
+ // Show current state
174
+ const beforeProps = await getTestProperties();
175
+ console.log('Current test properties:');
176
+ console.log(formatTestProperties(beforeProps));
123
177
  // Write PID file
124
178
  try {
125
179
  fs.writeFileSync(pidFilePath, process.pid.toString());
126
180
  }
127
181
  catch (error) {
128
- console.warn('Failed to write PID file, hook will not work');
182
+ console.warn('Failed to write PID file');
129
183
  }
130
- // Spawn child watchdog process
184
+ // Spawn watchdog child process
131
185
  let childProcess = null;
132
186
  try {
133
187
  childProcess = spawn(process.execPath, [
134
- process.argv[1], // quest-dev script path
188
+ process.argv[1],
135
189
  'stay-awake-watchdog',
136
190
  '--parent-pid', process.pid.toString(),
137
- '--original-timeout', originalTimeout.toString()
191
+ '--pin', pin,
138
192
  ], {
139
193
  detached: true,
140
- stdio: 'ignore'
194
+ stdio: 'ignore',
141
195
  });
142
- childProcess.unref(); // Allow parent to exit without waiting for child
196
+ childProcess.unref();
143
197
  }
144
198
  catch (error) {
145
199
  console.warn('Failed to spawn watchdog child process');
146
200
  }
147
- // Wake screen and disable proximity sensor
201
+ // Enable test mode
202
+ try {
203
+ await setTestProperties(pin, true);
204
+ console.log('Test mode enabled — guardian, dialogs, and autosleep disabled');
205
+ }
206
+ catch (error) {
207
+ console.error('Failed to enable test mode:', error.message);
208
+ console.error('Requires Quest OS v44+ and a valid Meta Store PIN.');
209
+ process.exit(1);
210
+ }
211
+ // Wake screen
148
212
  try {
149
213
  await wakeScreen();
150
214
  console.log('Quest screen woken up');
151
- await disableProximitySensor();
152
- console.log('Proximity sensor disabled');
153
215
  }
154
216
  catch (error) {
155
- console.error('Failed to wake screen or disable proximity sensor:', error.message);
217
+ console.error('Failed to wake screen:', error.message);
156
218
  }
157
- // Set timeout to 24 hours (86400000ms)
158
- const longTimeout = 86400000;
219
+ // Battery monitoring state
220
+ let lastReportedBucket = -1; // Track 5% boundary crossings
221
+ // Initial battery check
159
222
  try {
160
- await setScreenTimeout(longTimeout);
161
- console.log(`Screen timeout set to 24 hours`);
162
- console.log(`Quest will stay awake (idle timeout: ${Math.round(idleTimeout / 1000)}s). Press Ctrl-C to restore original settings.`);
223
+ const battery = await getBatteryInfo();
224
+ console.log(`Battery: ${formatBatteryInfo(battery)}`);
225
+ lastReportedBucket = Math.floor(battery.level / 5) * 5;
163
226
  }
164
227
  catch (error) {
165
- console.error('Failed to set screen timeout');
166
- process.exit(1);
228
+ console.warn('Failed to read battery status');
167
229
  }
168
- // Idle timer mechanism
230
+ console.log(`Quest will stay awake (idle timeout: ${Math.round(idleTimeout / 1000)}s, low battery exit: ${lowBattery}%). Press Ctrl-C to restore.`);
231
+ // Idle timer
169
232
  let idleTimerHandle = null;
170
233
  let cleanupInProgress = false;
171
234
  const resetIdleTimer = () => {
@@ -176,58 +239,72 @@ export async function stayAwakeCommand(idleTimeout = 300000) {
176
239
  cleanup();
177
240
  }, idleTimeout);
178
241
  };
179
- // Set up cleanup on exit (must be synchronous for signal handlers)
242
+ // Cleanup handler
180
243
  const cleanup = () => {
181
244
  if (cleanupInProgress)
182
- return; // Guard against double-cleanup
245
+ return;
183
246
  cleanupInProgress = true;
184
- // Clear idle timer
185
247
  if (idleTimerHandle)
186
248
  clearTimeout(idleTimerHandle);
187
- // Kill child watchdog
249
+ if (batteryInterval)
250
+ clearInterval(batteryInterval);
188
251
  if (childProcess) {
189
252
  try {
190
253
  childProcess.kill();
191
254
  }
192
255
  catch { }
193
256
  }
194
- console.log('\nRestoring original settings...');
257
+ console.log('\nRestoring settings...');
195
258
  try {
196
- // Remove PID file
197
259
  try {
198
260
  fs.unlinkSync(pidFilePath);
199
261
  }
200
262
  catch { }
201
- // Restore Quest settings
202
- execSync(`adb shell settings put system screen_off_timeout ${originalTimeout}`, { stdio: 'ignore' });
203
- execSync(`adb shell am broadcast -a com.oculus.vrpowermanager.automation_disable`, { stdio: 'ignore' });
204
- console.log(`Screen timeout restored to ${originalTimeout}ms (${Math.round(originalTimeout / 1000)}s)`);
205
- console.log(`Proximity sensor re-enabled`);
263
+ const args = buildSetPropertyArgs(pin, false);
264
+ execSync(`adb ${args.join(' ')}`, { stdio: 'ignore' });
265
+ console.log('Test mode disabled guardian, dialogs, and autosleep restored');
206
266
  }
207
267
  catch (error) {
208
268
  console.error('Failed to restore settings:', error.message);
209
269
  }
210
270
  process.exit(0);
211
271
  };
212
- // Handle Ctrl-C and termination
272
+ // Signal handlers
213
273
  process.on('SIGINT', cleanup);
214
274
  process.on('SIGTERM', cleanup);
215
275
  process.on('SIGHUP', cleanup);
216
- // Handle SIGUSR1 for activity reset
276
+ // Activity reset via SIGUSR1
217
277
  process.on('SIGUSR1', () => {
218
- console.log('Activity detected, resetting idle timer');
278
+ const now = new Date().toLocaleTimeString();
279
+ console.log(`[${now}] Activity detected, resetting idle timer`);
219
280
  resetIdleTimer();
220
281
  });
221
282
  // Start idle timer
222
283
  resetIdleTimer();
223
- // Keep process running with an interval that does nothing
284
+ // Battery monitoring loop (every 60s)
285
+ const batteryInterval = setInterval(async () => {
286
+ try {
287
+ const battery = await getBatteryInfo();
288
+ const currentBucket = Math.floor(battery.level / 5) * 5;
289
+ if (verbose) {
290
+ console.log(`Battery: ${formatBatteryInfo(battery)}`);
291
+ }
292
+ else if (currentBucket !== lastReportedBucket) {
293
+ console.log(`Battery: ${formatBatteryInfo(battery)}`);
294
+ }
295
+ lastReportedBucket = currentBucket;
296
+ if (battery.level <= lowBattery && battery.state === 'not charging') {
297
+ console.log(`\nBattery critically low (${battery.level}%), exiting to preserve battery...`);
298
+ cleanup();
299
+ }
300
+ }
301
+ catch {
302
+ // Ignore battery check failures (device might be briefly unavailable)
303
+ }
304
+ }, 60000);
305
+ // Keep process alive
224
306
  console.log('Keeping Quest awake...');
225
- setInterval(() => {
226
- // Do nothing, just keep process alive
227
- }, 60000); // Check every minute
228
- // Prevent process from exiting
229
307
  await new Promise((resolve) => {
230
- // This will only resolve when cleanup is called
231
308
  process.on('exit', () => resolve());
232
309
  });
233
310
  }