added a module to copy the command to run a portscan for the scope, and

added the ability to add new configs to separate projects, like work vs
personal. Also added a way to switch between these configs.
This commit is contained in:
2026-08-19 16:56:27 -05:00
parent e28306d07d
commit 8ab7a2bec4
10 changed files with 759 additions and 291 deletions
+62 -3
View File
@@ -9,12 +9,12 @@ use ratatui::{
prelude::*,
widgets::{Block, Borders, List, ListItem, ListState, Paragraph},
};
use std::thread::sleep;
use std::thread::spawn;
use std::thread::{JoinHandle, sleep};
use std::time::Duration;
use std::{error::Error, time::Instant};
use std::{io::Write, usize};
use sysinfo::{MemoryRefreshKind, System};
use sysinfo::System;
pub fn get_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {
println!("{}", prompt);
@@ -23,9 +23,51 @@ pub fn get_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {
return Ok(response.trim().to_string());
}
pub fn startup(
mut state: AppState,
nested: bool,
handles: Arc<Mutex<Vec<JoinHandle<()>>>>,
) -> Result<(), Box<dyn std::error::Error>> {
let mut app = AppState::new();
let (tx, rx) = channel();
app.main_tx = tx.clone();
if let Some(line) = state.config.get("alternate_configs") {
let mut selections = HashMap::new();
line.split(",").into_iter().for_each(|line| {
if let Some((name, path)) = line.split_once("|") {
selections.insert(name.to_string(), path.to_string());
println!("{} | {} ", name, path);
}
});
selections.insert(
"default".to_string(),
state.config_file.display().to_string(),
);
println!("default | {}", state.config_file.display());
let response = get_user_input("which config would you like to load?")?;
if let Some(path) = selections.get(&response) {
app.load_config(PathBuf::from(path), true)?;
run_tui(app, rx, handles.clone())?;
} else {
eprintln!("error invalid selection! exiting...");
return Err("invalid config selected.".into());
}
} else {
app.load_config(state.config_file.clone(), true)?;
run_tui(app, rx, handles.clone())?;
}
if nested {
let (tx, rx) = channel();
state.main_tx = tx;
run_tui(state, rx, handles.clone())?;
}
Ok(())
}
pub fn run_tui(
mut state: AppState,
main_rx: Receiver<ToolMessage>,
main_handles: Arc<Mutex<Vec<JoinHandle<()>>>>,
) -> Result<(), Box<dyn std::error::Error>> {
enable_raw_mode()?;
let mut stdout = io::stdout();
@@ -43,6 +85,7 @@ pub fn run_tui(
let mut system = System::new_all();
let system_timer = Duration::from_secs(1);
let mut last_print = Instant::now();
let mut switch_config = false;
const BYTES_PER_GB: u64 = 1024 * 1024 * 1024;
if !state.projects.is_empty() {
project_list_state.select(Some(0));
@@ -87,6 +130,7 @@ pub fn run_tui(
let mut history_index = state.history.len();
let mut handles = Vec::new();
loop {
if switch_config {}
if Instant::now().duration_since(last_print) > system_timer {
system.refresh_cpu_usage();
system.refresh_memory();
@@ -556,7 +600,10 @@ pub fn run_tui(
.send(ToolMessage::Output((0, "\n".to_string())));
let prompt = state.prompt.clone();
if prompt.action.is_some() {
state.prompt.responses.push(trimmed.clone());
state.prompt.responses.push(PromptResponse {
query: prompt.last_prompted.clone().unwrap(),
response: trimmed.clone(),
});
if state.prompt.responses.len() == state.prompt.num_responses {
state.execute_command(
prompt.execute_command.as_str(),
@@ -604,6 +651,10 @@ pub fn run_tui(
);
}
}
"switch_config" => {
switch_config = true;
break;
}
command_name => {
if state.module_loader.commands.contains_key(command) {
let _ = state.main_tx.send(ToolMessage::Output((
@@ -756,5 +807,13 @@ pub fn run_tui(
for handle in handles {
handle.join().unwrap();
}
if switch_config {
let handles_clone = main_handles.clone();
if let Ok(mut lock) = main_handles.lock() {
lock.push(spawn(move || {
let _ = startup(state, true, handles_clone);
}));
}
}
Ok(())
}