@myerscarpenter/quest-dev 1.3.0 → 1.4.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/build/index.js CHANGED
@@ -13,6 +13,7 @@ import { openCommand } from './commands/open.js';
13
13
  import { startCommand, stopCommand, statusCommand, tailCommand } from './commands/logcat.js';
14
14
  import { batteryCommand } from './commands/battery.js';
15
15
  import { stayAwakeCommand, stayAwakeWatchdog, stayAwakeStatus, stayAwakeDisable } from './commands/stay-awake.js';
16
+ import { saveConfig, loadConfig } from './utils/config.js';
16
17
  // Read version from package.json
17
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
19
  const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
@@ -22,16 +23,12 @@ const cli = yargs(hideBin(process.argv))
22
23
  .scriptName('quest-dev')
23
24
  .version(version)
24
25
  .usage('Usage: $0 <command> [options]')
25
- .demandCommand(1, 'You must provide a command')
26
+ .demandCommand(1, '')
26
27
  .strict()
27
28
  .fail((msg, err, yargs) => {
28
- if (msg) {
29
- console.error(`Error: ${msg}\n`);
30
- }
31
- if (err) {
29
+ yargs.showHelp();
30
+ if (err)
32
31
  console.error(err.message);
33
- }
34
- console.error('Run "quest-dev --help" for usage information.');
35
32
  process.exit(1);
36
33
  })
37
34
  .help()
