@@ -361,62 +361,148 @@ fi
361361echo -e " ${BOLD} Required${RESET} ${DIM} (agent won't start without these)${RESET} "
362362echo " "
363363
364- # LLM provider picker
365- echo -e " ${BOLD} LLM provider${RESET} "
366- LLM_CHOICE= " $( ui_choose " Choose your primary LLM provider:" \
367- " Anthropic" \
368- " OpenAI" \
369- " Gemini" \
370- " OpenCode Zen" ) "
371-
372- case " $LLM_CHOICE " in
373- " Anthropic" )
374- prompt_secret " ANTHROPIC_API_KEY" \
375- " Anthropic API key" \
376- " https://console.anthropic.com/settings/keys" \
377- " required" \
378- " sk-ant-"
379- ;;
380- " OpenAI" )
381- prompt_secret " OPENAI_API_KEY" \
382- " OpenAI API key" \
383- " https://platform.openai.com/api-keys" \
384- " required" \
385- " sk-"
386- ;;
387- " Gemini" )
388- prompt_secret " GEMINI_API_KEY" \
389- " Google Gemini API key" \
390- " https://aistudio.google.com/apikey" \
391- " required"
392- ;;
393- " OpenCode Zen" )
394- prompt_secret " OPENCODE_ZEN_API_KEY" \
395- " OpenCode Zen API key (multi-provider router)" \
396- " https://opencode.ai" \
397- " required"
398- ;;
399- esac
364+ # LLM authentication tier
365+ echo -e " ${BOLD} LLM authentication${RESET} "
366+ LLM_AUTH_TIER= " $( ui_choose " How would you like to authenticate with your LLM?" \
367+ " API key" \
368+ " Subscription login (OAuth)" ) "
369+
370+ USED_SUBSCRIPTION_LOGIN= false
371+
372+ if [ " $LLM_AUTH_TIER " = " API key" ]; then
373+ # ── API key path ──
374+ echo " "
375+ LLM_CHOICE=" $( ui_choose " Choose your primary LLM provider:" \
376+ " Anthropic" \
377+ " OpenAI" \
378+ " Gemini" \
379+ " OpenCode Zen" ) "
380+
381+ case " $LLM_CHOICE " in
382+ " Anthropic" )
383+ prompt_secret " ANTHROPIC_API_KEY" \
384+ " Anthropic API key" \
385+ " https://console.anthropic.com/settings/keys" \
386+ " required" \
387+ " sk-ant-"
388+ ;;
389+ " OpenAI" )
390+ prompt_secret " OPENAI_API_KEY" \
391+ " OpenAI API key" \
392+ " https://platform.openai.com/api-keys" \
393+ " required" \
394+ " sk-"
395+ ;;
396+ " Gemini" )
397+ prompt_secret " GEMINI_API_KEY" \
398+ " Google Gemini API key" \
399+ " https://aistudio.google.com/apikey" \
400+ " required"
401+ ;;
402+ " OpenCode Zen" )
403+ prompt_secret " OPENCODE_ZEN_API_KEY" \
404+ " OpenCode Zen API key (multi-provider router)" \
405+ " https://opencode.ai" \
406+ " required"
407+ ;;
408+ esac
400409
401- SELECTED_LLM_KEY= " "
402- case " $LLM_CHOICE " in
403- " Anthropic" ) SELECTED_LLM_KEY=" ANTHROPIC_API_KEY" ;;
404- " OpenAI" ) SELECTED_LLM_KEY=" OPENAI_API_KEY" ;;
405- " Gemini" ) SELECTED_LLM_KEY=" GEMINI_API_KEY" ;;
406- " OpenCode Zen" ) SELECTED_LLM_KEY=" OPENCODE_ZEN_API_KEY" ;;
407- esac
410+ SELECTED_LLM_KEY=" "
411+ case " $LLM_CHOICE " in
412+ " Anthropic" ) SELECTED_LLM_KEY=" ANTHROPIC_API_KEY" ;;
413+ " OpenAI" ) SELECTED_LLM_KEY=" OPENAI_API_KEY" ;;
414+ " Gemini" ) SELECTED_LLM_KEY=" GEMINI_API_KEY" ;;
415+ " OpenCode Zen" ) SELECTED_LLM_KEY=" OPENCODE_ZEN_API_KEY" ;;
416+ esac
408417
409- if [ -z " ${ENV_VARS[$SELECTED_LLM_KEY]:- } " ]; then
410- echo " ❌ $SELECTED_LLM_KEY is required for selected provider '$LLM_CHOICE '"
411- exit 1
412- fi
418+ if [ -z " ${ENV_VARS[$SELECTED_LLM_KEY]:- } " ]; then
419+ echo " ❌ $SELECTED_LLM_KEY is required for selected provider '$LLM_CHOICE '"
420+ exit 1
421+ fi
413422
414- # Keep only selected provider key for deterministic config.
415- for key in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY; do
416- if [ " $key " != " $SELECTED_LLM_KEY " ]; then
417- unset " ENV_VARS[$key ]"
423+ # Keep only selected provider key for deterministic config.
424+ for key in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY; do
425+ if [ " $key " != " $SELECTED_LLM_KEY " ]; then
426+ unset " ENV_VARS[$key ]"
427+ fi
428+ done
429+
430+ else
431+ # ── Subscription login (OAuth) path ──
432+ clear_keys ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY
433+ LLM_CHOICE=" Subscription"
434+ SELECTED_LLM_KEY=" "
435+
436+ # Resolve the agent home for auth.json
437+ BAUDBOT_HOME=" ${BAUDBOT_HOME:-/ home/ baudbot_agent} "
438+ AUTH_JSON=" $BAUDBOT_HOME /.pi/agent/auth.json"
439+
440+ # Find Node.js for oauth-login.mjs
441+ OAUTH_SCRIPT=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) /oauth-login.mjs"
442+ OAUTH_NODE_BIN=" "
443+ if [ -f " $SCRIPT_DIR /../bin/lib/runtime-node.sh" ]; then
444+ # shellcheck source=bin/lib/runtime-node.sh
445+ source " $SCRIPT_DIR /../bin/lib/runtime-node.sh" 2> /dev/null || true
446+ OAUTH_NODE_BIN=" $( bb_resolve_runtime_node_bin " $BAUDBOT_HOME " 2> /dev/null || true) "
447+ fi
448+ if [ -z " $OAUTH_NODE_BIN " ] || [ ! -x " $OAUTH_NODE_BIN " ]; then
449+ OAUTH_NODE_BIN=" $( command -v node 2> /dev/null || true) "
450+ fi
451+
452+ if [ ! -f " $OAUTH_SCRIPT " ]; then
453+ echo " ❌ oauth-login.mjs not found at $OAUTH_SCRIPT "
454+ exit 1
455+ fi
456+ if [ -z " $OAUTH_NODE_BIN " ]; then
457+ echo " ❌ Node.js not found — required for OAuth login"
458+ exit 1
418459 fi
419- done
460+
461+ # Check for existing OAuth credentials
462+ HAS_EXISTING_OAUTH=false
463+ EXISTING_OAUTH_PROVIDER=" "
464+ if [ -f " $AUTH_JSON " ] && command -v jq & > /dev/null; then
465+ for op in " openai-codex" " anthropic" ; do
466+ if jq -e --arg p " $op " ' .[$p]' " $AUTH_JSON " & > /dev/null; then
467+ HAS_EXISTING_OAUTH=true
468+ EXISTING_OAUTH_PROVIDER=" $op "
469+ break
470+ fi
471+ done
472+ fi
473+
474+ if [ " $HAS_EXISTING_OAUTH " = true ]; then
475+ info " Existing OAuth credentials found ($EXISTING_OAUTH_PROVIDER )."
476+ if ! ui_confirm " Re-authenticate with a different provider?" false ; then
477+ info " Keeping existing OAuth credentials."
478+ USED_SUBSCRIPTION_LOGIN=true
479+ fi
480+ fi
481+
482+ if [ " $USED_SUBSCRIPTION_LOGIN " = false ]; then
483+ echo " "
484+ dim " This will open an OAuth flow. You'll get a URL to open in your browser."
485+ echo " "
486+
487+ # Run oauth-login.mjs interactively
488+ OAUTH_PROVIDER_ID=" "
489+ if OAUTH_PROVIDER_ID=$( " $OAUTH_NODE_BIN " " $OAUTH_SCRIPT " --auth-path " $AUTH_JSON " ) ; then
490+ OAUTH_PROVIDER_ID=" $( echo " $OAUTH_PROVIDER_ID " | tr -d ' [:space:]' ) "
491+ info " ✓ OAuth login complete ($OAUTH_PROVIDER_ID )"
492+
493+ # Fix ownership if running as root
494+ if [ " $( id -u) " -eq 0 ] && id baudbot_agent & > /dev/null; then
495+ chown baudbot_agent:baudbot_agent " $AUTH_JSON "
496+ # Also fix parent dirs
497+ chown baudbot_agent:baudbot_agent " $( dirname " $AUTH_JSON " ) " 2> /dev/null || true
498+ fi
499+ else
500+ echo " ❌ OAuth login failed"
501+ exit 1
502+ fi
503+ USED_SUBSCRIPTION_LOGIN=true
504+ fi
505+ fi
420506
421507echo " "
422508
@@ -655,7 +741,12 @@ VAR_COUNT=$(grep -c '=' "$CONFIG_FILE")
655741info " Wrote $VAR_COUNT variables to $CONFIG_FILE "
656742echo " "
657743echo -e " ${BOLD} Summary${RESET} "
658- echo -e " LLM provider: ${BOLD}${LLM_CHOICE}${RESET} "
744+ echo -e " LLM auth: ${BOLD}${LLM_AUTH_TIER}${RESET} "
745+ if [ " $LLM_AUTH_TIER " = " API key" ]; then
746+ echo -e " LLM provider: ${BOLD}${LLM_CHOICE}${RESET} "
747+ else
748+ echo -e " LLM provider: ${BOLD} Subscription (OAuth via auth.json)${RESET} "
749+ fi
659750echo -e " Slack mode: ${BOLD}${SLACK_CHOICE}${RESET} "
660751if [ " $SLACK_CHOICE " = " Use baudbot.ai Slack integration (easy)" ]; then
661752 echo -e " ${DIM} Next: run 'sudo baudbot broker register' after install${RESET} "
0 commit comments