From b46793c326341c2e42e9a00e6475ecd5cadc31ca Mon Sep 17 00:00:00 2001 From: Hung Pham Date: Mon, 14 Sep 2026 06:01:39 +0700 Subject: [PATCH 1/2] Add subcommand `clean` and remove subcommand `doc` --- README.md | 11 +- crates/codegraph/src/main.rs | 237 +++++------------------------------ docs/architecture.md | 1 - 3 files changed, 40 insertions(+), 209 deletions(-) diff --git a/README.md b/README.md index 6e43a0d84..0146147ca 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ codegraph serve --mcp codegraph serve --mcp --http --addr 0.0.0.0:8123 ``` +Reset generated index data without losing `config.toml` with `codegraph clean` (or remove the whole `.codegraph/` with `codegraph deinit`). + The agent binds the workspace with `codegraph_init {"path": ...}` and gets tools like `codegraph_search_symbol`, `codegraph_flow`, `codegraph_callers`, `codegraph_impact`, `codegraph_context` — all querying over MCP. ## 📊 Comparison — Why Not X? @@ -63,13 +65,12 @@ CodeGraph supports parsing both **source code** (via tree-sitter) and **configur | Format | Extension | Parser | Access | |--------|-----------|--------|--------| -| YAML | `.yaml`, `.yml` | YamlParser | `codegraph doc ingest` / MCP | -| JSON | `.json` | JsonParser | `codegraph doc ingest` / MCP | -| TOML | `.toml` | TomlParser | `codegraph doc ingest` / MCP | -| **HCL** (HashiCorp) | `.hcl`, `.tf` | HclParser | `codegraph doc ingest` / MCP | +| YAML | `.yaml`, `.yml` | YamlParser | MCP | +| JSON | `.json` | JsonParser | MCP | +| TOML | `.toml` | TomlParser | MCP | +| **HCL** (HashiCorp) | `.hcl`, `.tf` | HclParser | MCP | Document files can be ingested into a **document graph** and queried via: -- **CLI**: `codegraph doc ingest `, `codegraph doc search`, `codegraph doc stats` - **MCP**: `codegraph_graphdoc_ingest`, `codegraph_graphdoc_search`, `codegraph_graphdoc_hydrate`, `codegraph_graphdoc_list`, `codegraph_graphdoc_stats` - **GraphQL**: `docList`, `docSearch`, `docStats` queries and `docIngest`, `docSearch`, `docStats` mutations diff --git a/crates/codegraph/src/main.rs b/crates/codegraph/src/main.rs index 825f76bb6..ffa488a66 100644 --- a/crates/codegraph/src/main.rs +++ b/crates/codegraph/src/main.rs @@ -48,6 +48,10 @@ enum Cmd { }, /// Remove the .codegraph/ directory. Deinit, + /// Remove generated index/data files inside .codegraph/ (db.sqlite, + /// docs store, …) while keeping config.toml, version and .gitignore — + /// the inverse of re-indexing: run `codegraph init` afterwards to rebuild. + Clean, /// Register codegraph as an MCP server for an AI agent (e.g. Claude Code), /// so the agent can launch `codegraph serve --mcp`. Writes the agent's config /// (e.g. `~/.claude/settings.json`). After a Homebrew install, this points @@ -129,11 +133,6 @@ enum Cmd { #[arg(long = "api-key")] api_key: Vec, }, - /// Document operations: ingest, search, hydrate, and manage structured documents (HCL, YAML, JSON, TOML, XML). - Doc { - #[command(subcommand)] - cmd: DocCmd, - }, } /// Giá trị `--format` của CLI — map sang `codegraph_mcp::OutputStyle`. @@ -153,67 +152,6 @@ impl OutputFormat { } } -/// Document CLI subcommands. -#[derive(Subcommand, Debug)] -enum DocCmd { - /// Parse and ingest a document file (HCL, YAML, JSON, TOML, XML). - Ingest { - /// Path to the document file. Đặt tên `file` — positional `path` đụng - /// global `--path` (Utf8PathBuf parser) làm clap panic khi parse args. - #[arg()] - file: String, - /// Override auto-detected format (hcl, yaml, json, toml, nginx). - #[arg(long)] - format: Option, - }, - /// Search document nodes by path pattern. - Search { - /// Search pattern (substring match on path tokens). - #[arg()] - pattern: String, - /// Search depth (default: 1). - #[arg(long, default_value_t = 1)] - depth: usize, - }, - /// Hydrate a node into a small payload for LLM reasoning. - Hydrate { - /// Node id to hydrate. - #[arg()] - node_id: u64, - }, - /// List all ingested documents with stats. - List, - /// Show document graph statistics. - Stats, - /// Mine structural patterns (kind chains ending at scalar leaves) across - /// all ingested documents and list them sorted by doc frequency ascending - /// — rare/characteristic patterns first, background noise last. - Patterns { - /// Max patterns to keep. - #[arg(long, default_value_t = 20)] - top_k: usize, - /// Min node occurrences for a pattern to be kept. - #[arg(long, default_value_t = 3)] - min_count: usize, - /// Max kind-chain window length ending at the leaf. - #[arg(long, default_value_t = 4)] - max_depth: usize, - }, - /// Search nodes by structural kind chain, ranked by IDF (rare structures - /// first), e.g. `codegraph doc struct "MAP, FIELD, NUMBER"`. - Struct { - /// Comma-separated kind labels: MAP, ARRAY, FIELD, INDEX, STRING, NUMBER, BOOL, NULL, ROOT. - #[arg()] - pattern: String, - /// Search depth (default: 1). - #[arg(long, default_value_t = 1)] - depth: usize, - /// Max results (default: 20). - #[arg(long, default_value_t = 20)] - limit: usize, - }, -} - #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt() @@ -241,6 +179,7 @@ async fn main() -> Result<()> { match cmd { Cmd::Init { no_index, progress } => cmd_init(&root, !no_index, progress).await, Cmd::Deinit => cmd_deinit(&root), + Cmd::Clean => cmd_clean(&root), Cmd::Doctor => cmd_doctor(&root).await, Cmd::Install { target, global } => cmd_install(&root, &target, global), Cmd::Uninstall { target, global } => cmd_uninstall(&root, &target, global), @@ -274,7 +213,6 @@ async fn main() -> Result<()> { ) .await } - Cmd::Doc { cmd } => cmd_doc(&root, cmd).await, } } @@ -412,6 +350,35 @@ fn cmd_deinit(root: &Utf8Path) -> Result<()> { Ok(()) } +/// `codegraph clean`: xoá dữ liệu index sinh ra trong `.codegraph/` (db.sqlite, +/// docs store, cache, …) nhưng giữ lại config.toml, version và .gitignore — +/// workspace vẫn initialized, chạy `codegraph init` sau để index lại. +fn cmd_clean(root: &Utf8Path) -> Result<()> { + const KEEP: [&str; 3] = ["config.toml", "version", ".gitignore"]; + let dir = codegraph_extract::project_dir(root); + if !dir.exists() { + eprintln!("no {dir} — nothing to clean"); + return Ok(()); + } + let mut removed = 0usize; + for entry in std::fs::read_dir(&dir)? { + let entry = entry?; + if KEEP.contains(&entry.file_name().to_string_lossy().as_ref()) { + continue; + } + let path = entry.path(); + if entry.file_type()?.is_dir() { + std::fs::remove_dir_all(&path)?; + } else { + std::fs::remove_file(&path)?; + } + removed += 1; + eprintln!("removed {}", path.display()); + } + eprintln!("cleaned {removed} item(s) in {dir} (config kept)"); + Ok(()) +} + /// `codegraph doctor`: in báo cáo chẩn đoán môi trường để người dùng (và agent) /// biết trạng thái hiện tại — đặc biệt hữu ích sau khi merge hỗ trợ Windows, vì /// codegraph giờ chạy cross-platform và có thể register cho nhiều agent (Claude, @@ -750,139 +717,3 @@ async fn cmd_serve( } codegraph_mcp::serve_stdio(server).await } - -/// `codegraph doc`: manage structured documents (HCL/Terraform, YAML, JSON, TOML). -/// Persist qua dataset docs theo config (`[docgraph]`/`[storage]`) — không còn -/// in-memory per-invocation. -async fn cmd_doc(root: &Utf8Path, cmd: DocCmd) -> Result<()> { - let mut graph = open_doc_graph(root).await?; - - match cmd { - DocCmd::Ingest { file, format } => { - let inserted = graph.ingest_file(&file, format.as_deref()).await?; - println!("ingested {file} → doc_id={inserted}"); - } - DocCmd::Search { pattern, depth } => { - use codegraph_docs::DocToken; - // Full path search qua trie; không match → fallback quét key. - let mut tokens = vec![DocToken::root()]; - let mut fuzzy_seg: Option = None; - for seg in pattern.split('.') { - if let Some(fz) = seg.strip_prefix('~') { - fuzzy_seg = Some(fz.to_string()); - break; - } - match graph.intern_id(seg) { - Some(id) => tokens.push(DocToken::field(id)), - None => break, - } - } - // Có segment `~` → bỏ qua full-path, đi thẳng fuzzy. - // depth = số tầng thừa dưới pattern; radix filter theo tổng key len. - let ids = if fuzzy_seg.is_none() { - let mut ids = graph - .search_path(&tokens, Some(tokens.len() - 1 + depth)) - .await - .unwrap_or_default(); - ids.extend(graph.search_path_scan(&tokens, 100)); - ids.sort_unstable(); - ids.dedup(); - ids - } else { - Vec::new() - }; - if ids.is_empty() { - let last = fuzzy_seg - .unwrap_or_else(|| pattern.rsplit('.').next().unwrap_or(&pattern).to_string()); - let hits = graph.search_key_fuzzy(&last, 50); - if hits.is_empty() { - println!("no nodes matched — key `{last}` not seen in any ingested document"); - return Ok(()); - } - for h in hits { - println!( - "node {} doc={} key={:?} score={:.3} kind={:?} value={:?}", - h.node.id, h.node.doc, h.matched_key, h.score, h.node.kind, h.node.value - ); - } - return Ok(()); - } - for id in ids.iter().take(100) { - if let Some(payload) = graph.hydrate_depth(*id, Some(1)).await { - let json = serde_json::to_string_pretty(&payload)?; - println!("{json}"); - } - } - } - DocCmd::Hydrate { node_id } => match graph.hydrate(node_id).await { - Some(payload) => { - let json = serde_json::to_string_pretty(&payload)?; - println!("{json}"); - } - None => println!("node {node_id} not found"), - }, - DocCmd::List => { - let stats = graph.stats().await?; - println!("documents: {}, nodes: {}", stats.docs, stats.nodes); - } - DocCmd::Stats => { - let stats = graph.stats().await?; - println!("documents: {}", stats.docs); - println!("nodes: {}", stats.nodes); - } - DocCmd::Patterns { - top_k, - min_count, - max_depth, - } => { - let mined = graph.mine_patterns(top_k, min_count, max_depth).await?; - if mined.is_empty() { - println!("no patterns matched (min_count={min_count})"); - } - for p in mined { - println!( - "P#{:<4} docs={:.1}% nodes={} chain={}", - p.pattern_id, - p.doc_freq * 100.0, - p.node_count, - p.tokens.join(" → ") - ); - } - } - DocCmd::Struct { - pattern, - depth, - limit, - } => { - let tokens: Vec = pattern - .split(',') - .filter_map(|s| { - let s = s.trim(); - (!s.is_empty()).then(|| codegraph_docs::parse_kind_label(s)) - }) - .collect(); - let ids = graph.search_kind_chain(&tokens, Some(depth)); - if ids.is_empty() { - println!("no nodes matched this structural pattern"); - return Ok(()); - } - let total_docs = graph.list_docs().len(); - let mut rows: Vec<(f64, u64)> = ids - .iter() - .take(limit * 5) - .map(|id| (graph.pattern_uniqueness(*id, total_docs), *id)) - .collect(); - rows.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal)); - for (idf, id) in rows.iter().take(limit) { - match graph.hydrate_depth(*id, Some(1)).await { - Some(p) => println!( - "node {} doc={} idf={:.3} path={:?} key={:?} value={:?}", - p.id, p.doc, idf, p.path, p.key, p.value - ), - None => continue, - } - } - } - } - Ok(()) -} diff --git a/docs/architecture.md b/docs/architecture.md index 59995b585..7c7be784d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -55,7 +55,6 @@ CodeGraph-docs supports parsing structured configuration and document files into Parsed documents are stored in a `DocumentGraph` backed by `codegraph-graph`'s `InMemoryStorage` (persistent tries) with `Search` indices for path, type, value, struct, and pattern queries. **Access points:** -- **CLI**: `codegraph doc ingest `, `codegraph doc search`, `codegraph doc hydrate `, `codegraph doc list`, `codegraph doc stats` - **MCP**: `codegraph_graphdoc_ingest`, `codegraph_graphdoc_search`, `codegraph_graphdoc_hydrate`, `codegraph_graphdoc_list`, `codegraph_graphdoc_stats` - **GraphQL**: `docList`, `docSearch`, `docStats` queries and `docIngest`, `docStats` mutations From 849930f92a0c8fd37df584a2385dab16aab96802 Mon Sep 17 00:00:00 2001 From: Hung Pham Date: Wed, 16 Sep 2026 08:04:29 +0700 Subject: [PATCH 2/2] Bump version to v2.2.2 --- Cargo.lock | 26 ++++++++++++------------- Cargo.toml | 2 +- packaging/aur/codegraph-rs-bin/PKGBUILD | 2 +- packaging/choco/codegraph.nuspec | 2 +- packaging/winget/codegraph.yaml | 4 ++-- scripts/install.ps1 | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 189c67426..5e67703a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,7 +720,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "codegraph" -version = "2.2.1" +version = "2.2.2" dependencies = [ "anyhow", "camino", @@ -743,7 +743,7 @@ dependencies = [ [[package]] name = "codegraph-api" -version = "2.2.1" +version = "2.2.2" dependencies = [ "anyhow", "camino", @@ -760,7 +760,7 @@ dependencies = [ [[package]] name = "codegraph-bench" -version = "2.2.1" +version = "2.2.2" dependencies = [ "anyhow", "camino", @@ -778,7 +778,7 @@ dependencies = [ [[package]] name = "codegraph-binary" -version = "2.2.1" +version = "2.2.2" dependencies = [ "camino", "codegraph-core", @@ -795,7 +795,7 @@ dependencies = [ [[package]] name = "codegraph-context" -version = "2.2.1" +version = "2.2.2" dependencies = [ "codegraph-core", "codegraph-graph", @@ -807,7 +807,7 @@ dependencies = [ [[package]] name = "codegraph-core" -version = "2.2.1" +version = "2.2.2" dependencies = [ "async-graphql", "camino", @@ -818,7 +818,7 @@ dependencies = [ [[package]] name = "codegraph-docs" -version = "2.2.1" +version = "2.2.2" dependencies = [ "anyhow", "codegraph-core", @@ -835,7 +835,7 @@ dependencies = [ [[package]] name = "codegraph-extract" -version = "2.2.1" +version = "2.2.2" dependencies = [ "camino", "codegraph-binary", @@ -874,7 +874,7 @@ dependencies = [ [[package]] name = "codegraph-graph" -version = "2.2.1" +version = "2.2.2" dependencies = [ "async-trait", "bincode", @@ -904,7 +904,7 @@ dependencies = [ [[package]] name = "codegraph-graphql" -version = "2.2.1" +version = "2.2.2" dependencies = [ "anyhow", "async-graphql", @@ -927,7 +927,7 @@ dependencies = [ [[package]] name = "codegraph-installer" -version = "2.2.1" +version = "2.2.2" dependencies = [ "anyhow", "camino", @@ -943,7 +943,7 @@ dependencies = [ [[package]] name = "codegraph-mcp" -version = "2.2.1" +version = "2.2.2" dependencies = [ "anyhow", "axum", @@ -966,7 +966,7 @@ dependencies = [ [[package]] name = "codegraph-sboxes" -version = "2.2.1" +version = "2.2.2" dependencies = [ "camino", "codegraph-core", diff --git a/Cargo.toml b/Cargo.toml index 021e59ff8..549f4865c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ members = [ ] [workspace.package] -version = "2.2.1" +version = "2.2.2" edition = "2021" rust-version = "1.80" license = "MIT" diff --git a/packaging/aur/codegraph-rs-bin/PKGBUILD b/packaging/aur/codegraph-rs-bin/PKGBUILD index a9a91060e..c1d568954 100644 --- a/packaging/aur/codegraph-rs-bin/PKGBUILD +++ b/packaging/aur/codegraph-rs-bin/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Hung Pham pkgname=codegraph-rs-bin -pkgver=2.2.1 +pkgver=2.2.2 pkgrel=1 pkgdesc="Local-first code intelligence: tree-sitter knowledge graph + MCP server (prebuilt binary)" arch=('x86_64' 'aarch64') diff --git a/packaging/choco/codegraph.nuspec b/packaging/choco/codegraph.nuspec index 07bd9593c..867b14fa7 100644 --- a/packaging/choco/codegraph.nuspec +++ b/packaging/choco/codegraph.nuspec @@ -2,7 +2,7 @@ codegraph - 2.2.1 + 2.2.2 codegraph Hung Pham https://github.com/hungpham10/codegraph-rs diff --git a/packaging/winget/codegraph.yaml b/packaging/winget/codegraph.yaml index 01448faab..1c421ed9f 100644 --- a/packaging/winget/codegraph.yaml +++ b/packaging/winget/codegraph.yaml @@ -6,7 +6,7 @@ # release time (or automate it in the release pipeline before submitting to # microsoft/winget-pkgs). PackageIdentifier: hungpham10.codegraph -PackageVersion: 2.2.1 +PackageVersion: 2.2.2 PackageName: codegraph Publisher: Hung Pham PublisherUrl: https://github.com/hungpham10/codegraph-rs @@ -18,7 +18,7 @@ PackageUrl: https://github.com/hungpham10/codegraph-rs InstallerType: zip Installers: - Architecture: x64 - InstallerUrl: https://github.com/hungpham10/codegraph-rs/releases/download/v2.2.1/codegraph-x86_64-pc-windows-msvc.zip + InstallerUrl: https://github.com/hungpham10/codegraph-rs/releases/download/v2.2.2/codegraph-x86_64-pc-windows-msvc.zip InstallerSha256: 0000000000000000000000000000000000000000000000000000000000000000 InstallerType: zip ManifestType: singleton diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 29344405b..c40b41887 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -5,11 +5,11 @@ # # Usage (pin a version / download the script first): # irm https://raw.githubusercontent.com/hungpham10/codegraph-rs/main/scripts/install.ps1 -OutFile install.ps1 -# .\install.ps1 -Version 2.2.1 +# .\install.ps1 -Version 2.2.2 [CmdletBinding()] param( - # Pin a specific version, e.g. "2.2.1". Empty = latest release. + # Pin a specific version, e.g. "2.2.2". Empty = latest release. [string]$Version )