use std::path::PathBuf;
use anyhow::Result;
use brainwires_agents::state_model::{
ApplicationChange, OperationLog, StateChange, StateModelProposedOperation, ThreeStateModel,
};
#[tokio::main]
async fn main() -> Result<()> {
println!("=== Three-State Model Demo ===\n");
let model = ThreeStateModel::new();
println!("--- Updating application state ---");
model
.application_state
.update_file(PathBuf::from("src/main.rs"), "abc123".to_string())
.await;
model
.application_state
.update_file(PathBuf::from("src/lib.rs"), "def456".to_string())
.await;
model
.application_state
.mark_resource_exists("build-cache")
.await;
let files = model.application_state.get_all_files().await;
println!("Tracked files: {}", files.len());
for (path, status) in &files {
println!(
" {} (hash={}, dirty={})",
path.display(),
status.content_hash,
status.dirty,
);
}
println!("\n--- Operation lifecycle ---");
let op_id = model.operation_state.generate_id().await;
let log = OperationLog::new(
op_id.clone(),
"agent-1".to_string(),
"build".to_string(),
serde_json::json!({ "target": "release" }),
)
.with_resources(
vec!["src/main.rs".to_string()],
vec!["target/release/app".to_string()],
);
model.operation_state.start_operation(log).await;
println!("Started operation: {op_id}");
let active = model.operation_state.get_active_operations().await;
println!("Active operations: {}", active.len());
model
.operation_state
.complete_operation(&op_id, true, None, None)
.await;
let completed = model.operation_state.get_operation(&op_id).await.unwrap();
println!("Operation {} status: {:?}", op_id, completed.status);
println!("\n--- Operation validation (no conflict) ---");
let proposed = StateModelProposedOperation {
agent_id: "agent-2".to_string(),
operation_type: "test".to_string(),
resources_needed: vec!["src/lib.rs".to_string()],
resources_produced: vec!["test-report.xml".to_string()],
};
let result = model.validate_operation(&proposed).await;
println!(
"Proposed test on src/lib.rs: valid={}, errors={}, warnings={}",
result.valid,
result.errors.len(),
result.warnings.len(),
);
println!("\n--- Operation validation (conflict) ---");
let conflict_op_id = model.operation_state.generate_id().await;
let conflict_log = OperationLog::new(
conflict_op_id.clone(),
"agent-3".to_string(),
"refactor".to_string(),
serde_json::json!({}),
)
.with_resources(vec!["src/main.rs".to_string()], vec![]);
model.operation_state.start_operation(conflict_log).await;
let conflicting = StateModelProposedOperation {
agent_id: "agent-4".to_string(),
operation_type: "format".to_string(),
resources_needed: vec!["src/main.rs".to_string()],
resources_produced: vec![],
};
let conflict_result = model.validate_operation(&conflicting).await;
println!(
"Proposed format on src/main.rs while refactor is running: valid={}",
conflict_result.valid
);
for err in &conflict_result.errors {
println!(" Error: {err}");
}
model
.operation_state
.complete_operation(&conflict_op_id, true, None, None)
.await;
println!("\n--- State change + snapshot ---");
let change = StateChange {
operation_id: "op-change-1".to_string(),
application_changes: vec![
ApplicationChange::FileModified {
path: PathBuf::from("src/main.rs"),
new_hash: "updated-hash-789".to_string(),
},
ApplicationChange::ResourceCreated {
resource_id: "deploy-artifact".to_string(),
},
],
new_dependencies: vec![],
};
model.record_state_change(change).await;
let snapshot = model.snapshot().await;
println!("Snapshot summary:");
println!(" Files tracked: {}", snapshot.files.len());
println!(" Resource locks: {}", snapshot.locks.len());
println!(" Active operations: {}", snapshot.active_operations.len());
println!(
" Git branch: {}",
if snapshot.git_state.current_branch.is_empty() {
"(none)"
} else {
&snapshot.git_state.current_branch
}
);
let main_rs = snapshot
.files
.get(&PathBuf::from("src/main.rs"))
.expect("src/main.rs should be tracked");
println!(
" src/main.rs hash: {} (dirty={})",
main_rs.content_hash, main_rs.dirty
);
println!("\nThree-state model demo complete.");
Ok(())
}