From 4175bf904206f275b24e7f1d97da7142f1dc4bfa Mon Sep 17 00:00:00 2001 From: Martin Donadieu Date: Fri, 30 Jan 2026 01:27:37 +0000 Subject: [PATCH 1/2] Warn when onboarding outside Capacitor root --- src/init.ts | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/init.ts b/src/init.ts index f1a11c1b..f498e15a 100644 --- a/src/init.ts +++ b/src/init.ts @@ -3,7 +3,7 @@ import type { Options } from './api/app' import type { Organization } from './utils' import { execSync, spawnSync } from 'node:child_process' import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs' -import { join } from 'node:path' +import path, { dirname, join } from 'node:path' import { cwd, env, exit, platform } from 'node:process' import { cancel as pCancel, confirm as pConfirm, intro as pIntro, isCancel as pIsCancel, log as pLog, outro as pOutro, select as pSelect, spinner as pSpinner, text as pText } from '@clack/prompts' import { format, increment, lessThan, parse } from '@std/semver' @@ -26,6 +26,7 @@ const codeInject = 'CapacitorUpdater.notifyAppReady()' const regexImport = /import.*from.*/g const defaultChannel = 'production' const execOption = { stdio: 'pipe' } +const capacitorConfigFiles = ['capacitor.config.ts', 'capacitor.config.js', 'capacitor.config.json'] let tmpObject: tmp.FileResult['name'] | undefined let globalPathToPackageJson: string | undefined @@ -100,6 +101,64 @@ async function cancelCommand(command: boolean | symbol, orgId: string, apikey: s } } +function findNearestCapacitorConfig(startDir: string) { + let currentDir = startDir + const rootDir = path.parse(currentDir).root + + while (true) { + for (const file of capacitorConfigFiles) { + const candidate = join(currentDir, file) + if (existsSync(candidate)) + return { dir: currentDir, file: candidate } + } + + if (currentDir === rootDir) + break + + const parent = dirname(currentDir) + if (parent === currentDir) + break + currentDir = parent + } + + return undefined +} + +async function warnIfNotInCapacitorRoot() { + const currentDir = cwd() + const configHere = capacitorConfigFiles.some(file => existsSync(join(currentDir, file))) + + if (configHere) + return + + const nearest = findNearestCapacitorConfig(currentDir) + + pLog.warn('Capacitor config not found in the current folder.') + if (nearest) { + pLog.info(`Found a capacitor config at: ${nearest.file}`) + pLog.info(`You are currently in: ${currentDir}`) + } + else { + pLog.info('No capacitor config was found in this folder or any parent directories.') + } + + const pathSegments = currentDir.split(path.sep).filter(Boolean) + if (pathSegments.includes('ios') || pathSegments.includes('android')) { + pLog.info('It looks like you are inside a platform folder (ios/android).') + pLog.info('Try running the onboarding from the project root (the folder with capacitor.config.*).') + } + + const continueAnyway = await pConfirm({ + message: 'Are you sure you want to continue? If that happens, the auto-configuration will probably not work from here.', + initialValue: false, + }) + + if (pIsCancel(continueAnyway) || !continueAnyway) { + pCancel('Operation cancelled.') + exit(1) + } +} + async function markStep(orgId: string, apikey: string, step: string, appId: string) { return markSnag('onboarding-v2', orgId, apikey, `onboarding-step-${step}`, appId) } @@ -1066,6 +1125,7 @@ async function testCapgoUpdateStep(orgId: string, apikey: string, appId: string, export async function initApp(apikeyCommand: string, appId: string, options: SuperOptions) { const pm = getPMAndCommand() pIntro(`Capgo onboarding 🛫`) + await warnIfNotInCapacitorRoot() await checkAlerts() const extConfig = (!options.supaAnon || !options.supaHost) From dfd87ca9edfd44ab30da1b37438670d8b510bdf1 Mon Sep 17 00:00:00 2001 From: Martin Donadieu Date: Fri, 30 Jan 2026 06:01:33 +0000 Subject: [PATCH 2/2] Tighten onboarding root warning --- src/init.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/init.ts b/src/init.ts index f498e15a..2d0da410 100644 --- a/src/init.ts +++ b/src/init.ts @@ -101,6 +101,9 @@ async function cancelCommand(command: boolean | symbol, orgId: string, apikey: s } } +/** + * Find the nearest Capacitor config file by walking up the directory tree. + */ function findNearestCapacitorConfig(startDir: string) { let currentDir = startDir const rootDir = path.parse(currentDir).root @@ -124,6 +127,9 @@ function findNearestCapacitorConfig(startDir: string) { return undefined } +/** + * Warn and optionally stop if onboarding is started outside the Capacitor project root. + */ async function warnIfNotInCapacitorRoot() { const currentDir = cwd() const configHere = capacitorConfigFiles.some(file => existsSync(join(currentDir, file))) @@ -142,14 +148,14 @@ async function warnIfNotInCapacitorRoot() { pLog.info('No capacitor config was found in this folder or any parent directories.') } - const pathSegments = currentDir.split(path.sep).filter(Boolean) - if (pathSegments.includes('ios') || pathSegments.includes('android')) { + const currentFolder = path.basename(currentDir) + if (currentFolder === 'ios' || currentFolder === 'android') { pLog.info('It looks like you are inside a platform folder (ios/android).') pLog.info('Try running the onboarding from the project root (the folder with capacitor.config.*).') } const continueAnyway = await pConfirm({ - message: 'Are you sure you want to continue? If that happens, the auto-configuration will probably not work from here.', + message: 'Are you sure you want to continue? If you do, the auto-configuration will probably not work from here.', initialValue: false, })