Skip to content
This repository was archived by the owner on May 1, 2026. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand Down Expand Up @@ -100,6 +101,70 @@ 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

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
}

/**
* 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)))

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 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 you do, 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)
}
Expand Down Expand Up @@ -1066,6 +1131,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)
Expand Down
Loading