Skip to main content

foundry_mcp/types/
spec.rs

1//! Spec-related type definitions
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6use crate::core::backends::ResourceLocator;
7
8/// Spec content data structure
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct SpecContentData {
11    pub spec: String,
12    pub notes: String,
13    pub tasks: String,
14}
15
16/// Core specification structure
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct Spec {
19    pub name: String,
20    pub created_at: String,
21    pub path: PathBuf, // Keep for backward compatibility (deprecated)
22    pub project_name: String,
23
24    // New optional fields for backend abstraction
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub location_hint: Option<String>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub locator: Option<ResourceLocator>,
29
30    // Existing fields
31    pub content: SpecContentData,
32}
33
34/// Spec creation parameters
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct SpecConfig {
37    pub project_name: String,
38    pub feature_name: String,
39    pub content: SpecContentData,
40}
41
42/// Spec metadata for listing operations
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct SpecMetadata {
45    pub name: String,
46    pub created_at: String,
47    pub feature_name: String,
48    pub project_name: String,
49}
50
51/// Spec filtering criteria for advanced queries
52#[derive(Debug, Clone, Default, Serialize, Deserialize)]
53pub struct SpecFilter {
54    pub feature_name_contains: Option<String>,
55    pub created_after: Option<String>,
56    pub created_before: Option<String>,
57    pub limit: Option<usize>,
58}
59
60/// Spec file types for content updates
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(rename_all = "lowercase")]
63pub enum SpecFileType {
64    Spec,
65    Notes,
66    TaskList,
67}
68
69/// Content validation status
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct ContentValidationStatus {
72    pub spec_valid: bool,
73    pub notes_valid: bool,
74    pub task_list_valid: bool,
75}
76
77/// Spec validation result
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct SpecValidationResult {
80    pub spec_name: String,
81    pub project_name: String,
82    pub spec_file_exists: bool,
83    pub notes_file_exists: bool,
84    pub task_list_file_exists: bool,
85    pub content_validation: ContentValidationStatus,
86    pub validation_errors: Vec<String>,
87}
88
89impl SpecValidationResult {
90    /// Check if the spec is completely valid
91    pub fn is_valid(&self) -> bool {
92        self.spec_file_exists
93            && self.notes_file_exists
94            && self.task_list_file_exists
95            && self.content_validation.spec_valid
96            && self.content_validation.notes_valid
97            && self.content_validation.task_list_valid
98            && self.validation_errors.is_empty()
99    }
100
101    /// Get summary of validation issues
102    pub fn summary(&self) -> String {
103        if self.is_valid() {
104            "Spec is valid".to_string()
105        } else {
106            format!(
107                "Spec validation failed: {} errors",
108                self.validation_errors.len()
109            )
110        }
111    }
112}