|
1 | 1 | use std::collections::BTreeSet; |
2 | 2 | use std::fs; |
3 | | -use std::io::BufRead as _; |
| 3 | +use std::io::{BufRead as _, IsTerminal}; |
4 | 4 | use std::path::{Path, PathBuf}; |
5 | 5 | use std::process::Stdio; |
6 | 6 |
|
@@ -737,19 +737,27 @@ async fn run_setup_wizard(mut base: BaseArgs, flags: WizardFlags) -> Result<()> |
737 | 737 | // Skills, docs, and the task file are always set up when a git root exists. |
738 | 738 | // Only the agent launch is conditional. |
739 | 739 | { |
740 | | - // Determine agent: explicit flag > single detected > ask user |
| 740 | + // Determine agent: explicit flag > ask user (when terminal available) > auto-detect |
741 | 741 | let instrument_agent = |
742 | 742 | determine_wizard_instrument_agent(flag_agent, git_root.as_deref(), &home); |
743 | 743 |
|
744 | 744 | let instrument_agent = |
745 | | - if launch_agent && instrument_agent.is_none() && ui::is_interactive() { |
746 | | - // Multiple or zero detected agents — ask the user |
747 | | - let detected2 = detect_agents(git_root.as_deref(), &home); |
748 | | - let detected_set: BTreeSet<Agent> = detected2.iter().map(|s| s.agent).collect(); |
749 | | - let candidates: Vec<Agent> = if detected_set.is_empty() { |
750 | | - ALL_AGENTS.to_vec() |
| 745 | + if launch_agent && flag_agent.is_none() && std::io::stderr().is_terminal() { |
| 746 | + // No explicit --agent flag and we have a terminal — always ask the user. |
| 747 | + // console reads input from /dev/tty when stdin is piped, so this works |
| 748 | + // even when bt is launched from a shell script (e.g. echo "bt setup" | sh). |
| 749 | + let runnable = detect_runnable_agents(); |
| 750 | + let candidates: Vec<Agent> = if !runnable.is_empty() { |
| 751 | + runnable |
751 | 752 | } else { |
752 | | - detected_set.into_iter().collect() |
| 753 | + let detected2 = detect_agents(git_root.as_deref(), &home); |
| 754 | + let detected_set: BTreeSet<Agent> = |
| 755 | + detected2.iter().map(|s| s.agent).collect(); |
| 756 | + if detected_set.is_empty() { |
| 757 | + ALL_AGENTS.to_vec() |
| 758 | + } else { |
| 759 | + detected_set.into_iter().collect() |
| 760 | + } |
753 | 761 | }; |
754 | 762 | let default = pick_agent_mode_target(&candidates).unwrap_or(Agent::Claude); |
755 | 763 | let selected = prompt_instrument_agent(default)?; |
@@ -809,7 +817,10 @@ async fn run_setup_wizard(mut base: BaseArgs, flags: WizardFlags) -> Result<()> |
809 | 817 | .interact()?; |
810 | 818 | idx == 0 |
811 | 819 | } else { |
812 | | - true |
| 820 | + // Default to TUI when the agent was explicitly chosen (user expects it) |
| 821 | + // or when a terminal is available. Fall back to background only when |
| 822 | + // auto-selecting an agent in a fully headless environment. |
| 823 | + flag_agent.is_some() || std::io::stderr().is_terminal() |
813 | 824 | }; |
814 | 825 | let yolo = if flag_yolo { |
815 | 826 | true |
@@ -1310,7 +1321,6 @@ impl LanguageArg { |
1310 | 1321 |
|
1311 | 1322 | fn should_prompt_setup_action(base: &BaseArgs, args: &AgentsSetupArgs) -> bool { |
1312 | 1323 | !base.json |
1313 | | - && ui::is_interactive() |
1314 | 1324 | && !args.no_fetch_docs |
1315 | 1325 | && !args.refresh_docs |
1316 | 1326 | && args.workers == crate::sync::default_workers() |
@@ -1861,7 +1871,7 @@ fn prompt_instrument_agent(default_agent: Agent) -> Result<Agent> { |
1861 | 1871 | .position(|agent| *agent == default_agent) |
1862 | 1872 | .unwrap_or(0); |
1863 | 1873 | let selection = FuzzySelect::with_theme(&ColorfulTheme::default()) |
1864 | | - .with_prompt("Select agent to instrument this repo") |
| 1874 | + .with_prompt("Select an agent to instrument this repo. This agent must already be installed, and will run in the current folder to install the Braintrust SDK.") |
1865 | 1875 | .items(&choices) |
1866 | 1876 | .default(default_index) |
1867 | 1877 | .interact_opt()?; |
|
0 commit comments