@@ -29,7 +29,7 @@ import { getAllCredentials } from '../lib/keychain.js';
2929import { installSecretScanningHooks } from '../bootstrap/hooks.js' ;
3030import { loadState , saveState , markAgentConfigured , addInstalledHook } from '../lib/state-manager.js' ;
3131import { runCommand } from '../lib/run-command.js' ;
32- import { version as VERSION } from '../../package.json ' ;
32+ import { VERSION } from '../version.js ' ;
3333import logger from '../lib/logger.js' ;
3434import { SONARCLOUD_URL , SONARCLOUD_HOSTNAME } from '../lib/config-constants.js' ;
3535import { ENV_TOKEN , ENV_SERVER } from '../lib/auth-resolver.js' ;
@@ -255,6 +255,7 @@ async function runHealthCheckAndRepair(
255255 token : string | undefined ,
256256 organization : string | undefined ,
257257 skipHooks : boolean | undefined ,
258+ nonInteractive ?: boolean ,
258259) : Promise < string | undefined > {
259260 text ( '\nPhase 2/3: Health Check & Repair' ) ;
260261 blank ( ) ;
@@ -279,18 +280,26 @@ async function runHealthCheckAndRepair(
279280 text ( ` - ${ msg } ` ) ;
280281 }
281282
283+ if ( nonInteractive && ! healthResult . tokenValid ) {
284+ // Can't repair token without browser interaction — install hooks and continue
285+ if ( ! skipHooks ) {
286+ await installSecretScanningHooks ( projectInfo . root ) ;
287+ }
288+ return token ;
289+ }
290+
282291 // Repair (part of Phase 2)
283292 text ( '\n Running repair...' ) ;
284293
285- await runRepair (
294+ const repairedToken = await runRepair (
286295 serverURL ,
287296 projectInfo . root ,
288297 healthResult ,
289298 projectKey ,
290299 organization ,
291300 ) ;
292301
293- return token ;
302+ return repairedToken ?? token ;
294303}
295304
296305/**
@@ -403,6 +412,8 @@ export async function integrateCommand(agent: string, options: OnboardAgentOptio
403412 if ( ! config . projectKey ) {
404413 text ( '\nNo project key configured.' ) ;
405414 text ( 'Installing secret scanning hooks only.' ) ;
415+ text ( '\nPhase 2/3: Health Check & Repair — skipped (no project key)' ) ;
416+ text ( 'Phase 3/3: Final Verification — skipped (no project key)' ) ;
406417 if ( ! options . skipHooks ) {
407418 await installSecretScanningHooks ( projectInfo . root ) ;
408419 await updateStateAfterConfiguration ( true ) ;
@@ -417,6 +428,11 @@ export async function integrateCommand(agent: string, options: OnboardAgentOptio
417428 // Ensure token is available
418429 let token = await ensureToken ( config . token , serverURL , config . organization ) ;
419430
431+ // When both env vars are set the caller is in a CI/automated context — treat as
432+ // non-interactive so that a bad token never triggers browser-based repair.
433+ const envBasedAuth = ! ! ( process . env [ ENV_TOKEN ] && process . env [ ENV_SERVER ] ) ;
434+ const effectiveNonInteractive = options . nonInteractive || envBasedAuth ;
435+
420436 // Phase 2 & 3: Health Check and Repair
421437 if ( token ) {
422438 token = await runHealthCheckAndRepair (
@@ -426,6 +442,7 @@ export async function integrateCommand(agent: string, options: OnboardAgentOptio
426442 token ,
427443 config . organization ,
428444 options . skipHooks ,
445+ effectiveNonInteractive ,
429446 ) ;
430447
431448 if ( token ) {
@@ -445,6 +462,16 @@ export async function integrateCommand(agent: string, options: OnboardAgentOptio
445462
446463 // If no token, run repair to generate one
447464 if ( ! token ) {
465+ if ( effectiveNonInteractive ) {
466+ // Can't generate token without browser — install hooks only
467+ if ( ! options . skipHooks ) {
468+ await installSecretScanningHooks ( projectInfo . root ) ;
469+ }
470+ await updateStateAfterConfiguration ( ! options . skipHooks ) ;
471+ outro ( 'Setup complete!' , 'success' ) ;
472+ return ;
473+ }
474+
448475 token = await runRepairWithoutToken (
449476 serverURL ,
450477 projectKey ,
0 commit comments