1use std::fs;
2use std::path::Path;
3use serde_json::{Value, json};
4use uuid::Uuid;
5use chrono::Utc;
6
7pub fn run_fork_from_active(title: Option<String>) {
8 let index_path = Path::new(".fur").join("index.json");
9 let index_data: Value = serde_json::from_str(&fs::read_to_string(index_path).unwrap()).unwrap();
10 let active_conversation = index_data["active_thread"]
11 .as_str()
12 .expect("No active conversation set");
13
14 run_fork(active_conversation, title);
15}
16
17pub fn run_fork(conversation_id: &str, title: Option<String>) {
18 let fur_dir = Path::new(".fur");
19 let threads_dir = fur_dir.join("threads");
20 let index_path = fur_dir.join("index.json");
21
22 let old_path = threads_dir.join(format!("{}.json", conversation_id));
23 if !old_path.exists() {
24 eprintln!("❌ Thread ID {} does not exist at path {:?}", conversation_id, old_path);
25 return;
26 }
27
28 let old_data: Value = serde_json::from_str(
30 &fs::read_to_string(&old_path).unwrap()
31 ).unwrap();
32
33 let old_title = old_data["title"].as_str().unwrap_or("Untitled");
34 let new_id = Uuid::new_v4().to_string();
35 let timestamp = Utc::now().to_rfc3339();
36
37 let fork_title: String;
39 let used_custom_title = title.is_some();
40
41 fork_title = match title {
42 Some(custom) => custom,
43 None => format!("Fork of {}", old_title),
44 };
45
46 let messages = old_data["messages"].clone();
47
48 let new_conversation = json!({
49 "id": new_id,
50 "title": fork_title,
51 "created_at": timestamp,
52 "forked_from": conversation_id,
53 "messages": messages
54 });
55
56 let new_path = threads_dir.join(format!("{}.json", new_id));
57 fs::write(&new_path, serde_json::to_string_pretty(&new_conversation).unwrap()).unwrap();
58
59 let mut index_data: Value = serde_json::from_str(
61 &fs::read_to_string(&index_path).unwrap()
62 ).unwrap();
63
64 index_data["active_thread"] = json!(new_id);
65 index_data["threads"].as_array_mut().unwrap().push(json!(new_id));
66
67 fs::write(index_path, serde_json::to_string_pretty(&index_data).unwrap()).unwrap();
68
69
70 if used_custom_title {
71 println!(
72 "🌱 Created fork \"{}\" from {} -- {} → {}",
73 fork_title, old_title, conversation_id, new_id
74 );
75 } else {
76 println!(
77 "🌱 Forked conversation from {} -- {} → {}",
78 old_title, conversation_id, new_id
79 );
80 }
81}