Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "you"
version = "0.1.80"
version = "0.1.90"
edition = "2024"
description = "Translate your natural language into executable command(s)"
authors = ["Xinyu Bao <baoxinyuworks@163.com>"]
Expand Down
36 changes: 28 additions & 8 deletions src/cache.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::{fs::{create_dir, read_dir, DirEntry}, path::PathBuf};
use std::{
fs::{DirEntry, File, create_dir, read_dir},
io::Write,
path::PathBuf,
};

use anyhow::Result;
use anyhow::{Result, anyhow};

use crate::{
constants::YOU_CACHE_DIRECTORY,
Expand Down Expand Up @@ -38,9 +42,7 @@ impl GlobalResourceInitialization for Cache {
}
}

Ok(
Self { scripts }
)
Ok(Self { scripts })
}
}

Expand All @@ -52,11 +54,29 @@ impl Cache {
return Some(&script);
}
}

None
}

pub fn add_new_script(&mut self, script_name: &str, script_content: &str) -> Result<()> {

pub fn add_new_script(&self, script_name: &str, script_content: &str) -> Result<()> {
let you_cache_directory: PathBuf = acquire_you_home_directory()?.join(YOU_CACHE_DIRECTORY);

let mut file: File =
std::fs::File::create_new(you_cache_directory.join(format!("{}.sh", script_name)))?;
Comment thread
AspadaX marked this conversation as resolved.
file.write(script_content.as_bytes())?;

Comment thread
AspadaX marked this conversation as resolved.
Outdated
Ok(())
}

pub fn delete_script(&self, script_name: &str) -> Result<()> {
Comment thread
AspadaX marked this conversation as resolved.
Outdated
for script in self.scripts.iter() {
let current_script_name: &str = script.file_stem().unwrap().to_str().unwrap();
if current_script_name == script_name {
std::fs::remove_file(script)?;
break;
}
}

Err(anyhow!("Script '{}' not found", script_name))
}
}
13 changes: 12 additions & 1 deletion src/configurations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,22 @@ impl Display for PreferredCLI {
}
}

#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Configurations {
#[serde(default)]
pub enable_cache: bool,
preferred_clis: Vec<PreferredCLI>,
}

impl Default for Configurations {
fn default() -> Self {
Self {
enable_cache: false,
preferred_clis: vec![],
}
}
}

impl Display for Configurations {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&serde_json::to_string_pretty(&self).unwrap())
Expand Down
34 changes: 34 additions & 0 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
semi_autonomous_command_line_agent::SemiAutonomousCommandLineAgent,
traits::{AgentExecution, Step},
},
cache::Cache,
configurations::Configurations,
information::ContextualInformation,
llm::Context,
Expand Down Expand Up @@ -56,6 +57,8 @@ fn process_command_interaction(
}

