Skip to main content

tessera_codegraph/
lib.rs

1//! # tessera-codegraph
2//!
3//! Local semantic code graph for AI coding agents. Index a repository into
4//! SQLite + a memory-mapped snapshot; ask deterministic questions about
5//! symbols, references, blast radius, and hallucinated identifiers.
6//!
7//! ```no_run
8//! use tessera_codegraph::{Index, IndexOptions};
9//!
10//! # fn main() -> anyhow::Result<()> {
11//! Index::build("./my-repo", "./my-repo/.tessera/tessera.db", IndexOptions::default())?;
12//! let idx = Index::open("./my-repo/.tessera/tessera.db")?;
13//! let impact = idx.impact("findById", 4)?;
14//! for caller in impact.callers.iter().take(5) {
15//!     println!(
16//!         "{:5.1}  {} @ {}:{}",
17//!         caller.criticality,
18//!         caller.symbol.qualified_name,
19//!         caller.symbol.path,
20//!         caller.symbol.start_line
21//!     );
22//! }
23//! # Ok(())
24//! # }
25//! ```
26//!
27//! The library binary `tessera` is also built from this crate; see the README.
28
29pub mod bench;
30pub mod bloom;
31pub mod completions;
32pub mod config;
33pub mod db;
34pub mod doctor;
35pub mod engine;
36pub mod indexer;
37pub mod init;
38pub mod mcp;
39pub mod mcp_http;
40pub mod query;
41pub mod snapshot;
42pub mod types;
43pub mod watch;
44
45use std::path::{Path, PathBuf};
46
47use anyhow::Result;
48use rusqlite::Connection;
49
50pub use indexer::{IndexMode, IndexOptions, IndexReport};
51pub use query::{ExportGroupBy, ExportOptions};
52pub use types::{
53    AlternativeQuery, BenchQuery, BenchResult, BenchSavings, ConnectResult, ContextPack,
54    CriticalityBreakdown, DefinitionResult, DiffChangedSymbol, DiffImpactResult,
55    DiffImpactedSymbol, EditPrepResult, ExpandResult, ExportResult, GraphEngineKind, ImpactCaller,
56    ImpactResult, ImportRecord, ImportedByResult, ImportsResult, KindCount, Language,
57    LanguageCount, OutlineResult, PlanQueryResult, PlanStep, QueryMeta, ReferenceRecord,
58    ReferencesResult, SearchHit, SearchOptions, SearchResult, Sibling, SiblingsResult,
59    SignatureLine, SignatureResult, SnippetReferenceCheck, StatsResult, SymbolRecord,
60    SymbolSuggestion, TestsForResult, TopFanout, UnusedOptions, UnusedResult, UnusedSymbol,
61    ValidateResult, ValidateSnippetResult,
62};
63
64/// High-level handle to a Tessera index. Holds a single SQLite connection and,
65/// when present, a memory-mapped snapshot for hot-path queries.
66pub struct Index {
67    conn: Connection,
68    db_path: PathBuf,
69}
70
71impl Index {
72    /// Open an existing index. Returns an error if the database doesn't exist
73    /// or can't be migrated to the current schema.
74    pub fn open(db_path: impl AsRef<Path>) -> Result<Self> {
75        let db_path = db_path.as_ref().to_path_buf();
76        let conn = db::open_existing(&db_path)?;
77        Ok(Self { conn, db_path })
78    }
79
80    /// Build (or refresh) an index from a repository on disk. This is the
81    /// library equivalent of `tessera index <root>`.
82    pub fn build(
83        root: impl AsRef<Path>,
84        db_path: impl AsRef<Path>,
85        options: IndexOptions,
86    ) -> Result<IndexReport> {
87        indexer::index_path_with(root.as_ref(), db_path.as_ref(), options)
88    }
89
90    pub fn db_path(&self) -> &Path {
91        &self.db_path
92    }
93
94    pub fn connection(&self) -> &Connection {
95        &self.conn
96    }
97
98    pub fn find_definition(&self, symbol: &str) -> Result<DefinitionResult> {
99        query::find_definition_conn(&self.conn, symbol)
100    }
101
102    pub fn find_references(&self, symbol: &str) -> Result<ReferencesResult> {
103        query::find_references_conn(&self.conn, symbol)
104    }
105
106    pub fn outline(&self, path: impl AsRef<Path>) -> Result<OutlineResult> {
107        query::get_outline_conn(&self.conn, path.as_ref())
108    }
109
110    pub fn expand(&self, symbol: &str) -> Result<ExpandResult> {
111        query::expand_symbol_conn(&self.conn, symbol)
112    }
113
114    pub fn impact(&self, symbol: &str, depth: usize) -> Result<ImpactResult> {
115        query::impact_conn(&self.conn, symbol, depth)
116    }
117
118    pub fn validate(&self, symbol: &str) -> Result<ValidateResult> {
119        query::validate_conn(&self.conn, symbol)
120    }
121
122    pub fn validate_snippet(
123        &self,
124        code: &str,
125        language: Language,
126    ) -> Result<ValidateSnippetResult> {
127        query::validate_snippet_conn(&self.conn, code, language)
128    }
129
130    pub fn stats(&self) -> Result<StatsResult> {
131        query::stats_conn(&self.conn, &self.db_path)
132    }
133
134    pub fn tests_for(&self, symbol: &str) -> Result<TestsForResult> {
135        query::tests_for_conn(&self.conn, symbol)
136    }
137
138    pub fn connect(&self, from: &str, to: &str, depth: usize) -> Result<ConnectResult> {
139        query::connect_conn(&self.conn, from, to, depth)
140    }
141
142    pub fn export(
143        &self,
144        format: &str,
145        from: Option<&str>,
146        depth: usize,
147        limit: usize,
148    ) -> Result<ExportResult> {
149        query::export_conn(&self.conn, format, from, depth, limit)
150    }
151
152    pub fn export_with_options(&self, options: ExportOptions) -> Result<ExportResult> {
153        query::export_conn_with_options(&self.conn, options)
154    }
155
156    pub fn search(&self, pattern: &str, options: SearchOptions) -> Result<SearchResult> {
157        query::search_conn(&self.conn, pattern, options)
158    }
159
160    pub fn unused(&self, options: UnusedOptions) -> Result<UnusedResult> {
161        query::unused_conn(&self.conn, options)
162    }
163
164    pub fn context_pack(&self, symbol: &str, budget_tokens: usize) -> Result<ContextPack> {
165        query::context_pack_conn(&self.conn, symbol, budget_tokens)
166    }
167
168    pub fn plan_query(&self, task: &str, symbol: Option<&str>) -> PlanQueryResult {
169        query::plan_query(task, symbol)
170    }
171
172    pub fn edit_prep(&self, symbol: &str, budget_tokens: usize) -> Result<EditPrepResult> {
173        query::edit_prep_conn(&self.conn, symbol, budget_tokens)
174    }
175
176    pub fn diff_impact(
177        &self,
178        from_ref: &str,
179        to_ref: Option<&str>,
180        depth: usize,
181    ) -> Result<DiffImpactResult> {
182        query::diff_impact_conn(&self.conn, from_ref, to_ref, depth)
183    }
184
185    pub fn imports(&self, path: &str) -> Result<ImportsResult> {
186        query::imports_conn(&self.conn, path)
187    }
188
189    pub fn imported_by(&self, source: &str) -> Result<ImportedByResult> {
190        query::imported_by_conn(&self.conn, source)
191    }
192
193    pub fn signature(&self, symbol: &str) -> Result<SignatureResult> {
194        query::signature_conn(&self.conn, symbol)
195    }
196
197    pub fn siblings(&self, symbol: &str) -> Result<SiblingsResult> {
198        query::siblings_conn(&self.conn, symbol)
199    }
200}