2026-07-12 13:52:00 +07:00
//! Tool for marking tasks as finished in the session's todo list.
use super ::super ::{ Tool , ToolCtx };
2026-07-16 07:42:03 +07:00
use anyhow ::{ anyhow , Result };
use serde_json ::{ json , Value };
use std ::path ::PathBuf ;
2026-07-12 13:52:00 +07:00
/// Tool that marks tasks as finished in the session's todo.md.
pub struct Todofinish ;
impl Tool for Todofinish {
2026-07-18 01:59:42 +07:00
fn name ( & self ) -> & 'static str { "todofinish" }
2026-07-12 13:52:00 +07:00
fn description ( & self ) -> & 'static str {
"Mark tasks as finished in the session todo list (todo.md). You can mark all tasks as finished by leaving the 'task_index' empty, or specify a 1-based index to finish a specific task."
}
fn parameters ( & self ) -> Value {
json! ({
"type" : "object" ,
"properties" : {
"task_index" : {
"type" : "integer" ,
"description" : "Optional 1-based index of the task to mark as finished. If omitted, ALL unfinished tasks will be marked as finished."
}
}
})
}
fn run ( & self , ctx : & ToolCtx , args : & Value ) -> Result < String > {
let path : PathBuf = ctx . session_dir . join ( "todo.md" );
if ! path . exists () {
return Ok ( "No todo.md found in session directory. Nothing to finish." . to_string ());
}
2026-07-16 07:42:03 +07:00
let content =
std ::fs ::read_to_string ( & path ). map_err ( | e | anyhow! ( "failed to read todo.md: {e}" )) ? ;
2026-07-12 13:52:00 +07:00
2026-07-13 08:12:02 +07:00
let task_index = args . get ( "task_index" ). and_then ( serde_json ::Value ::as_i64 );
2026-07-12 13:52:00 +07:00
let mut new_content = String ::new ();
let mut task_count = 0 ;
let mut modified = false ;
for line in content . lines () {
if line . trim_start (). starts_with ( "- [ ]" ) {
task_count += 1 ;
if let Some ( target ) = task_index {
if task_count == target {
new_content . push_str ( & line . replacen ( "- [ ]" , "- [x]" , 1 ));
modified = true ;
} else {
new_content . push_str ( line );
}
} else {
// Mark all as finished
new_content . push_str ( & line . replacen ( "- [ ]" , "- [x]" , 1 ));
modified = true ;
}
} else {
new_content . push_str ( line );
}
new_content . push ( '\n' );
}
if ! modified {
return Ok ( "No unfinished tasks found or index out of bounds." . to_string ());
}
std ::fs ::write ( & path , new_content )
2026-07-13 08:12:02 +07:00
. map_err ( | e | anyhow! ( "failed to write to todo.md: {e}" )) ? ;
2026-07-12 13:52:00 +07:00
if let Some ( idx ) = task_index {
2026-07-13 08:12:02 +07:00
Ok ( format! ( "Successfully marked task {idx} as finished." ))
2026-07-12 13:52:00 +07:00
} else {
Ok ( "Successfully marked ALL tasks as finished." . to_string ())
}
}
}