feat(M12): complete milestone with plugins, checkpointing, and rewind
Implements the remaining M12 features from AGENTS.md: **Plugin System (crates/platform/plugins)** - Plugin manifest schema with plugin.json support - Plugin loader for commands, agents, skills, hooks, and MCP servers - Discovers plugins from ~/.config/owlen/plugins and .owlen/plugins - Includes comprehensive tests (4 passing) **Session Checkpointing (crates/core/agent)** - Checkpoint struct capturing session state and file diffs - CheckpointManager with snapshot, diff, save, load, and rewind capabilities - File diff tracking with before/after content - Checkpoint persistence to .owlen/checkpoints/ - Includes comprehensive tests (6 passing) **REPL Commands (crates/app/cli)** - /checkpoint - Save current session with file diffs - /checkpoints - List all saved checkpoints - /rewind <id> - Restore session and files from checkpoint - Updated /help documentation M12 milestone now fully complete: ✅ /permissions, /status, /cost (previously implemented) ✅ Checkpointing and /rewind ✅ Plugin loader with manifest schema 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -466,6 +466,9 @@ async fn main() -> Result<()> {
|
||||
let mut lines = stdin.lock().lines();
|
||||
let mut stats = agent_core::SessionStats::new();
|
||||
let mut history = agent_core::SessionHistory::new();
|
||||
let mut checkpoint_mgr = agent_core::CheckpointManager::new(
|
||||
std::path::PathBuf::from(".owlen/checkpoints")
|
||||
);
|
||||
|
||||
loop {
|
||||
print!("> ");
|
||||
@@ -487,6 +490,9 @@ async fn main() -> Result<()> {
|
||||
println!(" /permissions - Show permission settings");
|
||||
println!(" /cost - Show token usage and timing");
|
||||
println!(" /history - Show conversation history");
|
||||
println!(" /checkpoint - Save current session state");
|
||||
println!(" /checkpoints - List all saved checkpoints");
|
||||
println!(" /rewind <id> - Restore session from checkpoint");
|
||||
println!(" /clear - Clear conversation history");
|
||||
println!(" /exit - Exit interactive mode");
|
||||
}
|
||||
@@ -553,6 +559,47 @@ async fn main() -> Result<()> {
|
||||
println!("\n Tool Calls: {}", history.tool_calls.len());
|
||||
}
|
||||
}
|
||||
"/checkpoint" => {
|
||||
let checkpoint_id = format!("checkpoint-{}",
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
);
|
||||
match checkpoint_mgr.save_checkpoint(
|
||||
checkpoint_id.clone(),
|
||||
stats.clone(),
|
||||
&history,
|
||||
) {
|
||||
Ok(checkpoint) => {
|
||||
println!("\n💾 Checkpoint saved: {}", checkpoint_id);
|
||||
if !checkpoint.file_diffs.is_empty() {
|
||||
println!(" Files tracked: {}", checkpoint.file_diffs.len());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("\n❌ Failed to save checkpoint: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
"/checkpoints" => {
|
||||
match checkpoint_mgr.list_checkpoints() {
|
||||
Ok(checkpoints) => {
|
||||
if checkpoints.is_empty() {
|
||||
println!("\n📋 No checkpoints saved yet");
|
||||
} else {
|
||||
println!("\n📋 Saved Checkpoints:");
|
||||
for (i, cp_id) in checkpoints.iter().enumerate() {
|
||||
println!(" [{}] {}", i + 1, cp_id);
|
||||
}
|
||||
println!("\n Use /rewind <id> to restore");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("\n❌ Failed to list checkpoints: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
"/clear" => {
|
||||
history.clear();
|
||||
stats = agent_core::SessionStats::new();
|
||||
@@ -562,6 +609,31 @@ async fn main() -> Result<()> {
|
||||
println!("\n👋 Goodbye!");
|
||||
break;
|
||||
}
|
||||
cmd if cmd.starts_with("/rewind ") => {
|
||||
let checkpoint_id = cmd.strip_prefix("/rewind ").unwrap().trim();
|
||||
match checkpoint_mgr.rewind_to(checkpoint_id) {
|
||||
Ok(restored_files) => {
|
||||
println!("\n⏪ Rewound to checkpoint: {}", checkpoint_id);
|
||||
if !restored_files.is_empty() {
|
||||
println!(" Restored files:");
|
||||
for file in restored_files {
|
||||
println!(" - {}", file.display());
|
||||
}
|
||||
}
|
||||
// Load the checkpoint to restore history and stats
|
||||
if let Ok(checkpoint) = checkpoint_mgr.load_checkpoint(checkpoint_id) {
|
||||
stats = checkpoint.stats;
|
||||
history.user_prompts = checkpoint.user_prompts;
|
||||
history.assistant_responses = checkpoint.assistant_responses;
|
||||
history.tool_calls = checkpoint.tool_calls;
|
||||
println!(" Session state restored");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("\n❌ Failed to rewind: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("\n❌ Unknown command: {}", input);
|
||||
println!(" Type /help for available commands");
|
||||
|
||||
Reference in New Issue
Block a user