Centralize g3 status message formatting

Extract a new g3_status module in g3-cli that provides consistent formatting
for all 'g3:' prefixed system status messages.

Key changes:
- Add G3Status struct with methods for progress, done, failed, error, etc.
- Add Status enum with Done, Failed, Error, Resolved, Insufficient, NoChanges
- Add ThinResult struct in g3-core for semantic thinning data
- Update UiWriter trait with print_thin_result() method
- Refactor context thinning to return ThinResult instead of formatted strings
- Update all callers to use the new centralized formatting
- Session resume/decline messages now use G3Status
- Compaction status messages now use G3Status

This maintains clean separation of concerns: g3-core emits semantic data,
g3-cli handles all terminal formatting and colors.
This commit is contained in:
Dhanji R. Prasanna
2026-01-20 09:50:55 +05:30
parent 7bd72a4a51
commit 182f5f98fe
15 changed files with 512 additions and 182 deletions

View File

@@ -10,6 +10,7 @@ use tracing::{debug, error};
use g3_core::ui_writer::UiWriter;
use g3_core::Agent;
use crate::g3_status::{G3Status, Status};
use crate::project_files::extract_readme_heading;
use crate::simple_output::SimpleOutput;
use crate::task_execution::execute_task_with_retry;
@@ -54,21 +55,20 @@ pub async fn run_interactive<W: UiWriter>(
// Resume the session
match agent.restore_from_continuation(&continuation) {
Ok(true) => {
// Print bold green [done]
println!("{}... resuming ... [done]{}", SetForegroundColor(Color::Green), ResetColor);
G3Status::resuming(&continuation.session_id, Status::Done);
}
Ok(false) => {
println!("{}... resuming ... [done]{}", SetForegroundColor(Color::Green), ResetColor);
G3Status::resuming_summary(&continuation.session_id);
}
Err(e) => {
println!("{}... failed: {}{}", SetForegroundColor(Color::Yellow), e, ResetColor);
G3Status::resuming(&continuation.session_id, Status::Error(e.to_string()));
// Clear the invalid continuation
let _ = g3_core::clear_continuation();
}
}
} else {
// User declined, clear the continuation
println!("{}... starting fresh{}", SetForegroundColor(Color::DarkGrey), ResetColor);
G3Status::info_inline("starting fresh");
let _ = g3_core::clear_continuation();
}
}
@@ -371,13 +371,13 @@ async fn handle_command<W: UiWriter>(
Ok(true)
}
"/thinnify" => {
let summary = agent.force_thin();
println!("{}", summary);
let result = agent.force_thin();
G3Status::thin_result(&result);
Ok(true)
}
"/skinnify" => {
let summary = agent.force_thin_all();
println!("{}", summary);
let result = agent.force_thin_all();
G3Status::thin_result(&result);
Ok(true)
}
"/fragments" => {
@@ -566,22 +566,13 @@ async fn handle_command<W: UiWriter>(
let selected = &sessions[num - 1];
match agent.switch_to_session(selected) {
Ok(true) => {
output.print_inline(&format!(
"... resuming \x1b[36m{}\x1b[0m \x1b[1;32m[done]\x1b[0m\n",
selected.session_id
));
G3Status::resuming(&selected.session_id, Status::Done);
}
Ok(false) => {
output.print_inline(&format!(
"... resuming \x1b[36m{}\x1b[0m (summary) \x1b[1;32m[done]\x1b[0m\n",
selected.session_id
));
G3Status::resuming_summary(&selected.session_id);
}
Err(e) => {
output.print_inline(&format!(
"... resuming \x1b[36m{}\x1b[0m \x1b[1;31m[error: {}]\x1b[0m\n",
selected.session_id, e
));
G3Status::resuming(&selected.session_id, Status::Error(e.to_string()));
}
}
} else {