@@ -117,16 +114,16 @@ cli.command('battery', 'Show Quest battery percentage and charging status', () =
117
114
  cli.command('stay-awake', 'Keep Quest awake (disables autosleep, guardian, dialogs)', (yargs) => {
118
115
  return yargs
119
116
  .option('pin', {
120
- describe: 'Meta Store PIN (or set in .quest-dev.json / ~/.config/quest-dev/config.json)',
117
+ describe: 'Meta Store PIN (or save with: quest-dev config --pin)',
121
118
  type: 'string',
122
119
  })
123
120
  .option('idle-timeout', {
124
- describe: 'Idle timeout in milliseconds (default: 300000 = 5 minutes, or set idleTimeout in config)',
121
+ describe: 'Idle timeout in milliseconds (default: 300000 = 5 minutes, or save with: quest-dev config)',
125
122
  type: 'number',
126
123
  alias: 'i',
127
124
  })
128
125
  .option('low-battery', {
129
- describe: 'Exit when battery drops to this percentage (default: 10, or set lowBattery in config)',
126
+ describe: 'Exit when battery drops to this percentage (default: 10, or save with: quest-dev config)',
130
127
  type: 'number',
131
128
  })
132
129
  .option('disable', {
@@ -156,6 +153,52 @@ cli.command('stay-awake', 'Keep Quest awake (disables autosleep, guardian, dialo
156
153
  await stayAwakeCommand(argv.pin, argv.idleTimeout, argv.lowBattery, argv.verbose);
157
154
  }
158
155
  });
156
+ // Config command
157
+ cli.command('config', 'Save default settings for quest-dev commands', (yargs) => {
158
+ return yargs
159
+ .option('pin', {
160
+ describe: 'Meta Store PIN',
161
+ type: 'string',
162
+ })
163
+ .option('idle-timeout', {
164
+ describe: 'Idle timeout in milliseconds for stay-awake',
165
+ type: 'number',
166
+ })
167
+ .option('low-battery', {
168
+ describe: 'Exit stay-awake when battery drops to this percentage',
169
+ type: 'number',
170
+ })
171
+ .option('show', {
172
+ describe: 'Show current config and exit',
173
+ type: 'boolean',
174
+ default: false,
175
+ });
176
+ }, (argv) => {
177
+ if (argv.show) {
178
+ const config = loadConfig();
179
+ if (Object.keys(config).length === 0) {
180
+ console.log('No config found.');
181
+ }
182
+ else {
183
+ console.log(JSON.stringify(config, null, 2));
184
+ }
185
+ return;
186
+ }
187
+ const values = {};
188
+ if (argv.pin !== undefined)
189
+ values.pin = argv.pin;
190
+ if (argv.idleTimeout !== undefined)
191
+ values.idleTimeout = argv.idleTimeout;
192
+ if (argv.lowBattery !== undefined)
193
+ values.lowBattery = argv.lowBattery;
194
+ if (Object.keys(values).length === 0) {
195
+ console.error('No config values provided. Use --pin, --idle-timeout, or --low-battery.');
196
+ process.exit(1);
197
+ }
198
+ saveConfig(values);
199
+ console.log('Config saved:');
200
+ console.log(JSON.stringify(values, null, 2));
201
+ });
159
202
  // Stay-awake watchdog (internal subcommand, spawned by stay-awake parent)
160
203
  cli.command('stay-awake-watchdog', false, // Hide from help
161
204
  (yargs) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,11 @@ export interface QuestDevConfig {
12
12
  * First file found wins for each field.
13
13
  */
14
14
  export declare function loadConfig(): QuestDevConfig;
15
+ /**
16
+ * Save config values to ~/.config/quest-dev/config.json
17
+ * Merges with existing config (doesn't overwrite unrelated fields).
18
+ */
19
+ export declare function saveConfig(values: QuestDevConfig): string;
15
20
  /**
16
21
  * Resolve PIN from CLI flag, then config files
17
22
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAgBD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,cAAc,CAY3C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAe/C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAgBD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,cAAc,CAY3C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAiBzD;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAc/C"}
@@ -2,8 +2,8 @@
2
2
  * Config file loading for quest-dev
3
3
  * Resolves settings from CLI flags → .quest-dev.json → ~/.config/quest-dev/config.json
4
4
  */
5
- import { readFileSync } from 'fs';
6
- import { join } from 'path';
5
+ import { readFileSync, writeFileSync, mkdirSync } from 'fs';
6
+ import { join, dirname } from 'path';
7
7
  import { homedir } from 'os';
8
8
  const CONFIG_LOCATIONS = [
9
9
  join(process.cwd(), '.quest-dev.json'),
@@ -37,6 +37,30 @@ export function loadConfig() {
37
37
  }
38
38
  return merged;
39
39
  }
40
+ /**
41
+ * Save config values to ~/.config/quest-dev/config.json
42
+ * Merges with existing config (doesn't overwrite unrelated fields).
43
+ */
44
+ export function saveConfig(values) {
45
+ const configPath = join(homedir(), '.config', 'quest-dev', 'config.json');
46
+ let existing = {};
47
+ try {
48
+ existing = JSON.parse(readFileSync(configPath, 'utf-8'));
49
+ }
50
+ catch {
51
+ // No existing config, start fresh
52
+ }
53
+ const merged = { ...existing };
54
+ if (values.pin !== undefined)
55
+ merged.pin = values.pin;
56
+ if (values.idleTimeout !== undefined)
57
+ merged.idleTimeout = values.idleTimeout;
58
+ if (values.lowBattery !== undefined)
59
+ merged.lowBattery = values.lowBattery;
60
+ mkdirSync(dirname(configPath), { recursive: true });
61
+ writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\n');
62
+ return configPath;
63
+ }
40
64
  /**
41
65
  * Resolve PIN from CLI flag, then config files
42
66
  */
@@ -50,8 +74,7 @@ export function loadPin(cliPin) {
50
74
  console.error('');
51
75
  console.error('Provide a PIN via one of:');
52
76
  console.error(' --pin <pin> CLI flag');
53
- console.error(' .quest-dev.json { "pin": "1234" }');
54
- console.error(' ~/.config/quest-dev/config.json { "pin": "1234" }');
77
+ console.error(' quest-dev config --pin <pin> Save as default');
55
78
  console.error('');
56
79
  console.error('The PIN is your Meta Store PIN for the logged-in account.');
57
80
  process.exit(1);
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAQ7B,MAAM,gBAAgB,GAAG;IACvB,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,iBAAiB,CAAC;IACtC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC;CACvD,CAAC;AAEF,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG;YAAE,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACpE,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS;YAAE,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QAClH,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;YAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAChH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,MAAe;IACrC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,MAAM,CAAC,GAAG;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC;IAElC,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACrC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC3C,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAClE,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC3E,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC3E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ # Hardware Tests
2
+
3
+ Tests that require a physical Quest device connected via ADB.
4
+
5
+ ## stay-awake command
6
+
7
+ ### Prerequisites
8
+
9
+ - Quest 3 connected via USB, ADB authorized
10
+ - Quest OS v44+
11
+ - Meta Store PIN known
12
+ - `.quest-dev.json` in project root: `{ "pin": "<pin>", "idleTimeout": 60000, "lowBattery": 15 }`
13
+
14
+ ### Test 1: --status flag (read-only)
15
+
16
+ ```bash
17
+ node build/index.js stay-awake --status
18
+ ```
19
+
20
+ Expected: Shows all four properties (disable_guardian, disable_dialogs, disable_autosleep, set_proximity_close) as false.
21
+
22
+ ### Test 2: --status works without config file
23
+
24
+ ```bash
25
+ node build/index.js stay-awake --status
26
+ ```
27
+
28
+ Expected: No PIN needed for status — works without `.quest-dev.json`.
29
+
30
+ ### Test 3: Enable test mode — short run
31
+
32
+ ```bash
33
+ node build/index.js stay-awake --idle-timeout 30000
34
+ ```
35
+
36
+ Expected:
37
+ - Shows current properties (all false)
38
+ - Enables test mode (prints confirmation)
39
+ - Wakes screen
40
+ - Shows battery level
41
+ - Prints idle timeout and low battery threshold
42
+
43
+ Verify on device:
44
+ ```bash
45
+ adb shell content call --uri content://com.oculus.rc --method GET_PROPERTY
46
+ ```
47
+ Should show all true.
48
+
49
+ Then Ctrl-C. Should print "Restoring settings..." and "Test mode disabled". Verify properties restored to false.
50
+
51
+ ### Test 4: --disable manual restore
52
+
53
+ Enable manually first:
54
+ ```bash
55
+ adb shell content call --uri content://com.oculus.rc --method SET_PROPERTY \
56
+ --extra 'disable_guardian:b:true' --extra 'disable_dialogs:b:true' \
57
+ --extra 'disable_autosleep:b:true' --extra 'PIN:s:<pin>'
58
+ ```
59
+
60
+ Then restore via CLI:
61
+ ```bash
62
+ node build/index.js stay-awake --disable
63
+ ```
64
+
65
+ Expected: Reads PIN from config, restores all properties to false.
66
+
67
+ ### Test 5: Battery monitoring
68
+
69
+ ```bash
70
+ node build/index.js stay-awake --idle-timeout 120000
71
+ ```
72
+
73
+ Expected: Shows initial battery level. If charging, should log when battery crosses a 5% boundary (e.g. 85% → 90%). Monitor checks every 60s.
74
+
75
+ ### Test 6: --verbose battery output
76
+
77
+ ```bash
78
+ node build/index.js stay-awake --idle-timeout 120000 --verbose
79
+ ```
80
+
81
+ Expected: Prints battery level on every 60s check, not just at 5% boundaries.
82
+
83
+ ### Test 7: SIGUSR1 extends idle timeout
84
+
85
+ ```bash
86
+ node build/index.js stay-awake --pin <pin> --idle-timeout 20000 --verbose &
87
+ PID=$!
88
+ sleep 5
89
+ kill -USR1 $PID
90
+ sleep 5
91
+ kill -USR1 $PID
92
+ sleep 15
93
+ kill $PID
94
+ ```
95
+
96
+ Expected: Two timestamped `[HH:MM:SS] Activity detected, resetting idle timer` log lines. Process stays alive past the original 20s because signals keep resetting the timer.
97
+
98
+ ### Test 8: CLI flags override config
99
+
100
+ ```bash
101
+ node build/index.js stay-awake --idle-timeout 15000 --low-battery 20
102
+ ```
103
+
104
+ Expected: Should show "idle timeout: 15s, low battery exit: 20%" overriding the config values (60s / 15).
105
+
106
+ ### Test 9: Config file values used as defaults
107
+
108
+ ```bash
109
+ node build/index.js stay-awake
110
+ ```
111
+
112
+ Expected: Should show "idle timeout: 60s, low battery exit: 15%" (from `.quest-dev.json`).
113
+
114
+ ### Test 10: Watchdog cleanup after kill -9
115
+
116
+ ```bash
117
+ node build/index.js stay-awake --idle-timeout 120000 &
118
+ PARENT_PID=$!
119
+ sleep 3
120
+ adb shell content call --uri content://com.oculus.rc --method GET_PROPERTY
121
+ # Should show all true
122
+ kill -9 $PARENT_PID
123
+ sleep 8
124
+ adb shell content call --uri content://com.oculus.rc --method GET_PROPERTY
125
+ # Should show all false — watchdog restored them
126
+ ```
127
+
128
+ Expected: Watchdog detects parent death within ~5s and restores all properties to false.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myerscarpenter/quest-dev",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "CLI tools for Meta Quest development — stay awake, screenshots, URL opening, logcat, and battery via ADB",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,7 @@
15
15
  "test:watch": "vitest",
16
16
  "test:ui": "vitest --ui",
17
17
  "test:coverage": "vitest run --coverage",
18
+ "install:global": "pnpm run build && pnpm pack && pnpm install -g $PWD/myerscarpenter-quest-dev-$(node -p \"require('./package.json').version\").tgz && rm myerscarpenter-quest-dev-$(node -p \"require('./package.json').version\").tgz",
18
19
  "version:patch": "pnpm version patch",
19
20
  "version:minor": "pnpm version minor",
20
21
  "version:major": "pnpm version major"
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ import { openCommand } from './commands/open.js';
15
15
  import { startCommand, stopCommand, statusCommand, tailCommand } from './commands/logcat.js';
16
16
  import { batteryCommand } from './commands/battery.js';
17
17
  import { stayAwakeCommand, stayAwakeWatchdog, stayAwakeStatus, stayAwakeDisable } from './commands/stay-awake.js';
18
+ import { saveConfig, loadConfig } from './utils/config.js';
18
19
 
19
20
  // Read version from package.json
20
21
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -28,16 +29,11 @@ const cli = yargs(hideBin(process.argv))
28
29
  .scriptName('quest-dev')
29
30
  .version(version)
30
31
  .usage('Usage: $0 <command> [options]')
31
- .demandCommand(1, 'You must provide a command')
32
+ .demandCommand(1, '')
32
33
  .strict()
33
34
  .fail((msg, err, yargs) => {
34
- if (msg) {
35
- console.error(`Error: ${msg}\n`);
36
- }
37
- if (err) {
38
- console.error(err.message);
39
- }
40
- console.error('Run "quest-dev --help" for usage information.');
35
+ yargs.showHelp();
36
+ if (err) console.error(err.message);
41
37
  process.exit(1);
42
38
  })
43
39
  .help()
@@ -159,16 +155,16 @@ cli.command(
159
155
  (yargs) => {
160
156
  return yargs
161
157
  .option('pin', {
162
- describe: 'Meta Store PIN (or set in .quest-dev.json / ~/.config/quest-dev/config.json)',
158
+ describe: 'Meta Store PIN (or save with: quest-dev config --pin)',
163
159
  type: 'string',
164
160
  })
165
161
  .option('idle-timeout', {
166
- describe: 'Idle timeout in milliseconds (default: 300000 = 5 minutes, or set idleTimeout in config)',
162
+ describe: 'Idle timeout in milliseconds (default: 300000 = 5 minutes, or save with: quest-dev config)',
167
163
  type: 'number',
168
164
  alias: 'i',
169
165
  })
170
166
  .option('low-battery', {
171
- describe: 'Exit when battery drops to this percentage (default: 10, or set lowBattery in config)',
167
+ describe: 'Exit when battery drops to this percentage (default: 10, or save with: quest-dev config)',
172
168
  type: 'number',
173
169
  })
174
170
  .option('disable', {
@@ -204,6 +200,57 @@ cli.command(
204
200
  }
205
201
  );
206
202
 
203
+ // Config command
204
+ cli.command(
205
+ 'config',
206
+ 'Save default settings for quest-dev commands',
207
+ (yargs) => {
208
+ return yargs
209
+ .option('pin', {
210
+ describe: 'Meta Store PIN',
211
+ type: 'string',
212
+ })
213
+ .option('idle-timeout', {
214
+ describe: 'Idle timeout in milliseconds for stay-awake',
215
+ type: 'number',
216
+ })
217
+ .option('low-battery', {
218
+ describe: 'Exit stay-awake when battery drops to this percentage',
219
+ type: 'number',
220
+ })
221
+ .option('show', {
222
+ describe: 'Show current config and exit',
223
+ type: 'boolean',
224
+ default: false,
225
+ });
226
+ },
227
+ (argv) => {
228
+ if (argv.show) {
229
+ const config = loadConfig();
230
+ if (Object.keys(config).length === 0) {
231
+ console.log('No config found.');
232
+ } else {
233
+ console.log(JSON.stringify(config, null, 2));
234
+ }
235
+ return;
236
+ }
237
+
238
+ const values: Record<string, unknown> = {};
239
+ if (argv.pin !== undefined) values.pin = argv.pin;
240
+ if (argv.idleTimeout !== undefined) values.idleTimeout = argv.idleTimeout;
241
+ if (argv.lowBattery !== undefined) values.lowBattery = argv.lowBattery;
242
+
243
+ if (Object.keys(values).length === 0) {
244
+ console.error('No config values provided. Use --pin, --idle-timeout, or --low-battery.');
245
+ process.exit(1);
246
+ }
247
+
248
+ saveConfig(values as any);
249
+ console.log('Config saved:');
250
+ console.log(JSON.stringify(values, null, 2));
251
+ }
252
+ );
253
+
207
254
  // Stay-awake watchdog (internal subcommand, spawned by stay-awake parent)
208
255
  cli.command(
209
256
  'stay-awake-watchdog',
@@ -3,8 +3,8 @@
3
3
  * Resolves settings from CLI flags → .quest-dev.json → ~/.config/quest-dev/config.json
4
4
  */
5
5
 
6
- import { readFileSync } from 'fs';
7
- import { join } from 'path';
6
+ import { readFileSync, writeFileSync, mkdirSync } from 'fs';
7
+ import { join, dirname } from 'path';
8
8
  import { homedir } from 'os';
9
9
 
10
10
  export interface QuestDevConfig {
@@ -45,6 +45,29 @@ export function loadConfig(): QuestDevConfig {
45
45
  return merged;
46
46
  }
47
47
 
48
+ /**
49
+ * Save config values to ~/.config/quest-dev/config.json
50
+ * Merges with existing config (doesn't overwrite unrelated fields).
51
+ */
52
+ export function saveConfig(values: QuestDevConfig): string {
53
+ const configPath = join(homedir(), '.config', 'quest-dev', 'config.json');
54
+ let existing: QuestDevConfig = {};
55
+ try {
56
+ existing = JSON.parse(readFileSync(configPath, 'utf-8'));
57
+ } catch {
58
+ // No existing config, start fresh
59
+ }
60
+
61
+ const merged = { ...existing };
62
+ if (values.pin !== undefined) merged.pin = values.pin;
63
+ if (values.idleTimeout !== undefined) merged.idleTimeout = values.idleTimeout;
64
+ if (values.lowBattery !== undefined) merged.lowBattery = values.lowBattery;
65
+
66
+ mkdirSync(dirname(configPath), { recursive: true });
67
+ writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\n');
68
+ return configPath;
69
+ }
70
+
48
71
  /**
49
72
  * Resolve PIN from CLI flag, then config files
50
73
  */
@@ -58,8 +81,7 @@ export function loadPin(cliPin?: string): string {
58
81
  console.error('');
59
82
  console.error('Provide a PIN via one of:');
60
83
  console.error(' --pin <pin> CLI flag');
61
- console.error(' .quest-dev.json { "pin": "1234" }');
62
- console.error(' ~/.config/quest-dev/config.json { "pin": "1234" }');
84
+ console.error(' quest-dev config --pin <pin> Save as default');
63
85
  console.error('');
64
86
  console.error('The PIN is your Meta Store PIN for the logged-in account.');
65
87
  process.exit(1);