#![allow(dead_code)]
use pathfinder_common::types::{ActionableGuidance, DegradedReason};
use rmcp::schemars;
use rmcp::serde::{self, Deserialize, Serialize};
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct SearchCodebaseParams {
pub query: String,
#[serde(default)]
pub is_regex: bool,
#[serde(default = "default_path_glob")]
pub path_glob: String,
#[serde(default)]
pub filter_mode: pathfinder_common::types::FilterMode,
#[serde(default = "default_max_results")]
pub max_results: u32,
#[serde(default = "default_context_lines")]
pub context_lines: u32,
#[serde(default)]
pub known_files: Vec<String>,
#[serde(default)]
pub group_by_file: bool,
#[serde(default)]
pub exclude_glob: String,
#[serde(default)]
pub offset: u32,
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct GetRepoMapParams {
#[serde(default = "default_repo_map_path")]
pub path: String,
#[serde(default = "default_max_tokens")]
pub max_tokens: u32,
#[serde(default = "default_depth")]
pub depth: u32,
#[serde(default)]
pub visibility: pathfinder_common::types::Visibility,
#[serde(default)]
pub include_imports: pathfinder_common::types::IncludeImports,
#[serde(default = "default_max_tokens_per_file")]
pub max_tokens_per_file: u32,
#[serde(default)]
pub changed_since: String,
#[serde(default)]
pub include_extensions: Vec<String>,
#[serde(default)]
pub exclude_extensions: Vec<String>,
#[serde(default = "default_true")]
pub include_tests: bool,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct SymbolOverviewParams {
pub semantic_path: String,
#[serde(default)]
pub project_only: Option<bool>,
#[serde(default = "default_max_references")]
pub max_callers_callees: u32,
#[serde(default = "default_max_references")]
pub max_references: u32,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct SymbolOverviewResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<SymbolSource>,
#[serde(skip_serializing_if = "Option::is_none")]
pub impact: Option<ImpactSummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub references: Option<Vec<SymbolOverviewReference>>,
pub files_referenced: usize,
pub degraded: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<DegradedReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actionable_guidance: Option<ActionableGuidance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lsp_readiness: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub warm_start_in_progress: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct SymbolSource {
pub content: String,
pub start_line: usize,
pub end_line: usize,
pub language: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct ImpactSummary {
#[serde(skip_serializing_if = "Option::is_none")]
pub incoming: Option<Vec<SymbolOverviewImpactEntry>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub outgoing: Option<Vec<SymbolOverviewImpactEntry>>,
pub degraded: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct SymbolOverviewImpactEntry {
pub semantic_path: String,
pub file: String,
pub line: usize,
pub snippet: String,
pub direction: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct SymbolOverviewReference {
pub file: String,
pub line: u32,
pub column: u32,
pub snippet: String,
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadSymbolScopeParams {
pub semantic_path: String,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadWithDeepContextParams {
pub semantic_path: String,
#[serde(default)]
pub project_only: Option<bool>,
#[serde(default = "default_max_dependencies")]
pub max_dependencies: u32,
}
impl Default for ReadWithDeepContextParams {
fn default() -> Self {
Self {
semantic_path: String::default(),
project_only: Some(true),
max_dependencies: default_max_dependencies(),
}
}
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct GetDefinitionParams {
pub semantic_path: String,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct AnalyzeImpactParams {
pub semantic_path: String,
#[serde(default = "default_max_depth")]
pub max_depth: u32,
#[serde(default)]
pub project_only: Option<bool>,
#[serde(default = "default_max_references")]
pub max_references: u32,
#[serde(default)]
pub include_test_coverage: bool,
}
impl Default for AnalyzeImpactParams {
fn default() -> Self {
Self {
semantic_path: String::default(),
max_depth: default_max_depth(),
project_only: Some(true),
max_references: default_max_references(),
include_test_coverage: false,
}
}
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadFileParams {
pub filepath: String,
#[serde(default = "default_start_line")]
pub start_line: u32,
#[serde(default = "default_max_lines")]
pub max_lines: u32,
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadSourceFileParams {
pub filepath: String,
#[serde(default = "default_detail_level")]
pub detail_level: String,
#[serde(default = "default_start_line")]
pub start_line: u32,
#[serde(default)]
pub end_line: Option<u32>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct SearchCodebaseResponse {
pub matches: Vec<pathfinder_search::SearchMatch>,
pub raw_match_count: usize,
pub total_matches: usize,
pub returned_count: usize,
pub filtered_count: usize,
pub files_searched: usize,
pub files_in_scope: usize,
pub coverage_percent: u8,
pub truncated: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_groups: Option<Vec<SearchResultGroup>>,
#[serde(default)]
pub degraded: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<DegradedReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_offset: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actionable_guidance: Option<ActionableGuidance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct GroupedKnownMatch {
pub line: u64,
pub column: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub enclosing_semantic_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_definition: Option<bool>,
pub known: bool,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct SearchResultGroup {
pub file: String,
pub version_hash: String,
pub total_matches: usize,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[schemars(skip)]
pub matches: Vec<GroupedMatch>,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[schemars(skip)]
pub known_matches: Vec<GroupedKnownMatch>,
}
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct GroupedMatch {
pub line: u64,
pub column: u64,
pub content: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub context_before: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub context_after: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enclosing_semantic_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_definition: Option<bool>,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct GetRepoMapMetadata {
pub tech_stack: Vec<String>,
pub files_scanned: usize,
pub files_truncated: usize,
pub files_in_scope: usize,
pub coverage_percent: u8,
pub version_hashes: std::collections::HashMap<String, String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility_degraded: Option<bool>,
#[serde(default)]
pub degraded: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<DegradedReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actionable_guidance: Option<ActionableGuidance>,
pub capabilities: RepoCapabilities,
pub max_tokens_used: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub lsp_status: Option<std::collections::HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct RepoCapabilities {
pub search: bool,
pub lsp: LspCapabilities,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct LspCapabilities {
pub supported: bool,
pub per_language: std::collections::HashMap<String, pathfinder_lsp::types::LspLanguageStatus>,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadSymbolScopeMetadata {
pub content: String,
pub start_line: usize,
pub end_line: usize,
pub language: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct SourceSymbol {
pub name: String,
pub semantic_path: String,
pub kind: String,
pub start_line: usize,
pub end_line: usize,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub children: Vec<Self>,
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadSourceFileMetadata {
pub language: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub symbols: Vec<SourceSymbol>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadFileMetadata {
pub start_line: u32,
pub lines_returned: u32,
pub total_lines: u32,
pub file_size_bytes: u64,
pub truncated: bool,
pub language: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct DeepContextDependency {
pub semantic_path: String,
pub signature: String,
pub file: String,
pub line: usize,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadWithDeepContextMetadata {
pub start_line: usize,
pub end_line: usize,
pub language: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub dependencies: Vec<DeepContextDependency>,
#[serde(default)]
pub degraded: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<DegradedReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actionable_guidance: Option<ActionableGuidance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lsp_readiness: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub warm_start_in_progress: Option<bool>,
pub dependencies_truncated: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolution_strategy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct GetDefinitionResponse {
pub file: String,
pub line: u32,
pub column: u32,
pub preview: String,
#[serde(default)]
pub degraded: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<DegradedReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actionable_guidance: Option<ActionableGuidance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lsp_readiness: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub warm_start_in_progress: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolution_strategy: Option<String>,
}
#[derive(Debug, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct ImpactReference {
pub semantic_path: String,
pub file: String,
pub line: usize,
pub snippet: String,
pub direction: String,
pub depth: usize,
}
#[derive(Debug, Default, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct AnalyzeImpactMetadata {
pub incoming: Option<Vec<ImpactReference>>,
pub outgoing: Option<Vec<ImpactReference>>,
pub depth_reached: u32,
pub files_referenced: usize,
pub degraded: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<DegradedReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actionable_guidance: Option<ActionableGuidance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lsp_readiness: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub warm_start_in_progress: Option<bool>,
pub references_truncated: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolution_strategy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub test_callers: Option<Vec<ImpactReference>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub test_coverage_status: Option<String>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct FindAllReferencesParams {
pub semantic_path: String,
#[serde(default = "default_max_references")]
pub max_results: u32,
#[serde(default)]
pub offset: u32,
}
#[derive(Debug, Default, Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct FindAllReferencesMetadata {
pub references: Option<Vec<ReferenceLocation>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_references: Option<usize>,
#[serde(skip_serializing_if = "std::ops::Not::not", default)]
pub truncated: bool,
pub files_referenced: usize,
pub degraded: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub degraded_reason: Option<DegradedReason>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actionable_guidance: Option<ActionableGuidance>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lsp_readiness: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub warm_start_in_progress: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolution_strategy: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct ReferenceLocation {
pub file: String,
pub line: u32,
pub column: u32,
pub snippet: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
pub struct DegradedToolInfo {
pub tool: String,
pub severity: String,
pub description: String,
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct LspHealthParams {
#[serde(default)]
pub language: Option<String>,
#[serde(default)]
pub action: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct LspHealthResponse {
pub status: String,
pub languages: Vec<LspLanguageHealth>,
pub warm_start_complete: bool,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub known_limitations: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct LspLanguageHealth {
pub language: String,
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub uptime: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub diagnostics_strategy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_call_hierarchy: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_diagnostics: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_definition: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexing_status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexing_source: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexing_duration_secs: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub navigation_ready: Option<bool>,
#[serde(skip_serializing_if = "crate::server::types::is_false", default)]
pub probe_verified: bool,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub install_hint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexing_progress_percent: Option<u8>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub degraded_tools: Vec<DegradedToolInfo>,
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct FindSymbolParams {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(default = "default_path_glob")]
pub path_glob: String,
#[serde(default = "find_symbol_default_max_results")]
pub max_results: u32,
}
#[must_use]
pub const fn find_symbol_default_max_results() -> u32 {
10
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct FoundSymbol {
pub semantic_path: String,
pub kind: String,
pub file: String,
pub line: u64,
pub preview: String,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct FindSymbolResponse {
pub symbols: Vec<FoundSymbol>,
pub total_found: u32,
pub search_strategy: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[derive(Debug, Default, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadFilesParams {
pub paths: Vec<String>,
#[serde(default = "read_files_default_detail_level")]
pub detail_level: String,
#[serde(default = "default_max_lines")]
pub max_lines_per_file: u32,
}
#[must_use]
pub fn read_files_default_detail_level() -> String {
"source_only".to_string()
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct FileResult {
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_lines: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version_hash: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
pub struct ReadFilesResponse {
pub files: Vec<FileResult>,
pub succeeded: u32,
pub failed: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
}
#[allow(clippy::trivially_copy_pass_by_ref)] pub(crate) fn is_false(b: &bool) -> bool {
!b
}
#[must_use]
pub fn default_path_glob() -> String {
"**/*".to_owned()
}
#[must_use]
pub const fn default_max_results() -> u32 {
50
}
#[must_use]
pub const fn default_context_lines() -> u32 {
2
}
#[must_use]
pub fn default_repo_map_path() -> String {
".".to_owned()
}
#[must_use]
pub const fn default_max_tokens() -> u32 {
16_000
}
#[must_use]
pub const fn default_max_tokens_per_file() -> u32 {
2_000
}
#[must_use]
pub const fn default_depth() -> u32 {
5
}
#[must_use]
pub const fn default_max_depth() -> u32 {
3
}
#[must_use]
pub const fn default_max_callers_callees() -> u32 {
20
}
#[must_use]
pub const fn default_max_references() -> u32 {
50
}
#[must_use]
pub const fn default_max_dependencies() -> u32 {
50
}
#[must_use]
pub const fn default_start_line() -> u32 {
1
}
#[must_use]
pub const fn default_max_lines() -> u32 {
500
}
#[must_use]
pub fn default_detail_level() -> String {
"compact".to_string()
}
#[must_use]
pub const fn default_true() -> bool {
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_read_with_deep_context_params_default() {
let params = ReadWithDeepContextParams::default();
assert_eq!(params.semantic_path, "");
assert_eq!(params.project_only, Some(true));
assert_eq!(params.max_dependencies, 50);
}
#[test]
fn test_analyze_impact_params_default() {
let params = AnalyzeImpactParams::default();
assert_eq!(params.semantic_path, "");
assert_eq!(params.max_depth, 3);
assert_eq!(params.project_only, Some(true));
assert_eq!(params.max_references, 50);
assert!(!params.include_test_coverage);
}
}