Skip to main content

foundry_mcp/types/
responses.rs

1//! JSON response structures for CLI commands
2
3use super::spec::SpecContentData;
4use serde::{Deserialize, Serialize};
5
6/// Generic response wrapper for all CLI commands
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct FoundryResponse<T> {
9    /// Command-specific data payload
10    pub data: T,
11    /// Validation status of the operation
12    pub validation_status: ValidationStatus,
13    /// Suggested next actions for LLM consumption (only included when relevant)
14    #[serde(skip_serializing_if = "Vec::is_empty")]
15    pub next_steps: Vec<String>,
16    /// Optional workflow guidance hints (only included when relevant)
17    #[serde(skip_serializing_if = "Vec::is_empty")]
18    pub workflow_hints: Vec<String>,
19}
20
21/// Validation status for operations
22#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
23#[serde(rename_all = "lowercase")]
24pub enum ValidationStatus {
25    /// Operation completed successfully with all validations passing
26    Complete,
27    /// Operation completed but with some validation warnings
28    Incomplete,
29    /// Operation failed due to validation errors
30    Error,
31}
32
33/// Response for create_project command
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct CreateProjectResponse {
36    pub project_name: String,
37    pub created_at: String,
38    pub project_path: String,
39    /// List of files created (only included if files were created)
40    #[serde(skip_serializing_if = "Vec::is_empty")]
41    pub files_created: Vec<String>,
42}
43
44/// Response for list_projects command
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct ListProjectsResponse {
47    pub projects: Vec<ProjectInfo>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct ProjectInfo {
52    pub name: String,
53    pub created_at: String,
54    pub spec_count: usize,
55    pub path: String,
56}
57
58/// Response for list_specs command
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct ListSpecsResponse {
61    pub project_name: String,
62    pub specs: Vec<SpecInfo>,
63    pub total_count: usize,
64}
65
66/// Response for load_project command
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct LoadProjectResponse {
69    pub project: ProjectContext,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct ProjectContext {
74    pub name: String,
75    pub vision: String,
76    pub tech_stack: String,
77    pub summary: String,
78    pub created_at: String,
79    /// List of available specs (only included if specs exist)
80    #[serde(skip_serializing_if = "Vec::is_empty")]
81    pub specs_available: Vec<String>,
82}
83
84/// Response for create_spec command
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct CreateSpecResponse {
87    pub project_name: String,
88    pub spec_name: String,
89    pub created_at: String,
90    pub spec_path: String,
91    /// List of files created (only included if files were created)
92    #[serde(skip_serializing_if = "Vec::is_empty")]
93    pub files_created: Vec<String>,
94}
95
96/// Response for load_spec command
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct LoadSpecResponse {
99    pub project_name: String,
100    pub project_summary: String,
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub spec_name: Option<String>,
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub created_at: Option<String>,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub spec_content: Option<SpecContent>,
107    #[serde(skip_serializing_if = "Vec::is_empty")]
108    pub available_specs: Vec<SpecInfo>,
109    /// Indicates if fuzzy matching was used
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub match_info: Option<MatchInfo>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct SpecInfo {
116    pub name: String,
117    pub feature_name: String,
118    pub created_at: String,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct MatchInfo {
123    pub requested_spec: String,
124    pub matched_spec: String,
125    pub match_type: String, // "exact", "feature_fuzzy", "name_fuzzy"
126    pub confidence: f32,    // 0.0 to 1.0
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct SpecContent {
131    pub content: SpecContentData,
132}
133
134/// Response for analyze_project command
135#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct AnalyzeProjectResponse {
137    pub project_name: String,
138    pub files_created: Vec<String>,
139}
140
141/// Response for get_foundry_help command
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct GetFoundryHelpResponse {
144    pub topic: String,
145    pub content: HelpContent,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct HelpContent {
150    pub title: String,
151    pub description: String,
152    pub examples: Vec<String>,
153    pub workflow_guide: Vec<String>,
154}
155
156/// Response for validate_content command
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct ValidateContentResponse {
159    pub content_type: String,
160    pub is_valid: bool,
161    pub validation_errors: Vec<String>,
162    pub suggestions: Vec<String>,
163}
164
165/// Response for update_spec command
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct UpdateSpecResponse {
168    pub project_name: String,
169    pub spec_name: String,
170    pub files_updated: Vec<FileUpdateResult>,
171    pub total_files_updated: usize,
172}
173
174/// Individual file update result within a multi-file update operation
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct FileUpdateResult {
177    /// Type of file updated ("spec", "tasks", or "notes")
178    pub file_type: String,
179    /// Operation performed ("replace", "append", or "context_patch")
180    pub operation_performed: String,
181    /// Full path to the updated file
182    pub file_path: String,
183    /// Length of final content in characters
184    pub content_length: usize,
185    /// Whether the update operation succeeded
186    pub success: bool,
187    /// Error message if the operation failed (None if successful)
188    #[serde(skip_serializing_if = "Option::is_none")]
189    pub error_message: Option<String>,
190    /// Number of lines modified (when applicable for edit commands)
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub lines_modified: Option<usize>,
193    /// Type of content change applied (e.g., command effect summary)
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub patch_type: Option<String>,
196    /// Confidence score of context match (0.0 to 1.0)
197    #[serde(skip_serializing_if = "Option::is_none")]
198    pub match_confidence: Option<f32>,
199}
200
201#[derive(Serialize, Debug, Clone)]
202pub struct EditCommandsResponsePayload {
203    pub applied_count: usize,
204    pub skipped_idempotent_count: usize,
205    pub file_updates: Vec<crate::types::edit_commands::FileUpdateSummary>,
206    #[serde(skip_serializing_if = "Option::is_none")]
207    pub errors: Option<Vec<crate::types::edit_commands::EditCommandError>>,
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub preview_diff: Option<String>,
210}
211
212/// Response for delete_spec command
213#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct DeleteSpecResponse {
215    pub project_name: String,
216    pub spec_name: String,
217    pub spec_path: String,
218    /// List of files deleted (only included if files were deleted)
219    #[serde(skip_serializing_if = "Vec::is_empty")]
220    pub files_deleted: Vec<String>,
221}
222
223/// Response for install command
224#[derive(Debug, Clone, Serialize, Deserialize)]
225pub struct InstallResponse {
226    pub target: String,
227    pub binary_path: String,
228    pub config_path: String,
229    pub installation_status: InstallationStatus,
230    /// List of actions taken during installation (only included if actions were taken)
231    #[serde(skip_serializing_if = "Vec::is_empty")]
232    pub actions_taken: Vec<String>,
233}
234
235/// Response for uninstall command
236#[derive(Debug, Clone, Serialize, Deserialize)]
237pub struct UninstallResponse {
238    pub target: String,
239    pub config_path: String,
240    pub uninstallation_status: InstallationStatus,
241    /// List of actions taken during uninstallation
242    pub actions_taken: Vec<String>,
243    /// List of files removed during uninstallation
244    pub files_removed: Vec<String>,
245}
246
247/// Response for status command
248#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct StatusResponse {
250    pub binary_path: String,
251    pub binary_found: bool,
252    pub environments: Vec<EnvironmentStatus>,
253}
254
255/// Installation/uninstallation status
256#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
257#[serde(rename_all = "lowercase")]
258pub enum InstallationStatus {
259    /// Installation/uninstallation completed successfully
260    Success,
261    /// Installation/uninstallation partially completed with warnings
262    Partial,
263    /// Installation/uninstallation failed
264    Failed,
265}
266
267/// Status information for a specific environment
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct EnvironmentStatus {
270    pub name: String,
271    pub installed: bool,
272    pub config_path: String,
273    pub config_exists: bool,
274    pub binary_path: String,
275    pub binary_accessible: bool,
276    #[serde(skip_serializing_if = "Option::is_none")]
277    pub config_content: Option<String>,
278    /// List of issues found (only included if there are issues)
279    #[serde(default)]
280    #[serde(skip_serializing_if = "Vec::is_empty")]
281    pub issues: Vec<String>,
282}