2
0

feat(headless): add commit, remember commands and agent chaining

This commit is contained in:
2026-03-24 14:15:08 +09:00
parent da1159cbf9
commit 5fd97f1e57
2 changed files with 93 additions and 6 deletions

View File

@@ -215,10 +215,24 @@ fn run_once(configs: &[config::AgentConfig]) -> Result<(), String> {
let running = Arc::new(AtomicBool::new(true));
setup_ctrlc(running.clone());
let agents = spawn_and_wait(configs, &running);
if let Some(a) = agents.first() {
if agents.is_empty() { return Ok(()); }
write_state(&agents);
println!("{}", strip_dir_listing(&a.output));
let output = &agents[0].output;
let clean = strip_dir_listing(output);
println!("{clean}");
// If the agent proposed @agents, chain them
let next = extract_agent_configs(clean);
if !next.is_empty() {
eprintln!("\n AI proposed {} agent(s):", next.len());
for c in &next { eprintln!(" @{} {}", c.name, c.task); }
let _ = std::fs::remove_dir_all(STATE_DIR);
create_state_dir();
return run_with_configs(next);
}
Ok(())
}
@@ -408,9 +422,7 @@ fn save_session(cycle: usize, agents: &[Agent], decision: &str, indices: &[usize
let json = serde_json::to_string_pretty(&session).unwrap_or_default();
atomic_write(&filename, json.as_bytes());
if !decision.is_empty() {
save_to_aigpt_memory(decision, &saved_agents);
}
// aigpt memory is NOT auto-saved. Use `aishell remember` for important decisions.
// Update unified command history
update_cmd_history(&saved_agents, timestamp);
@@ -632,6 +644,77 @@ pub fn decision() {
}
}
/// Run review preset, get commit message, and commit.
pub fn commit() {
use std::process::Command;
// Check if there are changes
let status = Command::new("git").args(["status", "--short"]).output();
match status {
Ok(o) if o.stdout.is_empty() => {
eprintln!("nothing to commit");
return;
}
Err(e) => { eprintln!("git error: {e}"); return; }
_ => {}
}
// Run commit-msg agent
eprintln!(" generating commit message...");
let cwd = std::env::current_dir()
.map(|p| p.display().to_string())
.unwrap_or_else(|_| ".".to_string());
let configs = vec![config::AgentConfig {
name: "commit-msg".into(),
task: "Suggest a commit message for the current git changes. Output ONLY the message, nothing else. Conventional commits format. One line.".into(),
cwd,
}];
let running = Arc::new(AtomicBool::new(true));
setup_ctrlc(running.clone());
let agents = spawn_and_wait(&configs, &running);
if agents.is_empty() { return; }
let msg = strip_dir_listing(&agents[0].output).trim().to_string();
let msg = msg.trim_matches('`').trim().to_string();
if msg.is_empty() {
eprintln!(" failed to generate message");
return;
}
eprintln!(" message: {msg}");
eprintln!(" committing...");
let _ = Command::new("git").args(["add", "-A"]).status();
match Command::new("git").args(["commit", "-m", &msg]).status() {
Ok(s) if s.success() => eprintln!(" ✓ committed"),
Ok(s) => eprintln!(" ✗ git commit failed: {}", s.code().unwrap_or(-1)),
Err(e) => eprintln!("{e}"),
}
}
/// Save the latest decision to aigpt memory (explicit, not automatic).
pub fn remember() {
let dec_path = format!("{STATE_DIR}/decision.json");
match std::fs::read_to_string(&dec_path) {
Ok(content) => {
if let Ok(d) = serde_json::from_str::<serde_json::Value>(&content) {
let decision = d["decision"].as_str().unwrap_or("");
let agents = d["agents"].as_array()
.map(|a| a.to_vec())
.unwrap_or_default();
if decision.is_empty() {
eprintln!("No decision to remember.");
return;
}
save_to_aigpt_memory(decision, &agents);
eprintln!("saved to aigpt memory");
}
}
Err(_) => eprintln!("No decision. Run a cycle first."),
}
}
pub fn signal_next(save: Vec<usize>) {
let save_val = if save.is_empty() {
serde_json::json!(null)

View File

@@ -92,7 +92,9 @@ fn main() {
aishell::headless::log(&id);
}
Some("decision") => aishell::headless::decision(),
Some("commit") => aishell::headless::commit(),
Some("context") => aishell::headless::context(),
Some("remember") => aishell::headless::remember(),
Some("history") => {
let sub = env::args().nth(2);
match sub.as_deref() {
@@ -134,10 +136,12 @@ fn print_help() {
println!(" aishell run <task> Run single agent");
println!(" aishell run -p <preset> Preset: daily, review, improve");
println!(" aishell run -f <config> Custom config file");
println!(" aishell commit Git commit with AI-suggested message");
println!(" aishell status [-v] Show agent status");
println!(" aishell log <id|name> Show agent output");
println!(" aishell decision Show AI integration result");
println!(" aishell context Full project context (for AI)");
println!(" aishell remember Save latest decision to AI memory");
println!(" aishell history [id] Show past sessions");
println!(" aishell history cmd [grep] Command history (filterable)");
println!(" aishell history clean Remove old sessions (keep 10)");