File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -261,6 +261,9 @@ pub fn login() {
261261 // Check if already authenticated
262262 if is_already_signed_in ( & profile_config) {
263263 println ! ( "{}" , "You are already signed in." . green( ) ) ;
264+ if !crate :: util:: is_interactive ( ) {
265+ return ;
266+ }
264267 print ! ( "Do you want to log in again? [y/N] " ) ;
265268 use std:: io:: Write ;
266269 std:: io:: stdout ( ) . flush ( ) . unwrap ( ) ;
Original file line number Diff line number Diff line change @@ -260,6 +260,15 @@ fn walk_auth(schema: &Value) -> Map<String, Value> {
260260// ── Entry point ───────────────────────────────────────────────────────────────
261261
262262pub fn run ( workspace_id : & str ) {
263+ if !crate :: util:: is_interactive ( ) {
264+ eprintln ! (
265+ "error: 'connections new' is interactive and stdin is not a TTY. \
266+ Use 'hotdata connections create list' to discover types and their config schemas, \
267+ then 'hotdata connections create --name <n> --type <t> --config '{{…}}''."
268+ ) ;
269+ std:: process:: exit ( 1 ) ;
270+ }
271+
263272 let api = ApiClient :: new ( Some ( workspace_id) ) ;
264273
265274 // Phase 1: Select connection type
Original file line number Diff line number Diff line change @@ -46,6 +46,10 @@ struct Cli {
4646 #[ arg( long, global = true , hide = true ) ]
4747 debug : bool ,
4848
49+ /// Disable interactive prompts; commands that need input will error instead
50+ #[ arg( long = "no-input" , global = true ) ]
51+ no_input : bool ,
52+
4953 #[ command( subcommand) ]
5054 command : Option < Commands > ,
5155}
@@ -134,6 +138,9 @@ fn main() {
134138 if cli. debug {
135139 util:: set_debug ( true ) ;
136140 }
141+ if cli. no_input {
142+ util:: set_no_input ( true ) ;
143+ }
137144
138145 let skip_skill_auto_update =
139146 cli. command . is_none ( ) || matches ! ( & cli. command, Some ( Commands :: Skills { .. } ) ) ;
Original file line number Diff line number Diff line change @@ -13,6 +13,27 @@ pub fn spinner(msg: &str) -> indicatif::ProgressBar {
1313 pb
1414}
1515
16+ static NO_INPUT : AtomicBool = AtomicBool :: new ( false ) ;
17+
18+ pub fn set_no_input ( enabled : bool ) {
19+ NO_INPUT . store ( enabled, Ordering :: Relaxed ) ;
20+ }
21+
22+ /// Returns true if interactive prompts are usable. Returns false when:
23+ /// - the global `--no-input` flag was passed,
24+ /// - the `CI` env var is set (most CI runners set this),
25+ /// - stdin is not a TTY (piped, redirected, or invoked by an agent harness).
26+ pub fn is_interactive ( ) -> bool {
27+ if NO_INPUT . load ( Ordering :: Relaxed ) {
28+ return false ;
29+ }
30+ if std:: env:: var_os ( "CI" ) . is_some ( ) {
31+ return false ;
32+ }
33+ use std:: io:: IsTerminal ;
34+ std:: io:: stdin ( ) . is_terminal ( )
35+ }
36+
1637static DEBUG : AtomicBool = AtomicBool :: new ( false ) ;
1738
1839pub fn set_debug ( enabled : bool ) {
Original file line number Diff line number Diff line change @@ -43,6 +43,14 @@ pub fn set(workspace_id: Option<&str>) {
4343 eprintln ! ( "error: no workspaces available." ) ;
4444 std:: process:: exit ( 1 ) ;
4545 }
46+ if !crate :: util:: is_interactive ( ) {
47+ eprintln ! (
48+ "error: stdin is not a TTY; cannot prompt for selection. \
49+ Run 'hotdata workspaces list' to see available IDs, \
50+ then 'hotdata workspaces set <workspace_id>'."
51+ ) ;
52+ std:: process:: exit ( 1 ) ;
53+ }
4654 let options: Vec < String > = workspaces
4755 . iter ( )
4856 . map ( |w| format ! ( "{} ({})" , w. name, w. public_id) )
You can’t perform that action at this time.
0 commit comments