summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config/mod.rs84
-rw-r--r--src/repl/mod.rs11
2 files changed, 89 insertions, 6 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs
index dae2018..a92c65f 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -19,7 +19,7 @@ use crate::utils::*;
use anyhow::{anyhow, bail, Context, Result};
use indexmap::IndexMap;
-use inquire::{validator::Validation, Confirm, Select, Text};
+use inquire::{list_option::ListOption, validator::Validation, Confirm, MultiSelect, Select, Text};
use parking_lot::RwLock;
use serde::Deserialize;
use serde_json::json;
@@ -27,7 +27,9 @@ use simplelog::LevelFilter;
use std::collections::{HashMap, HashSet};
use std::{
env,
- fs::{create_dir_all, read_dir, read_to_string, remove_file, File, OpenOptions},
+ fs::{
+ create_dir_all, read_dir, read_to_string, remove_dir_all, remove_file, File, OpenOptions,
+ },
io::Write,
path::{Path, PathBuf},
process,
@@ -624,11 +626,79 @@ impl Config {
let value = value.parse().with_context(|| "Invalid value")?;
config.write().highlight = value;
}
- _ => bail!("Unknown key `{key}`"),
+ _ => bail!("Unknown key '{key}'"),
}
Ok(())
}
+ pub fn delete(config: &GlobalConfig, kind: &str) -> Result<()> {
+ let (dir, file_ext) = match kind {
+ "roles" => (Self::roles_dir()?, Some(".md")),
+ "sessions" => (config.read().sessions_dir()?, Some(".yaml")),
+ "rags" => (Self::rags_dir()?, Some(".yaml")),
+ "agents-config" => (Self::agents_config_dir()?, None),
+ _ => bail!("Unknown kind '{kind}'"),
+ };
+ let names = match read_dir(&dir) {
+ Ok(rd) => {
+ let mut names = vec![];
+ for entry in rd.flatten() {
+ let name = entry.file_name();
+ match file_ext {
+ Some(file_ext) => {
+ if let Some(name) = name.to_string_lossy().strip_suffix(file_ext) {
+ names.push(name.to_string());
+ }
+ }
+ None => {
+ if entry.path().is_dir() {
+ names.push(name.to_string_lossy().to_string());
+ }
+ }
+ }
+ }
+ names.sort_unstable();
+ names
+ }
+ Err(_) => vec![],
+ };
+
+ if names.is_empty() {
+ bail!("No {kind} to delete")
+ }
+
+ let select_names = MultiSelect::new(&format!("Select {kind} to delete:"), names)
+ .with_validator(|list: &[ListOption<&String>]| {
+ if list.is_empty() {
+ Ok(Validation::Invalid(
+ "At least one item must be selected".into(),
+ ))
+ } else {
+ Ok(Validation::Valid)
+ }
+ })
+ .prompt()?;
+
+ for name in select_names {
+ match file_ext {
+ Some(ext) => {
+ let path = dir.join(format!("{name}{ext}"));
+ remove_file(&path).with_context(|| {
+ format!("Failed to delete {kind} at '{}'", path.display())
+ })?;
+ }
+ None => {
+ let path = dir.join(name);
+ remove_dir_all(&path).with_context(|| {
+ format!("Failed to delete {kind} at '{}'", path.display())
+ })?;
+ }
+ }
+ }
+ println!("✨ Successfully deleted {kind}.");
+ Ok(())
+ }
+
pub fn set_temperature(&mut self, value: Option<f64>) {
match self.role_like_mut() {
Some(role_like) => role_like.set_temperature(value),
@@ -1432,6 +1502,10 @@ impl Config {
.into_iter()
.map(|v| (format!("{v} "), None))
.collect(),
+ ".delete" => vec!["roles", "sessions", "rags", "agents-config"]
+ .into_iter()
+ .map(|v| (v.to_string(), None))
+ .collect(),
_ => vec![],
};
filter = args[0]
@@ -1505,7 +1579,7 @@ impl Config {
let theme_path = Self::local_path(&theme_filename)?;
if theme_path.exists() {
let theme = ThemeSet::get_theme(&theme_path)
- .with_context(|| format!("Invalid theme at {}", theme_path.display()))?;
+ .with_context(|| format!("Invalid theme at '{}'", theme_path.display()))?;
Some(theme)
} else {
let theme = if self.light_theme {
@@ -1703,7 +1777,7 @@ impl Config {
fn load_from_file(config_path: &Path) -> Result<Self> {
let content = read_to_string(config_path)
- .with_context(|| format!("Failed to load config at {}", config_path.display()))?;
+ .with_context(|| format!("Failed to load config at '{}'", config_path.display()))?;
let config: Self = serde_yaml::from_str(&content).map_err(|err| {
let err_msg = err.to_string();
let err_msg = if err_msg.starts_with(&format!("{}: ", CLIENTS_FIELD)) {
diff --git a/src/repl/mod.rs b/src/repl/mod.rs
index 8c68f78..13e147b 100644
--- a/src/repl/mod.rs
+++ b/src/repl/mod.rs
@@ -31,7 +31,7 @@ lazy_static::lazy_static! {
const MENU_NAME: &str = "completion_menu";
lazy_static::lazy_static! {
- static ref REPL_COMMANDS: [ReplCommand; 30] = [
+ static ref REPL_COMMANDS: [ReplCommand; 31] = [
ReplCommand::new(".help", "Show this help message", AssertState::pass()),
ReplCommand::new(".info", "View system info", AssertState::pass()),
ReplCommand::new(".model", "Change the current LLM", AssertState::pass()),
@@ -148,6 +148,7 @@ lazy_static::lazy_static! {
AssertState::pass()
),
ReplCommand::new(".set", "Adjust settings", AssertState::pass()),
+ ReplCommand::new(".delete", "Delete roles/sessions/RAGs/agents-config", AssertState::pass()),
ReplCommand::new(".copy", "Copy the last response", AssertState::pass()),
ReplCommand::new(".exit", "Exit the REPL", AssertState::pass()),
];
@@ -392,6 +393,14 @@ impl Repl {
println!("Usage: .set <key> <value>...")
}
},
+ ".delete" => match args {
+ Some(args) => {
+ Config::delete(&self.config, args)?;
+ }
+ _ => {
+ println!("Usage: .delete [roles|sessions|rags|agents-config]")
+ }
+ },
".copy" => {
let config = self.config.read();
self.copy(config.last_reply())