diff --git a/crates/tangled-cli/src/cli.rs b/crates/tangled-cli/src/cli.rs index 2c71f9b..efe9fd1 100644 --- a/crates/tangled-cli/src/cli.rs +++ b/crates/tangled-cli/src/cli.rs @@ -381,7 +381,7 @@ pub struct SpindleSecretAddArgs { /// Secret key #[arg(long)] pub key: String, - /// Secret value + /// Secret value (use '@filename' to read from file, '-' to read from stdin) #[arg(long)] pub value: String, } diff --git a/crates/tangled-cli/src/commands/spindle.rs b/crates/tangled-cli/src/commands/spindle.rs index 37e5cc2..e03f48c 100644 --- a/crates/tangled-cli/src/commands/spindle.rs +++ b/crates/tangled-cli/src/commands/spindle.rs @@ -250,7 +250,32 @@ async fn secret_add(args: SpindleSecretAddArgs) -> Result<()> { .unwrap_or_else(|| "https://spindle.tangled.sh".to_string()); let api = tangled_api::TangledClient::new(&spindle_base); - api.add_repo_secret(&pds, &session.access_jwt, &repo_at, &args.key, &args.value) + // Handle special value patterns: @file or - (stdin) + let value = if args.value == "-" { + // Read from stdin + use std::io::Read; + let mut buffer = String::new(); + std::io::stdin().read_to_string(&mut buffer)?; + buffer + } else if let Some(path) = args.value.strip_prefix('@') { + // Read from file, expand ~ if needed + let expanded_path = if path.starts_with("~/") { + if let Some(home) = std::env::var("HOME").ok() { + path.replacen("~/", &format!("{}/", home), 1) + } else { + path.to_string() + } + } else { + path.to_string() + }; + std::fs::read_to_string(&expanded_path) + .map_err(|e| anyhow!("Failed to read file '{}': {}", expanded_path, e))? + } else { + // Use value as-is + args.value + }; + + api.add_repo_secret(&pds, &session.access_jwt, &repo_at, &args.key, &value) .await?; println!("Added secret '{}' to {}", args.key, args.repo); Ok(())