vibe_graph_ops/
responses.rs1use std::path::PathBuf;
7use std::time::SystemTime;
8
9use serde::{Deserialize, Serialize};
10use vibe_graph_core::{GitChangeSnapshot, SourceCodeGraph};
11
12use crate::project::Project;
13use crate::store::Manifest;
14use crate::workspace::WorkspaceInfo;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct SyncResponse {
19 pub project: Project,
21
22 pub workspace: WorkspaceInfo,
24
25 pub path: PathBuf,
27
28 pub snapshot_created: Option<PathBuf>,
30
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub remote: Option<String>,
34}
35
36impl SyncResponse {
37 pub fn file_count(&self) -> usize {
39 self.project.total_sources()
40 }
41
42 pub fn repo_count(&self) -> usize {
44 self.project.repositories.len()
45 }
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct GraphResponse {
51 pub graph: SourceCodeGraph,
53
54 pub saved_path: PathBuf,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub output_path: Option<PathBuf>,
60
61 pub from_cache: bool,
63}
64
65impl GraphResponse {
66 pub fn node_count(&self) -> usize {
68 self.graph.node_count()
69 }
70
71 pub fn edge_count(&self) -> usize {
73 self.graph.edge_count()
74 }
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct StatusResponse {
80 pub workspace: WorkspaceInfo,
82
83 pub store_exists: bool,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub manifest: Option<Manifest>,
89
90 pub snapshot_count: usize,
92
93 pub store_size: u64,
95
96 #[serde(default)]
98 pub repositories: Vec<String>,
99}
100
101impl StatusResponse {
102 pub fn is_synced(&self) -> bool {
104 self.store_exists && self.manifest.is_some()
105 }
106
107 pub fn time_since_sync(&self) -> Option<std::time::Duration> {
109 self.manifest
110 .as_ref()
111 .and_then(|m| m.last_sync.elapsed().ok())
112 }
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct LoadResponse {
118 pub project: Project,
120
121 pub manifest: Manifest,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct ComposeResponse {
128 pub content: String,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub output_path: Option<PathBuf>,
134
135 pub project_name: String,
137
138 pub file_count: usize,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct CleanResponse {
145 pub path: PathBuf,
147
148 pub cleaned: bool,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct GitChangesResponse {
155 pub changes: GitChangeSnapshot,
157
158 pub change_count: usize,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct OperationSummary {
165 pub success: bool,
167
168 pub operation: String,
170
171 pub duration_ms: u64,
173
174 pub timestamp: SystemTime,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub message: Option<String>,
180}
181
182impl OperationSummary {
183 pub fn success(operation: impl Into<String>, duration_ms: u64) -> Self {
185 Self {
186 success: true,
187 operation: operation.into(),
188 duration_ms,
189 timestamp: SystemTime::now(),
190 message: None,
191 }
192 }
193
194 pub fn failure(operation: impl Into<String>, message: impl Into<String>) -> Self {
196 Self {
197 success: false,
198 operation: operation.into(),
199 duration_ms: 0,
200 timestamp: SystemTime::now(),
201 message: Some(message.into()),
202 }
203 }
204
205 pub fn with_message(mut self, message: impl Into<String>) -> Self {
207 self.message = Some(message.into());
208 self
209 }
210}