refactor(g3-cli): break lib.rs into focused modules
Extract 7 modules from the 2966-line lib.rs: - cli_args.rs (133 lines): CLI argument parsing with clap - autonomous.rs (785 lines): coach-player feedback loop - agent_mode.rs (284 lines): specialized agent execution - accumulative.rs (343 lines): iterative requirements mode - interactive.rs (851 lines): REPL with command handling - task_execution.rs (212 lines): unified retry logic - utils.rs (91 lines): display and workspace helpers Key improvements: - lib.rs reduced from 2966 to 415 lines (86% reduction) - Eliminated duplicate retry logic between execute_task and execute_task_machine - Each module has a single responsibility - Easier to reason about and maintain Agent: fowler
This commit is contained in:
91
crates/g3-cli/src/utils.rs
Normal file
91
crates/g3-cli/src/utils.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
//! Utility functions for G3 CLI.
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::style::{Color, ResetColor, SetForegroundColor};
|
||||
use g3_core::ui_writer::UiWriter;
|
||||
use g3_core::Agent;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::simple_output::SimpleOutput;
|
||||
|
||||
/// Display context window progress bar.
|
||||
pub fn display_context_progress<W: UiWriter>(agent: &Agent<W>, _output: &SimpleOutput) {
|
||||
let context = agent.get_context_window();
|
||||
let percentage = context.percentage_used();
|
||||
|
||||
// Create 10 dots representing context fullness
|
||||
let total_dots: usize = 10;
|
||||
let filled_dots = ((percentage / 100.0) * total_dots as f32).round() as usize;
|
||||
let empty_dots = total_dots.saturating_sub(filled_dots);
|
||||
|
||||
let filled_str = "●".repeat(filled_dots);
|
||||
let empty_str = "○".repeat(empty_dots);
|
||||
|
||||
// Determine color based on percentage
|
||||
let color = if percentage < 40.0 {
|
||||
Color::Green
|
||||
} else if percentage < 60.0 {
|
||||
Color::Yellow
|
||||
} else if percentage < 80.0 {
|
||||
Color::Rgb {
|
||||
r: 255,
|
||||
g: 165,
|
||||
b: 0,
|
||||
} // Orange
|
||||
} else {
|
||||
Color::Red
|
||||
};
|
||||
|
||||
// Format tokens as compact strings (e.g., "38.5k" instead of "38531")
|
||||
let format_tokens = |tokens: u32| -> String {
|
||||
if tokens >= 1_000_000 {
|
||||
format!("{:.1}m", tokens as f64 / 1_000_000.0)
|
||||
} else if tokens >= 1_000 {
|
||||
let k = tokens as f64 / 1000.0;
|
||||
if k >= 100.0 {
|
||||
format!("{:.0}k", k)
|
||||
} else {
|
||||
format!("{:.1}k", k)
|
||||
}
|
||||
} else {
|
||||
format!("{}", tokens)
|
||||
}
|
||||
};
|
||||
|
||||
// Print with colored dots (using print! directly to handle color codes)
|
||||
print!(
|
||||
"{}{}{}{} {}/{} ◉ | {:.0}%\n",
|
||||
SetForegroundColor(color),
|
||||
filled_str,
|
||||
empty_str,
|
||||
ResetColor,
|
||||
format_tokens(context.used_tokens),
|
||||
format_tokens(context.total_tokens),
|
||||
percentage
|
||||
);
|
||||
}
|
||||
|
||||
/// Set up the workspace directory for autonomous mode.
|
||||
/// Uses G3_WORKSPACE environment variable or defaults to ~/tmp/workspace.
|
||||
pub fn setup_workspace_directory(machine_mode: bool) -> Result<PathBuf> {
|
||||
let workspace_dir = if let Ok(env_workspace) = std::env::var("G3_WORKSPACE") {
|
||||
PathBuf::from(env_workspace)
|
||||
} else {
|
||||
// Default to ~/tmp/workspace
|
||||
let home_dir = dirs::home_dir()
|
||||
.ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
|
||||
home_dir.join("tmp").join("workspace")
|
||||
};
|
||||
|
||||
// Create the directory if it doesn't exist
|
||||
if !workspace_dir.exists() {
|
||||
std::fs::create_dir_all(&workspace_dir)?;
|
||||
let output = SimpleOutput::new_with_mode(machine_mode);
|
||||
output.print(&format!(
|
||||
"📁 Created workspace directory: {}",
|
||||
workspace_dir.display()
|
||||
));
|
||||
}
|
||||
|
||||
Ok(workspace_dir)
|
||||
}
|
||||
Reference in New Issue
Block a user