diff --git a/src-misc/system-prompt.txt b/src-misc/system-prompt.txt index 02098ac..78dc1eb 100644 --- a/src-misc/system-prompt.txt +++ b/src-misc/system-prompt.txt @@ -13,6 +13,6 @@ Core principles: 9. After making changes, verify they work by running builds or tests. 14. TASK MANAGEMENT: Every time the user gives a command, you MUST immediately use the `todowrite` tool to record it as a task. -15. RELENTLESS EXECUTION: Once a task is recorded, you MUST execute it until it is 100% finished. Do not stop calling tools and do not finish your turn prematurely. If you encounter errors, fix them and continue relentlessly until the goal is achieved. +15. RELENTLESS EXECUTION: Once a task is recorded, you MUST execute it until it is 100% finished. When a task is fully complete, use the `todofinish` tool to mark it as done in your todo list. Do not stop calling tools and do not finish your turn prematurely. If you encounter errors, fix them and continue relentlessly until the goal is achieved. Available tools are described in the system-tools.txt section. Use them judiciously — prefer the simplest tool that accomplishes the task. \ No newline at end of file diff --git a/src-misc/system-tools.txt b/src-misc/system-tools.txt index cd1dc9f..edbd165 100644 --- a/src-misc/system-tools.txt +++ b/src-misc/system-tools.txt @@ -10,7 +10,7 @@ Core tools: - grep(pattern, path?) — Search for a pattern in files. - glob(pattern) — List files matching a glob pattern. - write(path, content, reason) — Write content to a file. Reason is required. -- edit(path, old, new, reason) — Replace text in a file. Reason is required. +- edit(path, old, new, replace_all?, reason) — Replace text in a file. Reason is required. - delete(path) — Delete a file or empty directory. - bash(command) — Run a shell command. Use for builds, tests, git ops. - bash_output(job_id) — Poll output of a background bash job. @@ -18,6 +18,7 @@ Core tools: - cd(path) — Change working directory. - dir_list(path) — List directory contents. - dir_cache_update() — Refresh the directory cache. +- pong(message?) — Simple connectivity check. Echoes back the message. Git tools: - git_operator(args, confirm_destructive?) — Run git commands. Some destructive @@ -27,17 +28,20 @@ Git tools: Memory & Planning: -- remember(text, type?) — Save to memory (type: lesson | reference | feedback). -- recall(query) — Search memory for relevant entries. +- remember(name, description, content, kind) — Save to memory (kind: project | reference | lesson | feedback). +- recall(name?) — Read a specific memory entry, or list all if name is omitted. - forget(name) — Remove a memory entry. -- plan_enter() — Enter plan mode (for planning before changes). -- plan_ready() — Mark plan as ready for execution. +- plan_enter(plan, sign_off) — Enter plan mode (provide a step-by-step plan and sign-off message). +- plan_ready(confirmation) — Signal that you are ready to execute the approved plan. - seqthink(thought) — Record a chain-of-thought step. +- todowrite(task) — Append a task to the session todo list. +- todofinish(task_index?) — Mark a task (or all if omitted) as finished in todo.md. Workflow: - workflow_run(script, args) — Fan out work to sub-agents. Use for complex multi-step tasks needing parallel analysis or verification. Pass inline scripts with agent(), parallel(), and pipeline() primitives. +- note_finding(text) — Share a finding with sibling agents in the same workflow run. Language Server Protocol (LSP) tools: - lsp_connect(name, command, args?, language_id) — Start an LSP server for a diff --git a/src/tool/mod.rs b/src/tool/mod.rs index 7c3cfa0..ea503f2 100644 --- a/src/tool/mod.rs +++ b/src/tool/mod.rs @@ -158,6 +158,7 @@ pub fn all_tools() -> Vec> { Box::new(super::tool::utility::dir_cache_update::DirCacheUpdate), Box::new(super::tool::utility::pong::Pong), Box::new(super::tool::utility::todowrite::Todowrite), + Box::new(super::tool::utility::todofinish::Todofinish), Box::new(super::tool::lsp::LspConnect), Box::new(super::tool::lsp::LspDiagnostics), Box::new(super::tool::lsp::LspHover), diff --git a/src/tool/utility/mod.rs b/src/tool/utility/mod.rs index dd887d5..1f1568d 100644 --- a/src/tool/utility/mod.rs +++ b/src/tool/utility/mod.rs @@ -5,3 +5,4 @@ pub mod dir_cache_update; pub mod dir_list; pub mod pong; pub mod todowrite; +pub mod todofinish; diff --git a/src/tool/utility/todofinish.rs b/src/tool/utility/todofinish.rs new file mode 100644 index 0000000..51c8290 --- /dev/null +++ b/src/tool/utility/todofinish.rs @@ -0,0 +1,81 @@ +//! Tool for marking tasks as finished in the session's todo list. + +use serde_json::{json, Value}; +use anyhow::{Result, anyhow}; +use std::path::PathBuf; +use super::super::{Tool, ToolCtx}; + +/// Tool that marks tasks as finished in the session's todo.md. +pub struct Todofinish; + +impl Tool for Todofinish { + fn name(&self) -> &'static str { + "todofinish" + } + + 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 { + 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()); + } + + let content = std::fs::read_to_string(&path) + .map_err(|e| anyhow!("failed to read todo.md: {}", e))?; + + let task_index = args.get("task_index").and_then(|v| v.as_i64()); + + 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) + .map_err(|e| anyhow!("failed to write to todo.md: {}", e))?; + + if let Some(idx) = task_index { + Ok(format!("Successfully marked task {} as finished.", idx)) + } else { + Ok("Successfully marked ALL tasks as finished.".to_string()) + } + } +}