1use serde::{Deserialize, Serialize};
4
5use crate::domain::{EvidenceSpan, IndexKind, IndexState};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct FileIndexRoot {
10 pub scope_id: String,
11 pub root_id: String,
12 pub root_path: String,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct FileIndexEntry {
18 pub scope_id: String,
19 pub root_id: String,
20 pub path: String,
21 pub relative_path: String,
22 pub file_name: String,
23 pub extension: Option<String>,
24 pub parent_dir: String,
25 pub size_bytes: u64,
26 pub modified_at_ms: u64,
27 pub fingerprint: String,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct FileIndexRootUpdate {
33 pub root: FileIndexRoot,
34 pub entries: Vec<FileIndexEntry>,
35 pub processed_content_paths: std::collections::BTreeSet<String>,
36 pub content_entries: Vec<FileContentEntry>,
37 pub scan_error_count: usize,
38 pub truncated: bool,
39 pub content_truncated: bool,
40 pub content_read_error_count: usize,
41 pub last_error: Option<String>,
42 pub now_ms: u64,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47pub struct FileIndexRootStatus {
48 pub scope_id: String,
49 pub root_id: String,
50 pub root_path: String,
51 pub indexed_file_count: usize,
52 pub missing_file_count: usize,
53 pub scan_error_count: usize,
54 pub truncated: bool,
55 #[serde(default)]
56 pub content_truncated: bool,
57 #[serde(default)]
58 pub content_read_error_count: usize,
59 pub indexed_content_count: usize,
60 pub skipped_content_count: usize,
61 pub unchanged_content_count: usize,
62 pub stale_content_cursor_count: usize,
63 pub last_indexed_at_ms: Option<u64>,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub last_error: Option<String>,
66}
67
68#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
70pub struct FileIndexScanSummary {
71 pub root_count: usize,
72 pub indexed_file_count: usize,
73 pub missing_file_count: usize,
74 pub indexed_content_count: usize,
75 pub skipped_content_count: usize,
76 pub unchanged_content_count: usize,
77 pub stale_content_cursor_count: usize,
78 pub scan_error_count: usize,
79 pub content_read_error_count: usize,
80 pub truncated_root_count: usize,
81 pub roots: Vec<FileIndexRootStatus>,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
86pub struct FileSearchRequest {
87 pub query: String,
88 pub source_scope: Option<String>,
89 pub root_id: Option<String>,
90 pub limit: usize,
91 pub timeout_ms: u64,
92}
93
94#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
96pub struct FileSearchHit {
97 pub scope_id: String,
98 pub root_id: String,
99 pub path: String,
100 pub relative_path: String,
101 pub file_name: String,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub extension: Option<String>,
104 pub parent_dir: String,
105 pub size_bytes: u64,
106 pub modified_at_ms: u64,
107 pub status: String,
108 pub rank: usize,
109 pub score: f64,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct FileContentChunk {
115 pub chunk_index: usize,
116 pub start_byte: u32,
117 pub end_byte: u32,
118 pub start_line: u32,
119 pub end_line: u32,
120 pub content: String,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq)]
125pub struct FileContentEntry {
126 pub scope_id: String,
127 pub root_id: String,
128 pub path: String,
129 pub relative_path: String,
130 pub fingerprint: String,
131 pub content_hash: String,
132 pub indexed_at_ms: u64,
133 pub graph_version: u64,
134 pub chunks: Vec<FileContentChunk>,
135 pub skipped_reason: Option<String>,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140pub struct FileContentReadModelCursor {
141 pub kind: IndexKind,
142 pub source_scope: String,
143 pub root_id: String,
144 pub path: String,
145 pub content_hash: String,
146 pub indexed_graph_version: u64,
147 pub state: IndexState,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub stale_reason: Option<String>,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
154pub struct FileKnowledgeFactCandidate {
155 pub candidate_id: String,
156 pub kind: String,
157 pub subject: String,
158 pub predicate: String,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub object: Option<String>,
161 pub confidence_basis_points: u16,
162 pub status: String,
163 pub source_scope: String,
164 pub source_path: String,
165 pub span: EvidenceSpan,
166 pub fingerprint: String,
167 pub freshness_cursor: String,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq)]
172pub struct FileContentSearchRequest {
173 pub query: String,
174 pub source_scope: Option<String>,
175 pub root_id: Option<String>,
176 pub authorized_roots: Vec<FileIndexRoot>,
177 pub limit: usize,
178 pub timeout_ms: u64,
179}
180
181#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
183pub struct FileContentSearchHit {
184 pub scope_id: String,
185 pub root_id: String,
186 pub path: String,
187 pub relative_path: String,
188 pub chunk_id: String,
189 pub content_role: String,
190 pub excerpt: String,
191 pub span: EvidenceSpan,
192 pub fingerprint: String,
193 pub content_hash: String,
194 pub indexed_at_ms: u64,
195 pub graph_version: u64,
196 pub indexed_graph_version: u64,
197 pub freshness_cursor: String,
198 pub rank: usize,
199 pub score: f64,
200 pub ranking_signals: Vec<String>,
201 pub fact_candidates: Vec<FileKnowledgeFactCandidate>,
202}
203
204#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
206pub struct FileIndexDiagnostics {
207 pub root_count: usize,
208 pub indexed_file_count: usize,
209 pub missing_file_count: usize,
210 pub indexed_content_count: usize,
211 pub skipped_content_count: usize,
212 pub unchanged_content_count: usize,
213 pub stale_content_cursor_count: usize,
214 pub scan_error_count: usize,
215 pub content_read_error_count: usize,
216 pub truncated_root_count: usize,
217 pub roots: Vec<FileIndexRootStatus>,
218 pub content_cursors: Vec<FileContentReadModelCursor>,
219}