tandem-tools 0.6.0

Tooling and integrations for the Tandem engine
Documentation
use super::*;

#[tokio::test]
async fn repo_tools_index_and_query_structured_metadata() {
    let workspace = tempfile::tempdir().expect("workspace");
    std::fs::create_dir_all(workspace.path().join("src")).expect("src dir");
    std::fs::write(
        workspace.path().join("src/lib.rs"),
        "pub fn indexed_repo() {}\n",
    )
    .expect("write source");
    let args = json!({"__workspace_root": workspace.path(), "repo_path": "."});

    let index = RepoIndexTool.execute(args.clone()).await.expect("index");
    assert_eq!(index.metadata["structured"]["files"], json!(1));
    assert_eq!(
        index.metadata["structured"]["metrics"]["files_indexed"],
        json!(1)
    );
    assert!(index.metadata["structured"]["debug_export_path"]
        .as_str()
        .is_some_and(|path| path.ends_with(".tandem/repo-graph.json")));

    let search = RepoSearchTool
        .execute(json!({
            "__workspace_root": workspace.path(),
            "repo_path": ".",
            "query": "indexed",
            "path_scope": "."
        }))
        .await
        .expect("search");
    assert_eq!(search.metadata["structured"]["count"], json!(1));
    assert_eq!(search.metadata["index_source"], json!("stored"));
}

#[tokio::test]
async fn repo_context_bundle_tool_scopes_symbols() {
    let workspace = tempfile::tempdir().expect("workspace");
    std::fs::create_dir_all(workspace.path().join("packages/app/src")).expect("app dir");
    std::fs::create_dir_all(workspace.path().join("packages/admin/src")).expect("admin dir");
    std::fs::write(
        workspace.path().join("packages/app/src/login.rs"),
        "pub fn login_flow() {}\n",
    )
    .expect("write app");
    std::fs::write(
        workspace.path().join("packages/admin/src/login.rs"),
        "pub fn login_flow() {}\n",
    )
    .expect("write admin");
    let base = json!({"__workspace_root": workspace.path(), "repo_path": "."});
    RepoIndexTool.execute(base).await.expect("index");

    let result = RepoContextBundleTool
        .execute(json!({
            "__workspace_root": workspace.path(),
            "repo_path": ".",
            "task": "login flow",
            "path_scope": "packages/app",
            "limit": 10
        }))
        .await
        .expect("bundle");
    let symbols = result.metadata["structured"]["relevant_symbols"]
        .as_array()
        .expect("symbols");
    assert!(result.metadata["metrics"]["likely_files"]
        .as_u64()
        .is_some_and(|count| count >= 1));
    assert_eq!(result.metadata["metrics"]["relevant_symbols"], json!(1));
    assert!(symbols
        .iter()
        .any(|item| item["file_path"] == "packages/app/src/login.rs"));
    assert!(!symbols
        .iter()
        .any(|item| item["file_path"] == "packages/admin/src/login.rs"));
}

#[tokio::test]
async fn repo_search_fails_closed_without_readable_scope() {
    let workspace = tempfile::tempdir().expect("workspace");
    std::fs::create_dir_all(workspace.path().join("src")).expect("src dir");
    std::fs::write(
        workspace.path().join("src/lib.rs"),
        "pub fn indexed_repo() {}\n",
    )
    .expect("write source");
    RepoIndexTool
        .execute(json!({"__workspace_root": workspace.path(), "repo_path": "."}))
        .await
        .expect("index");

    let search = RepoSearchTool
        .execute(json!({
            "__workspace_root": workspace.path(),
            "repo_path": ".",
            "query": "indexed",
            "allowed_tools": ["repo.search"]
        }))
        .await
        .expect("search");

    assert_eq!(search.metadata["structured"]["count"], json!(0));
    assert_eq!(search.metadata["graph_query"]["denied_count"], json!(1));
    assert_eq!(
        search.metadata["graph_query"]["denied_reasons"],
        json!(["invalid_envelope:readable_paths"])
    );
}

#[tokio::test]
async fn repo_search_respects_explicit_tool_allowlist() {
    let workspace = tempfile::tempdir().expect("workspace");
    std::fs::create_dir_all(workspace.path().join("src")).expect("src dir");
    std::fs::write(
        workspace.path().join("src/lib.rs"),
        "pub fn indexed_repo() {}\n",
    )
    .expect("write source");
    RepoIndexTool
        .execute(json!({"__workspace_root": workspace.path(), "repo_path": "."}))
        .await
        .expect("index");

    let search = RepoSearchTool
        .execute(json!({
            "__workspace_root": workspace.path(),
            "repo_path": ".",
            "query": "indexed",
            "path_scope": ".",
            "allowed_tools": ["repo.symbol"]
        }))
        .await
        .expect("search");

    assert_eq!(search.metadata["structured"]["count"], json!(0));
    assert_eq!(search.metadata["graph_query"]["denied_count"], json!(1));
    assert_eq!(
        search.metadata["graph_query"]["denied_reasons"],
        json!(["tool_denied"])
    );
}