Skip to content

Commit 51865fd

Browse files
committed
refactor: extract performEarlyInit to deduplicate config+auth logic
The sandbox and non-relaunch code paths had identical ~40-line blocks for loadCliConfig, refreshAuth, getRemoteAdminSettings, and runDeferredCommand. Extract into performEarlyInit() which returns { partialConfig, authFailed } so callers can choose their error handling strategy. Behavioral change: the else block (SANDBOX env / command mode) now tracks authFailed (previously it silently swallowed auth errors). This is safe because the fallback path at line ~507 handles auth independently — the early failure just means the pre-init attempt didn't succeed.
1 parent 0370de7 commit 51865fd

1 file changed

Lines changed: 55 additions & 109 deletions

File tree

packages/cli/src/gemini.tsx

Lines changed: 55 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -357,115 +357,7 @@ export async function main() {
357357
? getNodeMemoryArgs(isDebugMode)
358358
: [];
359359

360-
if (!process.env['SANDBOX'] && !argv.isCommand) {
361-
const sandboxConfig = await loadSandboxConfig(settings.merged, argv);
362-
363-
if (sandboxConfig) {
364-
// Sandbox path: needs full config + auth before entering sandbox because
365-
// the sandbox will interfere with the OAuth2 web redirect.
366-
const partialConfig = await loadCliConfig(
367-
settings.merged,
368-
sessionId,
369-
argv,
370-
{
371-
projectHooks: settings.workspace.settings.hooks,
372-
},
373-
);
374-
adminControlsListner.setConfig(partialConfig);
375-
376-
let initialAuthFailed = false;
377-
if (!settings.merged.security.auth.useExternal) {
378-
try {
379-
if (
380-
partialConfig.isInteractive() &&
381-
settings.merged.security.auth.selectedType
382-
) {
383-
const err = validateAuthMethod(
384-
settings.merged.security.auth.selectedType,
385-
);
386-
if (err) {
387-
throw new Error(err);
388-
}
389-
390-
await partialConfig.refreshAuth(
391-
settings.merged.security.auth.selectedType,
392-
);
393-
} else if (!partialConfig.isInteractive()) {
394-
const authType = await validateNonInteractiveAuth(
395-
settings.merged.security.auth.selectedType,
396-
settings.merged.security.auth.useExternal,
397-
partialConfig,
398-
settings,
399-
);
400-
await partialConfig.refreshAuth(authType);
401-
}
402-
} catch (err) {
403-
if (err instanceof ValidationCancelledError) {
404-
await runExitCleanup();
405-
process.exit(ExitCodes.SUCCESS);
406-
}
407-
408-
if (!(err instanceof ValidationRequiredError)) {
409-
debugLogger.error('Error authenticating:', err);
410-
initialAuthFailed = true;
411-
}
412-
}
413-
}
414-
415-
const remoteAdminSettings = partialConfig.getRemoteAdminSettings();
416-
if (remoteAdminSettings) {
417-
settings.setRemoteAdminSettings(remoteAdminSettings);
418-
}
419-
420-
await runDeferredCommand(settings.merged);
421-
422-
if (initialAuthFailed) {
423-
await runExitCleanup();
424-
process.exit(ExitCodes.FATAL_AUTHENTICATION_ERROR);
425-
}
426-
let stdinData = '';
427-
if (!process.stdin.isTTY) {
428-
stdinData = await readStdin();
429-
}
430-
431-
// This function is a copy of the one from sandbox.ts
432-
// It is moved here to decouple sandbox.ts from the CLI's argument structure.
433-
const injectStdinIntoArgs = (
434-
args: string[],
435-
stdinData?: string,
436-
): string[] => {
437-
const finalArgs = [...args];
438-
if (stdinData) {
439-
const promptIndex = finalArgs.findIndex(
440-
(arg) => arg === '--prompt' || arg === '-p',
441-
);
442-
if (promptIndex > -1 && finalArgs.length > promptIndex + 1) {
443-
finalArgs[promptIndex + 1] =
444-
`${stdinData}\n\n${finalArgs[promptIndex + 1]}`;
445-
} else {
446-
finalArgs.push('--prompt', stdinData);
447-
}
448-
}
449-
return finalArgs;
450-
};
451-
452-
const sandboxArgs = injectStdinIntoArgs(process.argv, stdinData);
453-
454-
await relaunchOnExitCode(() =>
455-
start_sandbox(sandboxConfig, memoryArgs, partialConfig, sandboxArgs),
456-
);
457-
await runExitCleanup();
458-
process.exit(ExitCodes.SUCCESS);
459-
} else {
460-
// Non-sandbox path: skip loadCliConfig + refreshAuth entirely.
461-
// The child process handles all initialization on its own.
462-
// This eliminates ~500-1000ms of duplicated work (extensions loading,
463-
// hierarchical memory search, policy engine, and 3-5 network calls).
464-
await relaunchAppInChildProcess(memoryArgs, []);
465-
}
466-
} else {
467-
// Non-relaunch path (sandbox env or command mode): auth is needed here
468-
// because we won't be relaunching.
360+
async function performEarlyInit() {
469361
const partialConfig = await loadCliConfig(
470362
settings.merged,
471363
sessionId,
@@ -476,6 +368,7 @@ export async function main() {
476368
);
477369
adminControlsListner.setConfig(partialConfig);
478370

371+
let authFailed = false;
479372
if (!settings.merged.security.auth.useExternal && !argv.isCommand) {
480373
try {
481374
if (
@@ -509,6 +402,7 @@ export async function main() {
509402

510403
if (!(err instanceof ValidationRequiredError)) {
511404
debugLogger.error('Error authenticating:', err);
405+
authFailed = true;
512406
}
513407
}
514408
}
@@ -519,6 +413,58 @@ export async function main() {
519413
}
520414

521415
await runDeferredCommand(settings.merged);
416+
417+
return { partialConfig, authFailed };
418+
}
419+
420+
if (!process.env['SANDBOX'] && !argv.isCommand) {
421+
const sandboxConfig = await loadSandboxConfig(settings.merged, argv);
422+
423+
if (sandboxConfig) {
424+
const { partialConfig, authFailed } = await performEarlyInit();
425+
426+
if (authFailed) {
427+
await runExitCleanup();
428+
process.exit(ExitCodes.FATAL_AUTHENTICATION_ERROR);
429+
}
430+
let stdinData = '';
431+
if (!process.stdin.isTTY) {
432+
stdinData = await readStdin();
433+
}
434+
435+
// This function is a copy of the one from sandbox.ts
436+
// It is moved here to decouple sandbox.ts from the CLI's argument structure.
437+
const injectStdinIntoArgs = (
438+
args: string[],
439+
stdinData?: string,
440+
): string[] => {
441+
const finalArgs = [...args];
442+
if (stdinData) {
443+
const promptIndex = finalArgs.findIndex(
444+
(arg) => arg === '--prompt' || arg === '-p',
445+
);
446+
if (promptIndex > -1 && finalArgs.length > promptIndex + 1) {
447+
finalArgs[promptIndex + 1] =
448+
`${stdinData}\n\n${finalArgs[promptIndex + 1]}`;
449+
} else {
450+
finalArgs.push('--prompt', stdinData);
451+
}
452+
}
453+
return finalArgs;
454+
};
455+
456+
const sandboxArgs = injectStdinIntoArgs(process.argv, stdinData);
457+
458+
await relaunchOnExitCode(() =>
459+
start_sandbox(sandboxConfig, memoryArgs, partialConfig, sandboxArgs),
460+
);
461+
await runExitCleanup();
462+
process.exit(ExitCodes.SUCCESS);
463+
} else {
464+
await relaunchAppInChildProcess(memoryArgs, []);
465+
}
466+
} else {
467+
await performEarlyInit();
522468
}
523469

524470
// We are now past the logic handling potentially launching a child process

0 commit comments

Comments
 (0)