Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 66 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ blake3 = "1"
walkdir = "2"
glob = "0.3"
rusqlite = { version = "0.31", features = ["bundled"] }
tree-sitter = "0.24"
tree-sitter-rust = "0.23"
tree-sitter = "0.26"
tree-sitter-rust = "0.24"
async-graphql = { version = "7", features = ["chrono"] }
async-graphql-axum = "7"
axum = "0.8"
Expand Down
2 changes: 2 additions & 0 deletions crates/spy-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ spy-core = { workspace = true }
spy-storage = { workspace = true }
spy-indexer = { workspace = true }
spy-graph = { workspace = true }
spy-git = { workspace = true }
spy-mcp = { workspace = true }
clap = { workspace = true }
anyhow = { workspace = true }
serde = { workspace = true }
Expand Down
47 changes: 40 additions & 7 deletions crates/spy-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,36 +181,69 @@ async fn cmd_search(text: String, kind: Option<String>) -> Result<()> {
Ok(())
}

async fn cmd_callers(node_id: String, _depth: i32) -> Result<()> {
async fn cmd_callers(node_id: String, depth: i32) -> Result<()> {
let config = load_config()?;
let storage = Storage::open(&config.db_path)?;

let edges = storage.get_incoming_edges(&node_id, EdgeKind::Calls)?;

println!("Callers of {}:", node_id);
println!("Callers of {} (depth {}):", node_id, depth);
for edge in edges {
println!(" {} (confidence: {:.2})", edge.from_id, edge.confidence);
}

Ok(())
}

async fn cmd_callees(node_id: String, _depth: i32) -> Result<()> {
async fn cmd_callees(node_id: String, depth: i32) -> Result<()> {
let config = load_config()?;
let storage = Storage::open(&config.db_path)?;

let edges = storage.get_edges(&node_id, EdgeKind::Calls)?;

println!("Callees of {}:", node_id);
println!("Callees of {} (depth {}):", node_id, depth);
for edge in edges {
println!(" {} (confidence: {:.2})", edge.to_id, edge.confidence);
}

Ok(())
}

async fn cmd_changed(_git_ref: String) -> Result<()> {
println!("Changed since: Not implemented (git stub)");
async fn cmd_changed(git_ref: String) -> Result<()> {
let config = load_config()?;
let storage = Storage::open(&config.db_path)?;

let repo = spy_git::GitRepo::discover(std::path::Path::new("."))
.context("Failed to inspect git repository")?;

let Some(repo) = repo else {
anyhow::bail!("Not inside a git repository");
};

let changed_paths = repo
.files_changed_since_ref(&git_ref)
.context("Failed to compute changed files")?;

if changed_paths.is_empty() {
println!("No changed files since {}", git_ref);
return Ok(());
}

let path_strings: Vec<String> = changed_paths
.iter()
.map(|p| p.to_string_lossy().into_owned())
.collect();

let nodes = storage.get_nodes_for_files(&path_strings)?;

println!("Nodes changed since {}:", git_ref);
for node in &nodes {
println!(" {} ({}) — {}", node.node_id, node.kind, node.name);
}
if nodes.is_empty() {
println!(" (no indexed nodes in changed files)");
}

Ok(())
}

Expand All @@ -233,7 +266,7 @@ async fn cmd_stats() -> Result<()> {

async fn cmd_serve(mcp: bool, http: bool, port: u16) -> Result<()> {
if mcp {
println!("MCP server: Not implemented (stub)");
spy_mcp::run_mcp_server(std::path::Path::new("spy.config.json")).await?;
return Ok(());
}

Expand Down
Loading