agentool 0.1.0

Rust toolkit for AI agents: JSON Schema-defined tools for workspace files, search, web, Markdown, Git, memory, human-in-the-loop hooks, and todos.
Documentation
use std::fs;
use std::path::PathBuf;

use serde_json::{json, Value};

use crate::core::json::{json_str, ok_data};
use crate::core::path::{map_io_error, resolve_against_workspace_root};
use crate::tool::{ToolError, ToolResult};

use super::error::{tool_error, MdErrorCode};

use super::markdown::{document_stats, extract_toc};
use super::MdContext;

fn resolve_path(ctx: &MdContext, user: &str) -> Result<PathBuf, ToolError> {
    resolve_against_workspace_root(&ctx.root_canonical, ctx.allow_outside_root, user)
}

pub(crate) fn op_extract_toc(ctx: &MdContext, params: &Value) -> ToolResult {
    let path = json_str(params, "path")?;
    let resolved = resolve_path(ctx, path)?;
    if !resolved.is_file() {
        return Err(tool_error(
            MdErrorCode::InvalidPath,
            "path is not a regular file",
        ));
    }
    let text = fs::read_to_string(&resolved).map_err(|e| map_io_error(e, "read markdown file"))?;
    let toc = extract_toc(&text);
    let path_display = resolved.display().to_string();
    Ok(ok_data(json!({
        "path": path_display,
        "toc": toc,
    })))
}

pub(crate) fn op_markdown_stats(ctx: &MdContext, params: &Value) -> ToolResult {
    let path = json_str(params, "path")?;
    let resolved = resolve_path(ctx, path)?;
    if !resolved.is_file() {
        return Err(tool_error(
            MdErrorCode::InvalidPath,
            "path is not a regular file",
        ));
    }
    let text = fs::read_to_string(&resolved).map_err(|e| map_io_error(e, "read markdown file"))?;
    let stats = document_stats(&text);
    let path_display = resolved.display().to_string();
    Ok(ok_data(json!({
        "path": path_display,
        "characters": stats.characters,
        "paragraphs": stats.paragraphs,
        "headings": stats.headings,
        "lines": stats.lines,
    })))
}