anveesa 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Cargo.lock CHANGED
@@ -54,7 +54,7 @@ dependencies = [
54
54
 
55
55
  [[package]]
56
56
  name = "anveesa"
57
- version = "0.3.2"
57
+ version = "0.3.4"
58
58
  dependencies = [
59
59
  "anyhow",
60
60
  "base64",
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "anveesa"
3
- version = "0.3.2"
3
+ version = "0.3.4"
4
4
  edition = "2024"
5
5
  default-run = "anveesa"
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anveesa",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "A terminal CLI that wraps AI providers (OpenAI-compatible APIs and local CLIs) into a single unified command",
5
5
  "main": "bin/anveesa.js",
6
6
  "bin": {
package/src/config.rs CHANGED
@@ -424,6 +424,10 @@ impl ProviderConfig {
424
424
  pub struct OpenAiCompatibleProviderConfig {
425
425
  pub base_url: String,
426
426
 
427
+ /// Inline API key. Prefer `api_key_env` to avoid storing secrets in the config file.
428
+ #[serde(default, skip_serializing_if = "Option::is_none")]
429
+ pub api_key: Option<String>,
430
+
427
431
  #[serde(default, skip_serializing_if = "Option::is_none")]
428
432
  pub api_key_env: Option<String>,
429
433
 
@@ -477,6 +481,7 @@ fn insert_openai_provider(
477
481
  name.to_string(),
478
482
  ProviderConfig::OpenAiCompatible(OpenAiCompatibleProviderConfig {
479
483
  base_url: base_url.to_string(),
484
+ api_key: None,
480
485
  api_key_env: api_key_env.map(str::to_string),
481
486
  default_model: None,
482
487
  headers: BTreeMap::new(),
package/src/lib.rs CHANGED
@@ -1389,6 +1389,24 @@ impl PromptBuffer {
1389
1389
  self.segments.pop();
1390
1390
  }
1391
1391
  }
1392
+
1393
+ /// Ctrl+U / Cmd+Delete — erase the entire line.
1394
+ fn clear_all(&mut self) {
1395
+ self.full.clear();
1396
+ self.display.clear();
1397
+ self.segments.clear();
1398
+ }
1399
+
1400
+ /// Ctrl+W / Option+Delete — erase the last word (whitespace-delimited).
1401
+ fn pop_word(&mut self) {
1402
+ // Trim trailing whitespace first, then remove up to the previous whitespace boundary.
1403
+ while self.full.ends_with(' ') {
1404
+ self.pop_last();
1405
+ }
1406
+ while !self.full.is_empty() && !self.full.ends_with(' ') {
1407
+ self.pop_last();
1408
+ }
1409
+ }
1392
1410
  }
1393
1411
 
1394
1412
  #[cfg(unix)]
@@ -1474,9 +1492,20 @@ fn read_prompt_line(label: &str, width: usize, paste_count: &mut usize) -> Resul
1474
1492
  }
1475
1493
  4 if buffer.is_empty() => return Ok(PromptRead::Eof),
1476
1494
  8 | 127 => {
1495
+ // Backspace
1477
1496
  buffer.pop_last();
1478
1497
  display_rows = redraw_prompt_line(label, &buffer.display, display_rows, width)?;
1479
1498
  }
1499
+ 21 => {
1500
+ // Ctrl+U / Cmd+Delete — erase entire line
1501
+ buffer.clear_all();
1502
+ display_rows = redraw_prompt_line(label, &buffer.display, display_rows, width)?;
1503
+ }
1504
+ 23 => {
1505
+ // Ctrl+W / Option+Delete — erase last word
1506
+ buffer.pop_word();
1507
+ display_rows = redraw_prompt_line(label, &buffer.display, display_rows, width)?;
1508
+ }
1480
1509
  0x1b => {
1481
1510
  let sequence = read_escape_sequence(&mut input)?;
1482
1511
  if sequence == b"[200~" {
@@ -643,9 +643,17 @@ fn build_headers(config: &OpenAiCompatibleProviderConfig, prompt_cache: bool) ->
643
643
  let mut headers = HeaderMap::new();
644
644
  headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
645
645
 
646
- if let Some(api_key_env) = &config.api_key_env {
647
- let api_key = std::env::var(api_key_env)
648
- .with_context(|| format!("environment variable {api_key_env} is required"))?;
646
+ let resolved_key = if let Some(key) = &config.api_key {
647
+ Some(key.clone())
648
+ } else if let Some(env_var) = &config.api_key_env {
649
+ Some(
650
+ std::env::var(env_var)
651
+ .with_context(|| format!("environment variable {env_var} is required"))?,
652
+ )
653
+ } else {
654
+ None
655
+ };
656
+ if let Some(api_key) = resolved_key {
649
657
  headers.insert(
650
658
  AUTHORIZATION,
651
659
  HeaderValue::from_str(&format!("Bearer {api_key}"))