pub fn process_run_with_one_single_instruction(
cache: &Cache,
configurations: &Configurations,
contextual_information_object: &ContextualInformation,
command_in_natural_language: &str,
) -> Result<(), Error> {
Expand Down Expand Up @@ -83,8 +86,18 @@ pub fn process_run_with_one_single_instruction(

// Extract command if it's an Execute action type
if let LLMActionType::Execute(ref mut execute_action) = command_json {
if configurations.enable_cache {
save_to_shell_in_cache(
&cache,
save_shell_input.trim(),
execute_action,
)?;
break;
}

save_to_shell(save_shell_input.trim(), execute_action)?;
}

break;
}
Err(error) => {
Expand All @@ -100,6 +113,8 @@ pub fn process_run_with_one_single_instruction(
}

pub fn process_interactive_mode(
cache: &Cache,
configurations: &Configurations,
contextual_information_object: &ContextualInformation,
) -> Result<(), Error> {
let mut agent: SemiAutonomousCommandLineAgent =
Expand Down Expand Up @@ -138,6 +153,11 @@ pub fn process_interactive_mode(

// Extract command if it's an Execute action type
if let LLMActionType::Execute(ref mut execute_action) = command_store {
if configurations.enable_cache {
save_to_shell_in_cache(&cache, name.trim(), execute_action)?;
break;
}

save_to_shell(name.trim(), execute_action)?;
}

Expand Down Expand Up @@ -206,3 +226,17 @@ fn save_to_shell(shell_name: &str, execute_action: &mut ActionTypeExecute) -> Re

Ok(())
}

fn save_to_shell_in_cache(
cache: &Cache,
shell_name: &str,
execute_action: &mut ActionTypeExecute,
) -> Result<(), Error> {
let mut file_content: String = String::from("#!/usr/bin/env sh\n");
file_content.push_str(execute_action.get_commands());

cache.add_new_script(shell_name, &file_content)?;
display_message(Level::Logging, "Shell had been saved to the cache.");

Ok(())
}
32 changes: 29 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ mod constants;
mod helpers;
mod information;
mod llm;
mod shell;
mod styles;
mod traits;

use std::{fs::File, io::Read};

use anyhow::{Error, Result};
use arguments::{Arguments, Commands};
use cchain::display_control::{Level, display_message};
Expand All @@ -19,27 +22,50 @@ use helpers::{
};

use crate::{
configurations::Configurations, information::ContextualInformation,
traits::GlobalResourceInitialization,
cache::Cache, configurations::Configurations, information::ContextualInformation,
shell::execute_shell_script, traits::GlobalResourceInitialization,
};

fn main() -> Result<(), Error> {
let arguments: Arguments = Arguments::parse();

Configurations::initialize()?;
Cache::initialize()?;

let cache: Cache = Cache::load()?;
let contextual_information: ContextualInformation = ContextualInformation::new()?;
let configurations: Configurations = Configurations::load()?;

match arguments.commands {
Commands::Run(subcommand) => {
if let Some(command_in_natural_language) = subcommand.command_in_natural_language {
if configurations.enable_cache {
display_message(Level::Logging, "Cache has been enabled.");
if let Some(script) = cache.search(&command_in_natural_language) {
display_message(
Level::Logging,
&format!(
"Cache hit. Using the generated script {}...",
script.file_name().unwrap().to_str().unwrap()
),
);
let mut script_content: String = String::new();
File::open(script)?.read_to_string(&mut script_content)?;
execute_shell_script(&script_content)?;
return Ok(());
}
}

process_run_with_one_single_instruction(
&cache,
&configurations,
&contextual_information,
&command_in_natural_language,
)?;
return Ok(());
}

process_interactive_mode(&contextual_information)?;
process_interactive_mode(&cache, &configurations, &contextual_information)?;
}
Commands::Explain(subcommand) => {
process_explanation_with_one_single_instruction(
Expand Down
41 changes: 41 additions & 0 deletions src/shell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::process::Command;

use anyhow::{Error, Result, anyhow};

/// Execute a shell script with the specified execution context
pub fn execute_shell_script(shell_script: &str) -> Result<(), Error> {
let current_working_directory: std::path::PathBuf = std::env::current_dir()?;
if cfg!(target_os = "windows") {
let mut cmd = Command::new("cmd");
cmd.args(["/C", shell_script]).current_dir(&current_working_directory);

match cmd.status() {
Ok(status) if !status.success() => {
return Err(anyhow!(
"Windows CMD interpreter exited with a non-zero status"
Comment thread
AspadaX marked this conversation as resolved.
));
}
Ok(_) => {}
Err(e) => {
return Err(anyhow!("Failed to start Windows CMD interpreter: {}", e));
}
}
Comment thread
AspadaX marked this conversation as resolved.

return Ok(());
}

let mut cmd: Command = Command::new("sh");
cmd.args(["-c", shell_script]).current_dir(&current_working_directory);

match cmd.status() {
Ok(status) if !status.success() => {
return Err(anyhow!("Shell interpreter exited with a non-zero status"));
}
Ok(_) => {}
Err(e) => {
return Err(anyhow!("Failed to start shell interpreter: {}", e));
}
}

Ok(())
}
Loading