Skip to content

Commit 08f9657

Browse files
committed
feat: bt setup can be interactive even when launched in a script
example echo 'bt setup' | sh
1 parent e6dbbe2 commit 08f9657

1 file changed

Lines changed: 22 additions & 12 deletions

File tree

src/setup/mod.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::collections::BTreeSet;
22
use std::fs;
3-
use std::io::BufRead as _;
3+
use std::io::{BufRead as _, IsTerminal};
44
use std::path::{Path, PathBuf};
55
use std::process::Stdio;
66

@@ -737,19 +737,27 @@ async fn run_setup_wizard(mut base: BaseArgs, flags: WizardFlags) -> Result<()>
737737
// Skills, docs, and the task file are always set up when a git root exists.
738738
// Only the agent launch is conditional.
739739
{
740-
// Determine agent: explicit flag > single detected > ask user
740+
// Determine agent: explicit flag > ask user (when terminal available) > auto-detect
741741
let instrument_agent =
742742
determine_wizard_instrument_agent(flag_agent, git_root.as_deref(), &home);
743743

744744
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
751752
} 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+
}
753761
};
754762
let default = pick_agent_mode_target(&candidates).unwrap_or(Agent::Claude);
755763
let selected = prompt_instrument_agent(default)?;
@@ -809,7 +817,10 @@ async fn run_setup_wizard(mut base: BaseArgs, flags: WizardFlags) -> Result<()>
809817
.interact()?;
810818
idx == 0
811819
} 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()
813824
};
814825
let yolo = if flag_yolo {
815826
true
@@ -1310,7 +1321,6 @@ impl LanguageArg {
13101321

13111322
fn should_prompt_setup_action(base: &BaseArgs, args: &AgentsSetupArgs) -> bool {
13121323
!base.json
1313-
&& ui::is_interactive()
13141324
&& !args.no_fetch_docs
13151325
&& !args.refresh_docs
13161326
&& args.workers == crate::sync::default_workers()
@@ -1861,7 +1871,7 @@ fn prompt_instrument_agent(default_agent: Agent) -> Result<Agent> {
18611871
.position(|agent| *agent == default_agent)
18621872
.unwrap_or(0);
18631873
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.")
18651875
.items(&choices)
18661876
.default(default_index)
18671877
.interact_opt()?;

0 commit comments

Comments
 (0)