@myerscarpenter/quest-dev 1.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.
- package/.github/workflows/publish.yml +41 -0
- package/build/commands/open.d.ts +9 -0
- package/build/commands/open.d.ts.map +1 -0
- package/build/commands/open.js +111 -0
- package/build/commands/open.js.map +1 -0
- package/build/commands/screenshot.d.ts +9 -0
- package/build/commands/screenshot.d.ts.map +1 -0
- package/build/commands/screenshot.js +92 -0
- package/build/commands/screenshot.js.map +1 -0
- package/build/index.d.ts +7 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +59 -0
- package/build/index.js.map +1 -0
- package/build/utils/adb.d.ts +32 -0
- package/build/utils/adb.d.ts.map +1 -0
- package/build/utils/adb.js +191 -0
- package/build/utils/adb.js.map +1 -0
- package/build/utils/exec.d.ts +17 -0
- package/build/utils/exec.d.ts.map +1 -0
- package/build/utils/exec.js +66 -0
- package/build/utils/exec.js.map +1 -0
- package/package.json +63 -0
- package/src/commands/open.ts +138 -0
- package/src/commands/screenshot.ts +102 -0
- package/src/index.ts +77 -0
- package/src/utils/adb.ts +197 -0
- package/src/utils/exec.ts +83 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test-and-publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
id-token: write # Required for OIDC trusted publishing
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Setup Node.js
|
|
18
|
+
uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: 'lts/*'
|
|
21
|
+
registry-url: 'https://registry.npmjs.org'
|
|
22
|
+
|
|
23
|
+
- name: Install pnpm
|
|
24
|
+
uses: pnpm/action-setup@v4
|
|
25
|
+
with:
|
|
26
|
+
version: latest
|
|
27
|
+
|
|
28
|
+
- name: Install npm v11.6.2 (required for OIDC trusted publishing, min v11.5.1)
|
|
29
|
+
run: npm install -g npm@11.6.2
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: pnpm install
|
|
33
|
+
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: pnpm test
|
|
36
|
+
|
|
37
|
+
- name: Build
|
|
38
|
+
run: pnpm run build
|
|
39
|
+
|
|
40
|
+
- name: Publish to npm
|
|
41
|
+
run: npm publish --provenance --access public
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwFH;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2C5D"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quest open command
|
|
3
|
+
* Opens a URL in Quest browser with proper ADB port forwarding
|
|
4
|
+
*/
|
|
5
|
+
import { checkADBPath, checkADBDevices, ensurePortForwarding, isBrowserRunning, launchBrowser, getCDPPort } from '../utils/adb.js';
|
|
6
|
+
import { execCommandFull } from '../utils/exec.js';
|
|
7
|
+
/**
|
|
8
|
+
* Try to navigate or reload existing tab via cdp-cli
|
|
9
|
+
*/
|
|
10
|
+
async function tryNavigateExistingTab(targetUrl) {
|
|
11
|
+
const cdpPort = getCDPPort();
|
|
12
|
+
try {
|
|
13
|
+
// Get list of tabs using cdp-cli
|
|
14
|
+
const result = await execCommandFull('cdp-cli', ['--cdp-url', `http://localhost:${cdpPort}`, 'tabs']);
|
|
15
|
+
if (result.code !== 0) {
|
|
16
|
+
console.log('cdp-cli tabs command failed, will launch browser directly');
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
// Parse NDJSON output to find tabs
|
|
20
|
+
const lines = result.stdout.trim().split('\n').filter(line => line.trim());
|
|
21
|
+
const tabs = [];
|
|
22
|
+
for (const line of lines) {
|
|
23
|
+
try {
|
|
24
|
+
const tab = JSON.parse(line);
|
|
25
|
+
if (tab.id && tab.url !== undefined) {
|
|
26
|
+
tabs.push(tab);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Skip non-JSON lines
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// First, check if URL is already open
|
|
34
|
+
const existingTab = tabs.find(tab => tab.url === targetUrl);
|
|
35
|
+
if (existingTab) {
|
|
36
|
+
console.log(`Found existing tab with URL: ${targetUrl}`);
|
|
37
|
+
// Reload the tab
|
|
38
|
+
const reloadResult = await execCommandFull('cdp-cli', [
|
|
39
|
+
'--cdp-url', `http://localhost:${cdpPort}`,
|
|
40
|
+
'go', existingTab.id, 'reload'
|
|
41
|
+
]);
|
|
42
|
+
if (reloadResult.code === 0) {
|
|
43
|
+
console.log('Reloaded existing tab');
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Second, look for a blank tab to navigate
|
|
48
|
+
const blankTab = tabs.find(tab => tab.url === 'about:blank' ||
|
|
49
|
+
tab.url === 'chrome://newtab/' ||
|
|
50
|
+
tab.url === 'chrome://panel-app-nav/ntp' || // Quest New Tab page
|
|
51
|
+
tab.url === '');
|
|
52
|
+
if (blankTab) {
|
|
53
|
+
console.log('Found blank tab, navigating it...');
|
|
54
|
+
const navResult = await execCommandFull('cdp-cli', [
|
|
55
|
+
'--cdp-url', `http://localhost:${cdpPort}`,
|
|
56
|
+
'go', blankTab.id, targetUrl
|
|
57
|
+
]);
|
|
58
|
+
if (navResult.code === 0) {
|
|
59
|
+
console.log('Navigated blank tab to URL');
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.log('CDP operation failed:', error.message);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Main open command handler
|
|
72
|
+
*/
|
|
73
|
+
export async function openCommand(url) {
|
|
74
|
+
// Parse port from URL
|
|
75
|
+
let port;
|
|
76
|
+
try {
|
|
77
|
+
const parsedUrl = new URL(url);
|
|
78
|
+
port = parseInt(parsedUrl.port, 10);
|
|
79
|
+
if (!port || isNaN(port)) {
|
|
80
|
+
console.error('Error: Could not parse port from URL:', url);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error('Error: Invalid URL:', url);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
console.log(`\nOpening ${url} on Quest...\n`);
|
|
89
|
+
// Check prerequisites
|
|
90
|
+
checkADBPath();
|
|
91
|
+
await checkADBDevices();
|
|
92
|
+
// Set up port forwarding (idempotent)
|
|
93
|
+
await ensurePortForwarding(port);
|
|
94
|
+
// Check if browser is running
|
|
95
|
+
const browserRunning = await isBrowserRunning();
|
|
96
|
+
if (!browserRunning) {
|
|
97
|
+
console.log('Quest browser is not running');
|
|
98
|
+
await launchBrowser(url);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log('Quest browser is already running');
|
|
102
|
+
// Try to navigate existing or blank tab via cdp-cli first
|
|
103
|
+
const navigated = await tryNavigateExistingTab(url);
|
|
104
|
+
if (!navigated) {
|
|
105
|
+
console.log('No existing or blank tab found, opening URL...');
|
|
106
|
+
await launchBrowser(url);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
console.log('\nDone!\n');
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=open.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quest screenshot command
|
|
3
|
+
* Triggers Quest's native screenshot service and pulls the file
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Main screenshot command handler
|
|
7
|
+
*/
|
|
8
|
+
export declare function screenshotCommand(outputPath: string): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=screenshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/commands/screenshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiEH;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BzE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quest screenshot command
|
|
3
|
+
* Triggers Quest's native screenshot service and pulls the file
|
|
4
|
+
*/
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import { checkADBPath, checkADBDevices } from '../utils/adb.js';
|
|
7
|
+
import { execCommand } from '../utils/exec.js';
|
|
8
|
+
/**
|
|
9
|
+
* Trigger Quest screenshot service
|
|
10
|
+
*/
|
|
11
|
+
async function triggerScreenshot() {
|
|
12
|
+
try {
|
|
13
|
+
await execCommand('adb', [
|
|
14
|
+
'shell',
|
|
15
|
+
'am',
|
|
16
|
+
'startservice',
|
|
17
|
+
'-n',
|
|
18
|
+
'com.oculus.metacam/.capture.CaptureService',
|
|
19
|
+
'-a',
|
|
20
|
+
'TAKE_SCREENSHOT'
|
|
21
|
+
]);
|
|
22
|
+
console.log('Screenshot service triggered');
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error('Failed to trigger screenshot:', error.message);
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get most recent screenshot filename from Quest
|
|
32
|
+
*/
|
|
33
|
+
async function getMostRecentScreenshot() {
|
|
34
|
+
try {
|
|
35
|
+
const output = await execCommand('adb', ['shell', 'ls', '-t', '/sdcard/Oculus/Screenshots/']);
|
|
36
|
+
const files = output.split('\n').filter(line => line.trim() && line.endsWith('.jpg'));
|
|
37
|
+
if (files.length === 0) {
|
|
38
|
+
console.error('No screenshots found in /sdcard/Oculus/Screenshots/');
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const mostRecent = files[0].trim();
|
|
42
|
+
console.log(`Found most recent screenshot: ${mostRecent}`);
|
|
43
|
+
return mostRecent;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error('Failed to list screenshots:', error.message);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Pull screenshot from Quest to local path
|
|
52
|
+
*/
|
|
53
|
+
async function pullScreenshot(filename, outputPath) {
|
|
54
|
+
try {
|
|
55
|
+
const remotePath = `/sdcard/Oculus/Screenshots/${filename}`;
|
|
56
|
+
await execCommand('adb', ['pull', remotePath, outputPath]);
|
|
57
|
+
console.log(`Screenshot saved to: ${outputPath}`);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error('Failed to pull screenshot:', error.message);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Main screenshot command handler
|
|
67
|
+
*/
|
|
68
|
+
export async function screenshotCommand(outputPath) {
|
|
69
|
+
const resolvedPath = resolve(outputPath);
|
|
70
|
+
console.log('\nQuest Screenshot\n');
|
|
71
|
+
// Check prerequisites
|
|
72
|
+
checkADBPath();
|
|
73
|
+
await checkADBDevices();
|
|
74
|
+
// Trigger screenshot
|
|
75
|
+
if (!await triggerScreenshot()) {
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
// Wait for screenshot to save
|
|
79
|
+
console.log('Waiting for screenshot to save...');
|
|
80
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
81
|
+
// Get most recent screenshot
|
|
82
|
+
const filename = await getMostRecentScreenshot();
|
|
83
|
+
if (!filename) {
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
// Pull screenshot
|
|
87
|
+
if (!await pullScreenshot(filename, resolvedPath)) {
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
console.log('\nDone!\n');
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=screenshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/commands/screenshot.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Quest Dev CLI
|
|
4
|
+
* Command-line tools for Meta Quest Browser development
|
|
5
|
+
*/
|
|
6
|
+
import yargs from 'yargs';
|
|
7
|
+
import { hideBin } from 'yargs/helpers';
|
|
8
|
+
import { readFileSync } from 'fs';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { dirname, join } from 'path';
|
|
11
|
+
import { screenshotCommand } from './commands/screenshot.js';
|
|
12
|
+
import { openCommand } from './commands/open.js';
|
|
13
|
+
// Read version from package.json
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
16
|
+
const version = packageJson.version;
|
|
17
|
+
// Create CLI
|
|
18
|
+
const cli = yargs(hideBin(process.argv))
|
|
19
|
+
.scriptName('quest-dev')
|
|
20
|
+
.version(version)
|
|
21
|
+
.usage('Usage: $0 <command> [options]')
|
|
22
|
+
.demandCommand(1, 'You must provide a command')
|
|
23
|
+
.strict()
|
|
24
|
+
.fail((msg, err, yargs) => {
|
|
25
|
+
if (msg) {
|
|
26
|
+
console.error(`Error: ${msg}\n`);
|
|
27
|
+
}
|
|
28
|
+
if (err) {
|
|
29
|
+
console.error(err.message);
|
|
30
|
+
}
|
|
31
|
+
console.error('Run "quest-dev --help" for usage information.');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
})
|
|
34
|
+
.help()
|
|
35
|
+
.alias('help', 'h')
|
|
36
|
+
.epilog('Requires ADB to be installed and Quest connected via USB with debugging enabled.');
|
|
37
|
+
// Screenshot command
|
|
38
|
+
cli.command('screenshot <output>', 'Take a screenshot from Quest and save to local file', (yargs) => {
|
|
39
|
+
return yargs.positional('output', {
|
|
40
|
+
describe: 'Output file path (e.g., ~/screenshots/test.jpg)',
|
|
41
|
+
type: 'string',
|
|
42
|
+
demandOption: true
|
|
43
|
+
});
|
|
44
|
+
}, async (argv) => {
|
|
45
|
+
await screenshotCommand(argv.output);
|
|
46
|
+
});
|
|
47
|
+
// Open command
|
|
48
|
+
cli.command('open <url>', 'Open URL in Quest browser with ADB port forwarding', (yargs) => {
|
|
49
|
+
return yargs.positional('url', {
|
|
50
|
+
describe: 'URL to open (e.g., http://localhost:9004/myapp/)',
|
|
51
|
+
type: 'string',
|
|
52
|
+
demandOption: true
|
|
53
|
+
});
|
|
54
|
+
}, async (argv) => {
|
|
55
|
+
await openCommand(argv.url);
|
|
56
|
+
});
|
|
57
|
+
// Parse and execute
|
|
58
|
+
cli.parse();
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,iCAAiC;AACjC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAC1D,CAAC;AACF,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAEpC,aAAa;AACb,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KACrC,UAAU,CAAC,WAAW,CAAC;KACvB,OAAO,CAAC,OAAO,CAAC;KAChB,KAAK,CAAC,+BAA+B,CAAC;KACtC,aAAa,CAAC,CAAC,EAAE,4BAA4B,CAAC;KAC9C,MAAM,EAAE;KACR,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;IACxB,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;KACD,IAAI,EAAE;KACN,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC;KAClB,MAAM,CAAC,kFAAkF,CAAC,CAAC;AAE9F,qBAAqB;AACrB,GAAG,CAAC,OAAO,CACT,qBAAqB,EACrB,qDAAqD,EACrD,CAAC,KAAK,EAAE,EAAE;IACR,OAAO,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE;QAChC,QAAQ,EAAE,iDAAiD;QAC3D,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;AACL,CAAC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAgB,CAAC,CAAC;AACjD,CAAC,CACF,CAAC;AAEF,eAAe;AACf,GAAG,CAAC,OAAO,CACT,YAAY,EACZ,oDAAoD,EACpD,CAAC,KAAK,EAAE,EAAE;IACR,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE;QAC7B,QAAQ,EAAE,kDAAkD;QAC5D,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;AACL,CAAC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,MAAM,WAAW,CAAC,IAAI,CAAC,GAAa,CAAC,CAAC;AACxC,CAAC,CACF,CAAC;AAEF,oBAAoB;AACpB,GAAG,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADB utilities for Quest device communication
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check if ADB is available on PATH
|
|
6
|
+
*/
|
|
7
|
+
export declare function checkADBPath(): string;
|
|
8
|
+
/**
|
|
9
|
+
* Check if ADB devices are connected (with auto-recovery for server issues)
|
|
10
|
+
*/
|
|
11
|
+
export declare function checkADBDevices(retryCount?: number): Promise<boolean>;
|
|
12
|
+
/**
|
|
13
|
+
* Check if a port is already listening on localhost
|
|
14
|
+
*/
|
|
15
|
+
export declare function isPortListening(port: number): Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* Idempotently set up ADB port forwarding for a given port
|
|
18
|
+
*/
|
|
19
|
+
export declare function ensurePortForwarding(port: number): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Check if Quest browser is running
|
|
22
|
+
*/
|
|
23
|
+
export declare function isBrowserRunning(): Promise<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* Launch Quest browser with a URL using am start
|
|
26
|
+
*/
|
|
27
|
+
export declare function launchBrowser(url: string): Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Get CDP port
|
|
30
|
+
*/
|
|
31
|
+
export declare function getCDPPort(): number;
|
|
32
|
+
//# sourceMappingURL=adb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../../src/utils/adb.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAkBrC;AAoBD;;GAEG;AACH,wBAAsB,eAAe,CAAC,UAAU,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAqCtE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB9D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCtE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOzD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBjE;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADB utilities for Quest device communication
|
|
3
|
+
*/
|
|
4
|
+
import which from 'which';
|
|
5
|
+
import net from 'net';
|
|
6
|
+
import { execCommand, execCommandFull } from './exec.js';
|
|
7
|
+
const CDP_PORT = 9223; // Chrome DevTools Protocol port (Quest browser default)
|
|
8
|
+
/**
|
|
9
|
+
* Check if ADB is available on PATH
|
|
10
|
+
*/
|
|
11
|
+
export function checkADBPath() {
|
|
12
|
+
try {
|
|
13
|
+
const adbPath = which.sync('adb');
|
|
14
|
+
console.log(`Found ADB at: ${adbPath}`);
|
|
15
|
+
return adbPath;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.error('Error: ADB not found in PATH');
|
|
19
|
+
console.error('');
|
|
20
|
+
console.error('Please install Android Platform Tools and add adb to your PATH:');
|
|
21
|
+
console.error('https://developer.android.com/tools/releases/platform-tools');
|
|
22
|
+
console.error('');
|
|
23
|
+
console.error('Installation instructions:');
|
|
24
|
+
console.error('- macOS: brew install android-platform-tools');
|
|
25
|
+
console.error('- Linux: sudo apt install adb (or equivalent)');
|
|
26
|
+
console.error('- Windows: Download from the link above and add to PATH');
|
|
27
|
+
console.error('');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Restart ADB server if it's in a bad state
|
|
33
|
+
*/
|
|
34
|
+
async function restartADBServer() {
|
|
35
|
+
console.log('ADB server appears to be in a bad state, restarting...');
|
|
36
|
+
try {
|
|
37
|
+
// Kill server (ignore errors - it might already be dead)
|
|
38
|
+
await execCommandFull('adb', ['kill-server']);
|
|
39
|
+
// Start server
|
|
40
|
+
await execCommand('adb', ['start-server']);
|
|
41
|
+
console.log('ADB server restarted successfully');
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Failed to restart ADB server:', error.message);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if ADB devices are connected (with auto-recovery for server issues)
|
|
51
|
+
*/
|
|
52
|
+
export async function checkADBDevices(retryCount = 0) {
|
|
53
|
+
try {
|
|
54
|
+
const output = await execCommand('adb', ['devices']);
|
|
55
|
+
const lines = output.trim().split('\n').slice(1); // Skip header
|
|
56
|
+
const devices = lines.filter(line => line.trim() && !line.includes('List of devices'));
|
|
57
|
+
if (devices.length === 0) {
|
|
58
|
+
console.error('Error: No ADB devices connected');
|
|
59
|
+
console.error('');
|
|
60
|
+
console.error('Please connect your Quest device via USB and enable USB debugging');
|
|
61
|
+
console.error('');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
console.log(`Found ${devices.length} ADB device(s)`);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
const errorMsg = error.message;
|
|
69
|
+
// Check if it's a server issue
|
|
70
|
+
const isServerIssue = errorMsg.includes('protocol fault') ||
|
|
71
|
+
errorMsg.includes('Connection reset') ||
|
|
72
|
+
errorMsg.includes('server version') ||
|
|
73
|
+
errorMsg.includes('cannot connect to daemon');
|
|
74
|
+
if (isServerIssue && retryCount === 0) {
|
|
75
|
+
const restarted = await restartADBServer();
|
|
76
|
+
if (restarted) {
|
|
77
|
+
return await checkADBDevices(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
console.error('Error: Failed to list ADB devices:', errorMsg);
|
|
81
|
+
console.error('');
|
|
82
|
+
console.error('Try running: adb kill-server && adb start-server');
|
|
83
|
+
console.error('');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if a port is already listening on localhost
|
|
89
|
+
*/
|
|
90
|
+
export function isPortListening(port) {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
const socket = new net.Socket();
|
|
93
|
+
socket.setTimeout(500);
|
|
94
|
+
socket.on('connect', () => {
|
|
95
|
+
socket.destroy();
|
|
96
|
+
resolve(true);
|
|
97
|
+
});
|
|
98
|
+
socket.on('timeout', () => {
|
|
99
|
+
socket.destroy();
|
|
100
|
+
resolve(false);
|
|
101
|
+
});
|
|
102
|
+
socket.on('error', () => {
|
|
103
|
+
resolve(false);
|
|
104
|
+
});
|
|
105
|
+
socket.connect(port, '127.0.0.1');
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Idempotently set up ADB port forwarding for a given port
|
|
110
|
+
*/
|
|
111
|
+
export async function ensurePortForwarding(port) {
|
|
112
|
+
try {
|
|
113
|
+
// Check reverse forwarding (Quest -> Host for dev server)
|
|
114
|
+
const reverseList = await execCommand('adb', ['reverse', '--list']);
|
|
115
|
+
const reverseExists = reverseList.includes(`tcp:${port}`);
|
|
116
|
+
if (reverseExists) {
|
|
117
|
+
console.log(`ADB reverse port forwarding already set up: Quest:${port} -> Host:${port}`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
await execCommand('adb', ['reverse', `tcp:${port}`, `tcp:${port}`]);
|
|
121
|
+
console.log(`ADB reverse port forwarding set up: Quest:${port} -> Host:${port}`);
|
|
122
|
+
}
|
|
123
|
+
// Check forward forwarding (Host -> Quest for CDP)
|
|
124
|
+
const cdpPortListening = await isPortListening(CDP_PORT);
|
|
125
|
+
if (cdpPortListening) {
|
|
126
|
+
console.log(`CDP port ${CDP_PORT} already listening (forwarding assumed active)`);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
try {
|
|
130
|
+
await execCommand('adb', ['forward', `tcp:${CDP_PORT}`, 'localabstract:chrome_devtools_remote']);
|
|
131
|
+
console.log(`ADB forward port forwarding set up: Host:${CDP_PORT} -> Quest:chrome_devtools_remote (CDP)`);
|
|
132
|
+
}
|
|
133
|
+
catch (forwardError) {
|
|
134
|
+
const errorMsg = forwardError.message;
|
|
135
|
+
if (errorMsg.includes('Address already in use')) {
|
|
136
|
+
console.log(`CDP port ${CDP_PORT} is now active (another process set it up)`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
throw forwardError;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
console.error('Failed to set up port forwarding:', error.message);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Check if Quest browser is running
|
|
151
|
+
*/
|
|
152
|
+
export async function isBrowserRunning() {
|
|
153
|
+
try {
|
|
154
|
+
const result = await execCommandFull('adb', ['shell', 'ps | grep com.oculus.browser']);
|
|
155
|
+
return result.stdout.includes('com.oculus.browser');
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Launch Quest browser with a URL using am start
|
|
163
|
+
*/
|
|
164
|
+
export async function launchBrowser(url) {
|
|
165
|
+
console.log('Launching Quest browser...');
|
|
166
|
+
try {
|
|
167
|
+
await execCommand('adb', [
|
|
168
|
+
'shell',
|
|
169
|
+
'am',
|
|
170
|
+
'start',
|
|
171
|
+
'-a',
|
|
172
|
+
'android.intent.action.VIEW',
|
|
173
|
+
'-d',
|
|
174
|
+
url,
|
|
175
|
+
'com.oculus.browser'
|
|
176
|
+
]);
|
|
177
|
+
console.log(`Quest browser launched with URL: ${url}`);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.error('Failed to launch Quest browser:', error.message);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get CDP port
|
|
187
|
+
*/
|
|
188
|
+
export function getCDPPort() {
|
|
189
|
+
return CDP_PORT;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=adb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adb.js","sourceRoot":"","sources":["../../src/utils/adb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell command execution utilities
|
|
3
|
+
*/
|
|
4
|
+
export interface ExecResult {
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
code: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Execute a shell command and return a promise with stdout
|
|
11
|
+
*/
|
|
12
|
+
export declare function execCommand(command: string, args?: string[]): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Execute a shell command and return full result (doesn't throw on non-zero exit)
|
|
15
|
+
*/
|
|
16
|
+
export declare function execCommandFull(command: string, args?: string[]): Promise<ExecResult>;
|
|
17
|
+
//# sourceMappingURL=exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAgCjF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA8BzF"}
|