relay_knowledge/application/code_repository/repository/
mod.rs1#[cfg(test)]
2#[path = "mod_tests.rs"]
3mod mod_tests;
4mod staleness;
5mod status;
6#[cfg(test)]
7#[path = "test_support.rs"]
8mod test_support;
9mod worktree;
10#[cfg(test)]
11#[path = "worktree_review_tests.rs"]
12mod worktree_review_tests;
13
14use crate::{
15 api::{
16 ApiError, ApiMetadata, CodeRepositoryListResponse, CodeRepositoryRegisterRequest,
17 CodeRepositoryRegisterResponse, CodeRepositoryRemoveResponse, CodeRepositoryReportResponse,
18 CodeRepositoryStatusResponse, RequestContext,
19 },
20 code::{REGISTRATION_LANGUAGE_FILTER_ERROR, register_repository},
21 domain::CodeRepositorySelector,
22};
23
24use crate::application::service::RelayKnowledgeService;
25
26use super::{
27 blocking::run_blocking_code, clock::now_millis, errors::storage_api_error,
28 indexing::recover_code_index_task_leases,
29};
30
31pub(super) use staleness::annotate_query_result_staleness;
32pub(super) use status::{
33 code_status_checkpoint, registration_from_status, required_code_repository,
34};
35pub(super) use worktree::ensure_worktree_overlay_matches_current_worktree;
36
37impl RelayKnowledgeService {
38 pub async fn list_indexed_code_repositories(
40 &self,
41 context: RequestContext,
42 ) -> Result<CodeRepositoryListResponse, ApiError> {
43 let store = self.store().await.map_err(storage_api_error)?;
44 let repositories = store
45 .list_code_repositories()
46 .await
47 .map_err(storage_api_error)?
48 .into_iter()
49 .filter(|status| status.last_indexed_scope_id.is_some())
50 .collect();
51 let graph_version = store
52 .current_graph_version()
53 .await
54 .map_err(storage_api_error)?;
55
56 Ok(CodeRepositoryListResponse {
57 metadata: ApiMetadata::graph_only(&context, graph_version),
58 repositories,
59 })
60 }
61
62 pub async fn register_code_repository(
64 &self,
65 request: CodeRepositoryRegisterRequest,
66 context: RequestContext,
67 ) -> Result<CodeRepositoryRegisterResponse, ApiError> {
68 if !request.language_filters.is_empty() {
69 return Err(ApiError::invalid_argument(
70 REGISTRATION_LANGUAGE_FILTER_ERROR,
71 ));
72 }
73 let registration = run_blocking_code(move || {
74 register_repository(
75 request.root_path,
76 request.alias,
77 request.path_filters,
78 request.language_filters,
79 )
80 })
81 .await?;
82 let store = self.store().await.map_err(storage_api_error)?;
83 let status = store
84 .upsert_code_repository(registration.clone())
85 .await
86 .map_err(storage_api_error)?;
87 let _ = self.refresh_watched_code_repository(&status).await;
88 let graph_version = store
89 .current_graph_version()
90 .await
91 .map_err(storage_api_error)?;
92
93 Ok(CodeRepositoryRegisterResponse {
94 metadata: ApiMetadata::graph_only(&context, graph_version),
95 registration,
96 status,
97 })
98 }
99
100 pub async fn remove_code_repository(
102 &self,
103 repository: String,
104 context: RequestContext,
105 ) -> Result<CodeRepositoryRemoveResponse, ApiError> {
106 let store = self.store().await.map_err(storage_api_error)?;
107 let now_ms = now_millis();
108 recover_code_index_task_leases(&store, now_ms).await?;
109 let removed_status = required_code_repository(&store, &repository).await?;
110 let summary = store
111 .remove_code_repository(removed_status.repository_id.clone(), now_ms)
112 .await
113 .map_err(storage_api_error)?
114 .ok_or_else(|| {
115 ApiError::storage_unavailable("removed code repository disappeared before delete")
116 })?;
117 let _ = self
118 .remove_watched_code_repository(&removed_status.alias, &removed_status.repository_id)
119 .await;
120 let graph_version = store
121 .current_graph_version()
122 .await
123 .map_err(storage_api_error)?;
124
125 Ok(CodeRepositoryRemoveResponse {
126 metadata: ApiMetadata::graph_only(&context, graph_version),
127 removed_status,
128 summary,
129 })
130 }
131
132 pub async fn code_repository_status(
133 &self,
134 selector: CodeRepositorySelector,
135 context: RequestContext,
136 ) -> Result<CodeRepositoryStatusResponse, ApiError> {
137 let store = self.store().await.map_err(storage_api_error)?;
138 let status = required_code_repository(&store, &selector.repository).await?;
139 recover_code_index_task_leases(&store, now_millis()).await?;
140 let active_task = store
141 .active_code_index_task(status.repository_id.clone())
142 .await
143 .map_err(storage_api_error)?;
144 let checkpoint = code_status_checkpoint(&store, &status, active_task.as_ref()).await?;
145 let retention = store
146 .code_scope_retention(status.repository_id.clone())
147 .await
148 .map_err(storage_api_error)?;
149 let graph_version = store
150 .current_graph_version()
151 .await
152 .map_err(storage_api_error)?;
153
154 Ok(CodeRepositoryStatusResponse {
155 metadata: ApiMetadata::graph_only(&context, graph_version),
156 status,
157 active_task,
158 checkpoint,
159 retention,
160 })
161 }
162
163 pub(crate) async fn code_repository_is_registered(
164 &self,
165 repository: String,
166 ) -> Result<bool, ApiError> {
167 let selector = CodeRepositorySelector::new(repository, "HEAD", Vec::new(), Vec::new())
168 .map_err(|error| ApiError::invalid_argument(error.to_string()))?;
169 let store = self.store().await.map_err(storage_api_error)?;
170 store
171 .code_repository_status(selector.repository)
172 .await
173 .map(|status| status.is_some())
174 .map_err(storage_api_error)
175 }
176
177 pub async fn code_repository_report(
179 &self,
180 selector: CodeRepositorySelector,
181 context: RequestContext,
182 ) -> Result<CodeRepositoryReportResponse, ApiError> {
183 let store = self.store().await.map_err(storage_api_error)?;
184 let status = required_code_repository(&store, &selector.repository).await?;
185 let report = store
186 .code_repository_report(status.repository_id.clone())
187 .await
188 .map_err(storage_api_error)?;
189 let graph_version = store
190 .current_graph_version()
191 .await
192 .map_err(storage_api_error)?;
193
194 Ok(CodeRepositoryReportResponse {
195 metadata: ApiMetadata::graph_only(&context, graph_version),
196 scope: crate::api::CodeRepositoryScopeMetadata::from_status(
197 &status,
198 &selector,
199 selector.ref_selector.clone(),
200 ),
201 report,
202 })
203 }
204}