From dfb35aa5d93707cc03c60ce3d2a5fb10f199a9bc Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Tue, 17 Mar 2026 19:00:11 +0100 Subject: [PATCH 1/7] update to use fingerprint-hash param instead of runtimeVersion --- build/continuous-deploy-fingerprint-info/index.js | 2 +- build/continuous-deploy-fingerprint/index.js | 2 +- bun.lock | 1 + src/fingerprintUtils.ts | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build/continuous-deploy-fingerprint-info/index.js b/build/continuous-deploy-fingerprint-info/index.js index 8c5128812..2b769cfac 100644 --- a/build/continuous-deploy-fingerprint-info/index.js +++ b/build/continuous-deploy-fingerprint-info/index.js @@ -28264,7 +28264,7 @@ async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, finger platform, '--buildProfile', profile, - '--runtimeVersion', + '--fingerprint-hash', fingerprintHash, '--limit', '1', diff --git a/build/continuous-deploy-fingerprint/index.js b/build/continuous-deploy-fingerprint/index.js index 4d713c2c1..3c4da9ec4 100644 --- a/build/continuous-deploy-fingerprint/index.js +++ b/build/continuous-deploy-fingerprint/index.js @@ -35225,7 +35225,7 @@ async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, finger platform, '--buildProfile', profile, - '--runtimeVersion', + '--fingerprint-hash', fingerprintHash, '--limit', '1', diff --git a/bun.lock b/bun.lock index 33e237562..f822282ce 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "expo-github-action", diff --git a/src/fingerprintUtils.ts b/src/fingerprintUtils.ts index 23ea009de..1a5649d58 100644 --- a/src/fingerprintUtils.ts +++ b/src/fingerprintUtils.ts @@ -112,7 +112,7 @@ export async function getBuildInfoWithFingerprintAsync({ platform, '--buildProfile', profile, - '--runtimeVersion', + '--fingerprint-hash', fingerprintHash, '--limit', '1', From 2d2a532d83c0cec3cb78c8b2c7ca1d477d4aaf84 Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Tue, 17 Mar 2026 20:12:34 +0100 Subject: [PATCH 2/7] add debugging --- .../index.js | 7 +++- build/continuous-deploy-fingerprint/index.js | 29 +++++++------- src/fingerprintUtils.ts | 39 +++++++++---------- 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/build/continuous-deploy-fingerprint-info/index.js b/build/continuous-deploy-fingerprint-info/index.js index 2b769cfac..749d4e419 100644 --- a/build/continuous-deploy-fingerprint-info/index.js +++ b/build/continuous-deploy-fingerprint-info/index.js @@ -28258,7 +28258,7 @@ async function getFingerprintHashForPlatformAsync({ cwd, platform, environment, async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, fingerprintHash, excludeExpiredBuilds, }) { let builds; try { - const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), [ + const args = [ 'build:list', '--platform', platform, @@ -28270,10 +28270,13 @@ async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, finger '1', '--json', '--non-interactive', - ], { + ] + console.log(`Running command: eas ${args.join(' ')}`); + const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), args, { cwd, silent: !(0, core_1.isDebug)(), }); + console.log('stdout', JSON.stringify(stdout, null, 2)) builds = JSON.parse(stdout); } catch (error) { diff --git a/build/continuous-deploy-fingerprint/index.js b/build/continuous-deploy-fingerprint/index.js index 3c4da9ec4..f4f431520 100644 --- a/build/continuous-deploy-fingerprint/index.js +++ b/build/continuous-deploy-fingerprint/index.js @@ -35219,22 +35219,25 @@ async function getFingerprintHashForPlatformAsync({ cwd, platform, environment, async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, fingerprintHash, excludeExpiredBuilds, }) { let builds; try { - const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), [ - 'build:list', - '--platform', - platform, - '--buildProfile', - profile, - '--fingerprint-hash', - fingerprintHash, - '--limit', - '1', - '--json', - '--non-interactive', - ], { + const args = [ + 'build:list', + '--platform', + platform, + '--buildProfile', + profile, + '--fingerprint-hash', + fingerprintHash, + '--limit', + '1', + '--json', + '--non-interactive', + ] + console.log(`Running command: eas ${args.join(' ')}`); + const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), args, { cwd, silent: !(0, core_1.isDebug)(), }); + console.log('stdout', JSON.stringify(stdout, null, 2)) builds = JSON.parse(stdout); } catch (error) { diff --git a/src/fingerprintUtils.ts b/src/fingerprintUtils.ts index 1a5649d58..af48d556f 100644 --- a/src/fingerprintUtils.ts +++ b/src/fingerprintUtils.ts @@ -104,26 +104,25 @@ export async function getBuildInfoWithFingerprintAsync({ }): Promise { let builds: BuildInfo[]; try { - const { stdout } = await getExecOutput( - await which('eas', true), - [ - 'build:list', - '--platform', - platform, - '--buildProfile', - profile, - '--fingerprint-hash', - fingerprintHash, - '--limit', - '1', - '--json', - '--non-interactive', - ], - { - cwd, - silent: !isDebug(), - } - ); + const args = [ + 'build:list', + '--platform', + platform, + '--buildProfile', + profile, + '--fingerprint-hash', + fingerprintHash, + '--limit', + '1', + '--json', + '--non-interactive', + ]; + console.log(`Running command: eas ${args.join(' ')}`); + const { stdout } = await getExecOutput(await which('eas', true), args, { + cwd, + silent: !isDebug(), + }); + console.log('stdout', JSON.stringify(stdout, null, 2)); builds = JSON.parse(stdout); } catch (error: unknown) { throw new Error(`Error getting EAS builds: ${String(error)}`, { cause: error }); From 7a66de23bb2e29c18e46a4420a45120860af06e8 Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Wed, 18 Mar 2026 01:26:08 +0100 Subject: [PATCH 3/7] Revert "add debugging" This reverts commit 2d2a532d83c0cec3cb78c8b2c7ca1d477d4aaf84. --- .../index.js | 7 +--- build/continuous-deploy-fingerprint/index.js | 29 +++++++------- src/fingerprintUtils.ts | 39 ++++++++++--------- 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/build/continuous-deploy-fingerprint-info/index.js b/build/continuous-deploy-fingerprint-info/index.js index 749d4e419..2b769cfac 100644 --- a/build/continuous-deploy-fingerprint-info/index.js +++ b/build/continuous-deploy-fingerprint-info/index.js @@ -28258,7 +28258,7 @@ async function getFingerprintHashForPlatformAsync({ cwd, platform, environment, async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, fingerprintHash, excludeExpiredBuilds, }) { let builds; try { - const args = [ + const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), [ 'build:list', '--platform', platform, @@ -28270,13 +28270,10 @@ async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, finger '1', '--json', '--non-interactive', - ] - console.log(`Running command: eas ${args.join(' ')}`); - const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), args, { + ], { cwd, silent: !(0, core_1.isDebug)(), }); - console.log('stdout', JSON.stringify(stdout, null, 2)) builds = JSON.parse(stdout); } catch (error) { diff --git a/build/continuous-deploy-fingerprint/index.js b/build/continuous-deploy-fingerprint/index.js index f4f431520..3c4da9ec4 100644 --- a/build/continuous-deploy-fingerprint/index.js +++ b/build/continuous-deploy-fingerprint/index.js @@ -35219,25 +35219,22 @@ async function getFingerprintHashForPlatformAsync({ cwd, platform, environment, async function getBuildInfoWithFingerprintAsync({ cwd, platform, profile, fingerprintHash, excludeExpiredBuilds, }) { let builds; try { - const args = [ - 'build:list', - '--platform', - platform, - '--buildProfile', - profile, - '--fingerprint-hash', - fingerprintHash, - '--limit', - '1', - '--json', - '--non-interactive', - ] - console.log(`Running command: eas ${args.join(' ')}`); - const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), args, { + const { stdout } = await (0, exec_1.getExecOutput)(await (0, io_1.which)('eas', true), [ + 'build:list', + '--platform', + platform, + '--buildProfile', + profile, + '--fingerprint-hash', + fingerprintHash, + '--limit', + '1', + '--json', + '--non-interactive', + ], { cwd, silent: !(0, core_1.isDebug)(), }); - console.log('stdout', JSON.stringify(stdout, null, 2)) builds = JSON.parse(stdout); } catch (error) { diff --git a/src/fingerprintUtils.ts b/src/fingerprintUtils.ts index af48d556f..1a5649d58 100644 --- a/src/fingerprintUtils.ts +++ b/src/fingerprintUtils.ts @@ -104,25 +104,26 @@ export async function getBuildInfoWithFingerprintAsync({ }): Promise { let builds: BuildInfo[]; try { - const args = [ - 'build:list', - '--platform', - platform, - '--buildProfile', - profile, - '--fingerprint-hash', - fingerprintHash, - '--limit', - '1', - '--json', - '--non-interactive', - ]; - console.log(`Running command: eas ${args.join(' ')}`); - const { stdout } = await getExecOutput(await which('eas', true), args, { - cwd, - silent: !isDebug(), - }); - console.log('stdout', JSON.stringify(stdout, null, 2)); + const { stdout } = await getExecOutput( + await which('eas', true), + [ + 'build:list', + '--platform', + platform, + '--buildProfile', + profile, + '--fingerprint-hash', + fingerprintHash, + '--limit', + '1', + '--json', + '--non-interactive', + ], + { + cwd, + silent: !isDebug(), + } + ); builds = JSON.parse(stdout); } catch (error: unknown) { throw new Error(`Error getting EAS builds: ${String(error)}`, { cause: error }); From 9daef4d3d69f4664eda47ffa8b2c61380a4cf104 Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Fri, 3 Apr 2026 01:02:18 +0200 Subject: [PATCH 4/7] Add debug logging to loadProjectConfig to diagnose 'Could not fetch project info' failures Co-Authored-By: Claude Opus 4.6 (1M context) --- .../index.js | 18 ++++++++++++++-- build/continuous-deploy-fingerprint/index.js | 18 ++++++++++++++-- src/project.ts | 21 ++++++++++++++++--- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/build/continuous-deploy-fingerprint-info/index.js b/build/continuous-deploy-fingerprint-info/index.js index 2b769cfac..1d4410a09 100644 --- a/build/continuous-deploy-fingerprint-info/index.js +++ b/build/continuous-deploy-fingerprint-info/index.js @@ -28352,13 +28352,27 @@ async function loadProjectConfig(cwd, easEnvironment) { commandLine = 'npx'; args = baseArguments; } + (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); + (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { + const result = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - })); + }); + stdout = result.stdout; + if (result.stderr) { + (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); + } + (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); } catch (error) { + (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); + if (error instanceof Error && 'stdout' in error) { + (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); + } + if (error instanceof Error && 'stderr' in error) { + (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); + } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/build/continuous-deploy-fingerprint/index.js b/build/continuous-deploy-fingerprint/index.js index 3c4da9ec4..7cd918690 100644 --- a/build/continuous-deploy-fingerprint/index.js +++ b/build/continuous-deploy-fingerprint/index.js @@ -35478,13 +35478,27 @@ async function loadProjectConfig(cwd, easEnvironment) { commandLine = 'npx'; args = baseArguments; } + (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); + (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { + const result = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - })); + }); + stdout = result.stdout; + if (result.stderr) { + (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); + } + (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); } catch (error) { + (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); + if (error instanceof Error && 'stdout' in error) { + (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); + } + if (error instanceof Error && 'stderr' in error) { + (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); + } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/src/project.ts b/src/project.ts index 4a88e533a..502c2c788 100644 --- a/src/project.ts +++ b/src/project.ts @@ -1,4 +1,4 @@ -import { isDebug } from '@actions/core'; +import { info, warning, isDebug } from '@actions/core'; import { getExecOutput } from '@actions/exec'; import { which } from '@actions/io'; import { ExpoConfig } from '@expo/config'; @@ -27,12 +27,27 @@ export async function loadProjectConfig( args = baseArguments; } + info(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); + info(`[loadProjectConfig] cwd: ${cwd}`); + try { - ({ stdout } = await getExecOutput(commandLine, args, { + const result = await getExecOutput(commandLine, args, { cwd, silent: !isDebug(), - })); + }); + stdout = result.stdout; + if (result.stderr) { + warning(`[loadProjectConfig] stderr: ${result.stderr}`); + } + info(`[loadProjectConfig] exitCode: ${result.exitCode}`); } catch (error: unknown) { + warning(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); + if (error instanceof Error && 'stdout' in error) { + warning(`[loadProjectConfig] stdout from error: ${(error as any).stdout}`); + } + if (error instanceof Error && 'stderr' in error) { + warning(`[loadProjectConfig] stderr from error: ${(error as any).stderr}`); + } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } From 88a3d845daaee01f7b91ed65c1e3fb7e01401b20 Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Fri, 3 Apr 2026 01:37:19 +0200 Subject: [PATCH 5/7] Prefer bunx over npx for expo config resolution npx fails with ENOTDIR when the project contains symlinked files (e.g. CLAUDE.md -> AGENTS.md) because its older @expo/config version tries to open /package.json without checking if the entry is a directory first. bunx resolves to the project-local expo version which handles this correctly. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../index.js | 18 ++++++++-- build/continuous-deploy-fingerprint/index.js | 18 ++++++++-- build/preview-build/index.js | 36 ++++++++++++++++--- build/preview/index.js | 36 ++++++++++++++++--- src/project.ts | 18 ++++++++-- 5 files changed, 112 insertions(+), 14 deletions(-) diff --git a/build/continuous-deploy-fingerprint-info/index.js b/build/continuous-deploy-fingerprint-info/index.js index 1d4410a09..1fe09c18c 100644 --- a/build/continuous-deploy-fingerprint-info/index.js +++ b/build/continuous-deploy-fingerprint-info/index.js @@ -28333,6 +28333,19 @@ exports.loadProjectConfig = loadProjectConfig; const core_1 = __nccwpck_require__(7484); const exec_1 = __nccwpck_require__(5236); const io_1 = __nccwpck_require__(4994); +/** + * Resolve the package runner to use for executing expo commands. + * Prefers `bunx` if available (works better with bun-managed projects), + * falls back to `npx`. + */ +async function resolvePackageRunner() { + try { + return await (0, io_1.which)('bunx', true); + } + catch { + return 'npx'; + } +} /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -28345,11 +28358,12 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await resolvePackageRunner(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await resolvePackageRunner(); args = baseArguments; } (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); diff --git a/build/continuous-deploy-fingerprint/index.js b/build/continuous-deploy-fingerprint/index.js index 7cd918690..e11e0ac37 100644 --- a/build/continuous-deploy-fingerprint/index.js +++ b/build/continuous-deploy-fingerprint/index.js @@ -35459,6 +35459,19 @@ exports.loadProjectConfig = loadProjectConfig; const core_1 = __nccwpck_require__(7484); const exec_1 = __nccwpck_require__(5236); const io_1 = __nccwpck_require__(4994); +/** + * Resolve the package runner to use for executing expo commands. + * Prefers `bunx` if available (works better with bun-managed projects), + * falls back to `npx`. + */ +async function resolvePackageRunner() { + try { + return await (0, io_1.which)('bunx', true); + } + catch { + return 'npx'; + } +} /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -35471,11 +35484,12 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await resolvePackageRunner(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await resolvePackageRunner(); args = baseArguments; } (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); diff --git a/build/preview-build/index.js b/build/preview-build/index.js index c9a089e3c..da8316664 100644 --- a/build/preview-build/index.js +++ b/build/preview-build/index.js @@ -99133,6 +99133,19 @@ exports.loadProjectConfig = loadProjectConfig; const core_1 = __nccwpck_require__(7484); const exec_1 = __nccwpck_require__(5236); const io_1 = __nccwpck_require__(4994); +/** + * Resolve the package runner to use for executing expo commands. + * Prefers `bunx` if available (works better with bun-managed projects), + * falls back to `npx`. + */ +async function resolvePackageRunner() { + try { + return await (0, io_1.which)('bunx', true); + } + catch { + return 'npx'; + } +} /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -99145,20 +99158,35 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await resolvePackageRunner(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await resolvePackageRunner(); args = baseArguments; } + (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); + (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { + const result = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - })); + }); + stdout = result.stdout; + if (result.stderr) { + (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); + } + (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); } catch (error) { + (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); + if (error instanceof Error && 'stdout' in error) { + (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); + } + if (error instanceof Error && 'stderr' in error) { + (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); + } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/build/preview/index.js b/build/preview/index.js index e1a36eb41..e7490d16e 100644 --- a/build/preview/index.js +++ b/build/preview/index.js @@ -35535,6 +35535,19 @@ exports.loadProjectConfig = loadProjectConfig; const core_1 = __nccwpck_require__(7484); const exec_1 = __nccwpck_require__(5236); const io_1 = __nccwpck_require__(4994); +/** + * Resolve the package runner to use for executing expo commands. + * Prefers `bunx` if available (works better with bun-managed projects), + * falls back to `npx`. + */ +async function resolvePackageRunner() { + try { + return await (0, io_1.which)('bunx', true); + } + catch { + return 'npx'; + } +} /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -35547,20 +35560,35 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await resolvePackageRunner(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await resolvePackageRunner(); args = baseArguments; } + (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); + (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { + const result = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - })); + }); + stdout = result.stdout; + if (result.stderr) { + (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); + } + (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); } catch (error) { + (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); + if (error instanceof Error && 'stdout' in error) { + (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); + } + if (error instanceof Error && 'stderr' in error) { + (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); + } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/src/project.ts b/src/project.ts index 502c2c788..ab61dcacc 100644 --- a/src/project.ts +++ b/src/project.ts @@ -3,6 +3,19 @@ import { getExecOutput } from '@actions/exec'; import { which } from '@actions/io'; import { ExpoConfig } from '@expo/config'; +/** + * Resolve the package runner to use for executing expo commands. + * Prefers `bunx` if available (works better with bun-managed projects), + * falls back to `npx`. + */ +async function resolvePackageRunner(): Promise { + try { + return await which('bunx', true); + } catch { + return 'npx'; + } +} + /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -20,10 +33,11 @@ export async function loadProjectConfig( let args: string[]; if (easEnvironment) { commandLine = await which('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await resolvePackageRunner(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await resolvePackageRunner(); args = baseArguments; } From d756d6a354324a029d54565959f235e476c577b6 Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Fri, 3 Apr 2026 01:40:10 +0200 Subject: [PATCH 6/7] Remove debug logging from loadProjectConfig Co-Authored-By: Claude Opus 4.6 (1M context) --- .../index.js | 18 ++-------------- build/continuous-deploy-fingerprint/index.js | 18 ++-------------- build/preview-build/index.js | 18 ++-------------- build/preview/index.js | 18 ++-------------- src/project.ts | 21 +++---------------- 5 files changed, 11 insertions(+), 82 deletions(-) diff --git a/build/continuous-deploy-fingerprint-info/index.js b/build/continuous-deploy-fingerprint-info/index.js index 1fe09c18c..c900fe107 100644 --- a/build/continuous-deploy-fingerprint-info/index.js +++ b/build/continuous-deploy-fingerprint-info/index.js @@ -28366,27 +28366,13 @@ async function loadProjectConfig(cwd, easEnvironment) { commandLine = await resolvePackageRunner(); args = baseArguments; } - (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); - (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - const result = await (0, exec_1.getExecOutput)(commandLine, args, { + ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - }); - stdout = result.stdout; - if (result.stderr) { - (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); - } - (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); + })); } catch (error) { - (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); - if (error instanceof Error && 'stdout' in error) { - (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); - } - if (error instanceof Error && 'stderr' in error) { - (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); - } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/build/continuous-deploy-fingerprint/index.js b/build/continuous-deploy-fingerprint/index.js index e11e0ac37..7fe127519 100644 --- a/build/continuous-deploy-fingerprint/index.js +++ b/build/continuous-deploy-fingerprint/index.js @@ -35492,27 +35492,13 @@ async function loadProjectConfig(cwd, easEnvironment) { commandLine = await resolvePackageRunner(); args = baseArguments; } - (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); - (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - const result = await (0, exec_1.getExecOutput)(commandLine, args, { + ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - }); - stdout = result.stdout; - if (result.stderr) { - (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); - } - (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); + })); } catch (error) { - (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); - if (error instanceof Error && 'stdout' in error) { - (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); - } - if (error instanceof Error && 'stderr' in error) { - (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); - } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/build/preview-build/index.js b/build/preview-build/index.js index da8316664..2ff55eb91 100644 --- a/build/preview-build/index.js +++ b/build/preview-build/index.js @@ -99166,27 +99166,13 @@ async function loadProjectConfig(cwd, easEnvironment) { commandLine = await resolvePackageRunner(); args = baseArguments; } - (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); - (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - const result = await (0, exec_1.getExecOutput)(commandLine, args, { + ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - }); - stdout = result.stdout; - if (result.stderr) { - (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); - } - (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); + })); } catch (error) { - (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); - if (error instanceof Error && 'stdout' in error) { - (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); - } - if (error instanceof Error && 'stderr' in error) { - (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); - } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/build/preview/index.js b/build/preview/index.js index e7490d16e..f2fcc05ca 100644 --- a/build/preview/index.js +++ b/build/preview/index.js @@ -35568,27 +35568,13 @@ async function loadProjectConfig(cwd, easEnvironment) { commandLine = await resolvePackageRunner(); args = baseArguments; } - (0, core_1.info)(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); - (0, core_1.info)(`[loadProjectConfig] cwd: ${cwd}`); try { - const result = await (0, exec_1.getExecOutput)(commandLine, args, { + ({ stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { cwd, silent: !(0, core_1.isDebug)(), - }); - stdout = result.stdout; - if (result.stderr) { - (0, core_1.warning)(`[loadProjectConfig] stderr: ${result.stderr}`); - } - (0, core_1.info)(`[loadProjectConfig] exitCode: ${result.exitCode}`); + })); } catch (error) { - (0, core_1.warning)(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); - if (error instanceof Error && 'stdout' in error) { - (0, core_1.warning)(`[loadProjectConfig] stdout from error: ${error.stdout}`); - } - if (error instanceof Error && 'stderr' in error) { - (0, core_1.warning)(`[loadProjectConfig] stderr from error: ${error.stderr}`); - } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } return JSON.parse(stdout); diff --git a/src/project.ts b/src/project.ts index ab61dcacc..aa9257bca 100644 --- a/src/project.ts +++ b/src/project.ts @@ -1,4 +1,4 @@ -import { info, warning, isDebug } from '@actions/core'; +import { isDebug } from '@actions/core'; import { getExecOutput } from '@actions/exec'; import { which } from '@actions/io'; import { ExpoConfig } from '@expo/config'; @@ -41,27 +41,12 @@ export async function loadProjectConfig( args = baseArguments; } - info(`[loadProjectConfig] Running: ${commandLine} ${args.join(' ')}`); - info(`[loadProjectConfig] cwd: ${cwd}`); - try { - const result = await getExecOutput(commandLine, args, { + ({ stdout } = await getExecOutput(commandLine, args, { cwd, silent: !isDebug(), - }); - stdout = result.stdout; - if (result.stderr) { - warning(`[loadProjectConfig] stderr: ${result.stderr}`); - } - info(`[loadProjectConfig] exitCode: ${result.exitCode}`); + })); } catch (error: unknown) { - warning(`[loadProjectConfig] Command failed. Error: ${error instanceof Error ? error.message : String(error)}`); - if (error instanceof Error && 'stdout' in error) { - warning(`[loadProjectConfig] stdout from error: ${(error as any).stdout}`); - } - if (error instanceof Error && 'stderr' in error) { - warning(`[loadProjectConfig] stderr from error: ${(error as any).stderr}`); - } throw new Error(`Could not fetch the project info from ${cwd}`, { cause: error }); } From 6402b75b494c69f1679689ecf5e446abb6e60bef Mon Sep 17 00:00:00 2001 From: Robert Herber Date: Fri, 3 Apr 2026 02:26:44 +0200 Subject: [PATCH 7/7] Use bunx for fingerprint generation too Extract resolvePackageRunner to shared module and apply it to both loadProjectConfig and getFingerprintHashForPlatformAsync. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../index.js | 31 +++++++++---- build/continuous-deploy-fingerprint/index.js | 31 +++++++++---- build/preview-build/index.js | 43 ++++++++++++------- build/preview/index.js | 25 ++++++++--- src/fingerprintUtils.ts | 6 ++- src/packageRunner.ts | 14 ++++++ src/project.ts | 13 +----- 7 files changed, 112 insertions(+), 51 deletions(-) create mode 100644 src/packageRunner.ts diff --git a/build/continuous-deploy-fingerprint-info/index.js b/build/continuous-deploy-fingerprint-info/index.js index c900fe107..18195a15f 100644 --- a/build/continuous-deploy-fingerprint-info/index.js +++ b/build/continuous-deploy-fingerprint-info/index.js @@ -28199,6 +28199,7 @@ const core_1 = __nccwpck_require__(7484); const exec_1 = __nccwpck_require__(5236); const io_1 = __nccwpck_require__(4994); const expo_1 = __nccwpck_require__(4503); +const packageRunner_1 = __nccwpck_require__(7253); async function getBuildInfoForCurrentFingerprintAsync({ platform, workingDirectory, environment, profile, isInPullRequest, }) { const humanReadablePlatformName = platform === 'ios' ? 'iOS' : 'Android'; const fingerprintHash = await getFingerprintHashForPlatformAsync({ @@ -28234,11 +28235,12 @@ async function getFingerprintHashForPlatformAsync({ cwd, platform, environment, let args; if (environment) { commandLine = await (0, io_1.which)('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await (0, packageRunner_1.resolvePackageRunner)(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', environment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await (0, packageRunner_1.resolvePackageRunner)(); args = baseArguments; } const { stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { @@ -28323,15 +28325,13 @@ function getInput(name, options) { /***/ }), -/***/ 4330: +/***/ 7253: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.loadProjectConfig = loadProjectConfig; -const core_1 = __nccwpck_require__(7484); -const exec_1 = __nccwpck_require__(5236); +exports.resolvePackageRunner = resolvePackageRunner; const io_1 = __nccwpck_require__(4994); /** * Resolve the package runner to use for executing expo commands. @@ -28346,6 +28346,21 @@ async function resolvePackageRunner() { return 'npx'; } } + + +/***/ }), + +/***/ 4330: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.loadProjectConfig = loadProjectConfig; +const core_1 = __nccwpck_require__(7484); +const exec_1 = __nccwpck_require__(5236); +const io_1 = __nccwpck_require__(4994); +const packageRunner_1 = __nccwpck_require__(7253); /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -28358,12 +28373,12 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const runner = await resolvePackageRunner(); + const runner = await (0, packageRunner_1.resolvePackageRunner)(); const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = await resolvePackageRunner(); + commandLine = await (0, packageRunner_1.resolvePackageRunner)(); args = baseArguments; } try { diff --git a/build/continuous-deploy-fingerprint/index.js b/build/continuous-deploy-fingerprint/index.js index 7fe127519..794894bc7 100644 --- a/build/continuous-deploy-fingerprint/index.js +++ b/build/continuous-deploy-fingerprint/index.js @@ -35160,6 +35160,7 @@ const core_1 = __nccwpck_require__(7484); const exec_1 = __nccwpck_require__(5236); const io_1 = __nccwpck_require__(4994); const expo_1 = __nccwpck_require__(4503); +const packageRunner_1 = __nccwpck_require__(7253); async function getBuildInfoForCurrentFingerprintAsync({ platform, workingDirectory, environment, profile, isInPullRequest, }) { const humanReadablePlatformName = platform === 'ios' ? 'iOS' : 'Android'; const fingerprintHash = await getFingerprintHashForPlatformAsync({ @@ -35195,11 +35196,12 @@ async function getFingerprintHashForPlatformAsync({ cwd, platform, environment, let args; if (environment) { commandLine = await (0, io_1.which)('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await (0, packageRunner_1.resolvePackageRunner)(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', environment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await (0, packageRunner_1.resolvePackageRunner)(); args = baseArguments; } const { stdout } = await (0, exec_1.getExecOutput)(commandLine, args, { @@ -35449,15 +35451,13 @@ function getInput(name, options) { /***/ }), -/***/ 4330: +/***/ 7253: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.loadProjectConfig = loadProjectConfig; -const core_1 = __nccwpck_require__(7484); -const exec_1 = __nccwpck_require__(5236); +exports.resolvePackageRunner = resolvePackageRunner; const io_1 = __nccwpck_require__(4994); /** * Resolve the package runner to use for executing expo commands. @@ -35472,6 +35472,21 @@ async function resolvePackageRunner() { return 'npx'; } } + + +/***/ }), + +/***/ 4330: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.loadProjectConfig = loadProjectConfig; +const core_1 = __nccwpck_require__(7484); +const exec_1 = __nccwpck_require__(5236); +const io_1 = __nccwpck_require__(4994); +const packageRunner_1 = __nccwpck_require__(7253); /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -35484,12 +35499,12 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const runner = await resolvePackageRunner(); + const runner = await (0, packageRunner_1.resolvePackageRunner)(); const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = await resolvePackageRunner(); + commandLine = await (0, packageRunner_1.resolvePackageRunner)(); args = baseArguments; } try { diff --git a/build/preview-build/index.js b/build/preview-build/index.js index 2ff55eb91..ca6953039 100644 --- a/build/preview-build/index.js +++ b/build/preview-build/index.js @@ -99069,6 +99069,31 @@ async function getPullRequestFromGitCommitShaAsync(options, gitCommitHash) { } +/***/ }), + +/***/ 7253: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.resolvePackageRunner = resolvePackageRunner; +const io_1 = __nccwpck_require__(4994); +/** + * Resolve the package runner to use for executing expo commands. + * Prefers `bunx` if available (works better with bun-managed projects), + * falls back to `npx`. + */ +async function resolvePackageRunner() { + try { + return await (0, io_1.which)('bunx', true); + } + catch { + return 'npx'; + } +} + + /***/ }), /***/ 3497: @@ -99133,19 +99158,7 @@ exports.loadProjectConfig = loadProjectConfig; const core_1 = __nccwpck_require__(7484); const exec_1 = __nccwpck_require__(5236); const io_1 = __nccwpck_require__(4994); -/** - * Resolve the package runner to use for executing expo commands. - * Prefers `bunx` if available (works better with bun-managed projects), - * falls back to `npx`. - */ -async function resolvePackageRunner() { - try { - return await (0, io_1.which)('bunx', true); - } - catch { - return 'npx'; - } -} +const packageRunner_1 = __nccwpck_require__(7253); /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -99158,12 +99171,12 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const runner = await resolvePackageRunner(); + const runner = await (0, packageRunner_1.resolvePackageRunner)(); const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = await resolvePackageRunner(); + commandLine = await (0, packageRunner_1.resolvePackageRunner)(); args = baseArguments; } try { diff --git a/build/preview/index.js b/build/preview/index.js index f2fcc05ca..fcd449c94 100644 --- a/build/preview/index.js +++ b/build/preview/index.js @@ -35525,15 +35525,13 @@ async function getPullRequestFromGitCommitShaAsync(options, gitCommitHash) { /***/ }), -/***/ 4330: +/***/ 7253: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.loadProjectConfig = loadProjectConfig; -const core_1 = __nccwpck_require__(7484); -const exec_1 = __nccwpck_require__(5236); +exports.resolvePackageRunner = resolvePackageRunner; const io_1 = __nccwpck_require__(4994); /** * Resolve the package runner to use for executing expo commands. @@ -35548,6 +35546,21 @@ async function resolvePackageRunner() { return 'npx'; } } + + +/***/ }), + +/***/ 4330: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.loadProjectConfig = loadProjectConfig; +const core_1 = __nccwpck_require__(7484); +const exec_1 = __nccwpck_require__(5236); +const io_1 = __nccwpck_require__(4994); +const packageRunner_1 = __nccwpck_require__(7253); /** * Load the Expo app project config in the given directory. * This runs `expo config` command instead of using `@expo/config` directly, @@ -35560,12 +35573,12 @@ async function loadProjectConfig(cwd, easEnvironment) { let args; if (easEnvironment) { commandLine = await (0, io_1.which)('eas', true); - const runner = await resolvePackageRunner(); + const runner = await (0, packageRunner_1.resolvePackageRunner)(); const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', easEnvironment, `"${commandToExecute}"`]; } else { - commandLine = await resolvePackageRunner(); + commandLine = await (0, packageRunner_1.resolvePackageRunner)(); args = baseArguments; } try { diff --git a/src/fingerprintUtils.ts b/src/fingerprintUtils.ts index 1a5649d58..2fd2efb73 100644 --- a/src/fingerprintUtils.ts +++ b/src/fingerprintUtils.ts @@ -3,6 +3,7 @@ import { getExecOutput } from '@actions/exec'; import { which } from '@actions/io'; import { BuildInfo, BuildStatus } from './expo'; +import { resolvePackageRunner } from './packageRunner'; export async function getBuildInfoForCurrentFingerprintAsync({ platform, @@ -68,10 +69,11 @@ async function getFingerprintHashForPlatformAsync({ let args: string[]; if (environment) { commandLine = await which('eas', true); - const commandToExecute = ['npx', ...baseArguments].join(' ').replace(/"/g, '\\"'); + const runner = await resolvePackageRunner(); + const commandToExecute = [runner, ...baseArguments].join(' ').replace(/"/g, '\\"'); args = ['env:exec', '--non-interactive', environment, `"${commandToExecute}"`]; } else { - commandLine = 'npx'; + commandLine = await resolvePackageRunner(); args = baseArguments; } diff --git a/src/packageRunner.ts b/src/packageRunner.ts new file mode 100644 index 000000000..2ac66e9ab --- /dev/null +++ b/src/packageRunner.ts @@ -0,0 +1,14 @@ +import { which } from '@actions/io'; + +/** + * Resolve the package runner to use for executing expo commands. + * Prefers `bunx` if available (works better with bun-managed projects), + * falls back to `npx`. + */ +export async function resolvePackageRunner(): Promise { + try { + return await which('bunx', true); + } catch { + return 'npx'; + } +} diff --git a/src/project.ts b/src/project.ts index aa9257bca..8c4779dea 100644 --- a/src/project.ts +++ b/src/project.ts @@ -3,18 +3,7 @@ import { getExecOutput } from '@actions/exec'; import { which } from '@actions/io'; import { ExpoConfig } from '@expo/config'; -/** - * Resolve the package runner to use for executing expo commands. - * Prefers `bunx` if available (works better with bun-managed projects), - * falls back to `npx`. - */ -async function resolvePackageRunner(): Promise { - try { - return await which('bunx', true); - } catch { - return 'npx'; - } -} +import { resolvePackageRunner } from './packageRunner'; /** * Load the Expo app project config in the given directory.