ricecoder_modes/
vibe_mode.rs

1//! Vibe Mode implementation for free-form exploration and rapid prototyping
2
3use async_trait::async_trait;
4use std::time::Instant;
5
6use crate::error::Result;
7use crate::mode::Mode;
8use crate::models::{
9    Capability, ModeAction, ModeConfig, ModeConstraints, ModeContext, ModeResponse, Operation,
10};
11
12/// Vibe Mode for free-form exploration and rapid prototyping
13///
14/// Vibe Mode provides capabilities for:
15/// - Natural language code generation without formal specs
16/// - Rapid iteration and exploration
17/// - Spec conversion for transitioning to spec-driven development
18/// - Warnings about limitations and best practices
19#[derive(Debug, Clone)]
20pub struct VibeMode {
21    config: ModeConfig,
22}
23
24impl VibeMode {
25    /// Create a new Vibe Mode instance
26    pub fn new() -> Self {
27        Self {
28            config: ModeConfig {
29                temperature: 0.9,
30                max_tokens: 4096,
31                system_prompt: "You are a creative coding partner. Help explore ideas, \
32                    prototype quickly, and iterate on concepts. Bypass formal specifications \
33                    and focus on rapid development."
34                    .to_string(),
35                capabilities: vec![
36                    Capability::CodeGeneration,
37                    Capability::CodeModification,
38                    Capability::FileOperations,
39                    Capability::FreeformChat,
40                    Capability::QuestionAnswering,
41                    Capability::SpecConversion,
42                ],
43                constraints: ModeConstraints {
44                    allow_file_operations: true,
45                    allow_command_execution: false,
46                    allow_code_generation: true,
47                    require_specs: false,
48                    auto_think_more_threshold: None,
49                },
50            },
51        }
52    }
53
54    /// Create a Vibe Mode with custom configuration
55    pub fn with_config(config: ModeConfig) -> Self {
56        Self { config }
57    }
58
59    /// Generate code from natural language without formal specs
60    ///
61    /// This method generates code directly from natural language descriptions
62    /// without requiring formal specifications.
63    pub fn generate_code_from_description(&self, description: &str) -> Result<String> {
64        // Validate that code generation is allowed
65        if !self.config.constraints.allow_code_generation {
66            return Err(crate::error::ModeError::OperationNotAllowed {
67                mode: self.id().to_string(),
68                operation: Operation::GenerateCode.to_string(),
69            });
70        }
71
72        // For now, return a placeholder response
73        // In a real implementation, this would call an LLM
74        Ok(format!(
75            "// Generated from description:\n// {}\n\n// TODO: Implement based on description",
76            description
77        ))
78    }
79
80    /// Support rapid iteration by accepting natural language input
81    ///
82    /// This method enables quick prototyping by accepting natural language
83    /// input and generating code without formal review cycles.
84    pub fn iterate_rapidly(&self, iteration_input: &str) -> Result<String> {
85        // Validate that code generation is allowed
86        if !self.config.constraints.allow_code_generation {
87            return Err(crate::error::ModeError::OperationNotAllowed {
88                mode: self.id().to_string(),
89                operation: Operation::GenerateCode.to_string(),
90            });
91        }
92
93        Ok(format!(
94            "// Rapid iteration:\n// {}\n\n// Generated code for quick prototyping",
95            iteration_input
96        ))
97    }
98
99    /// Generate code with multiple iterations
100    ///
101    /// This method supports generating code through multiple rapid iterations,
102    /// allowing developers to refine and improve the generated code.
103    pub fn generate_with_iterations(&self, description: &str, iterations: usize) -> Result<String> {
104        // Validate that code generation is allowed
105        if !self.config.constraints.allow_code_generation {
106            return Err(crate::error::ModeError::OperationNotAllowed {
107                mode: self.id().to_string(),
108                operation: Operation::GenerateCode.to_string(),
109            });
110        }
111
112        let mut code = format!(
113            "// Generated from description:\n// {}\n\n// Iteration 1:\n// TODO: Implement",
114            description
115        );
116
117        for i in 2..=iterations {
118            code.push_str(&format!("\n\n// Iteration {}:\n// TODO: Refine", i));
119        }
120
121        Ok(code)
122    }
123
124    /// Accept natural language input and generate code
125    ///
126    /// This method is the core of Vibe Mode - it accepts natural language
127    /// input without requiring formal specifications and generates code.
128    pub fn accept_natural_language(&self, input: &str) -> Result<String> {
129        // Validate that code generation is allowed
130        if !self.config.constraints.allow_code_generation {
131            return Err(crate::error::ModeError::OperationNotAllowed {
132                mode: self.id().to_string(),
133                operation: Operation::GenerateCode.to_string(),
134            });
135        }
136
137        // Validate that specs are not required
138        if self.config.constraints.require_specs {
139            return Err(crate::error::ModeError::ProcessingFailed(
140                "Specs are required in this mode".to_string(),
141            ));
142        }
143
144        Ok(format!(
145            "// Natural language input:\n// {}\n\n// Generated code without formal specs",
146            input
147        ))
148    }
149
150    /// Convert a Vibe Mode project to spec-driven format
151    ///
152    /// This method converts existing code and context from Vibe Mode
153    /// to a formal spec-driven development format.
154    pub fn convert_to_specs(&self, project_code: &str) -> Result<String> {
155        let spec_template = format!(
156            "# Generated Specification\n\n\
157            ## Overview\n\
158            This specification was auto-generated from Vibe Mode code.\n\n\
159            ## Code\n\
160            ```\n\
161            {}\n\
162            ```\n\n\
163            ## Next Steps\n\
164            1. Review and refine the specification\n\
165            2. Add acceptance criteria\n\
166            3. Define design decisions\n\
167            4. Create implementation tasks",
168            project_code
169        );
170        Ok(spec_template)
171    }
172
173    /// Preserve all code and context during conversion
174    ///
175    /// This method ensures that all code and context is preserved
176    /// when converting from Vibe Mode to spec-driven format.
177    pub fn preserve_code_and_context(&self, code: &str, context: &ModeContext) -> Result<String> {
178        let mut preserved = String::new();
179        preserved.push_str("# Preserved Context\n\n");
180        preserved.push_str(&format!("Session ID: {}\n", context.session_id));
181
182        if let Some(path) = &context.project_path {
183            preserved.push_str(&format!("Project Path: {}\n", path.display()));
184        }
185
186        preserved.push_str(&format!(
187            "Conversation History: {} messages\n",
188            context.conversation_history.len()
189        ));
190
191        preserved.push_str("\n# Preserved Code\n\n");
192        preserved.push_str("```\n");
193        preserved.push_str(code);
194        preserved.push_str("\n```\n");
195
196        Ok(preserved)
197    }
198
199    /// Generate initial specs from code
200    ///
201    /// This method analyzes code and generates initial specifications
202    /// that can be refined and expanded.
203    pub fn generate_specs_from_code(&self, code: &str) -> Result<String> {
204        let mut spec = String::new();
205        spec.push_str("# Auto-Generated Specification from Code\n\n");
206
207        // Analyze code for functions
208        if code.contains("fn ") {
209            spec.push_str("## Functions\n");
210            spec.push_str("The following functions were detected in the code:\n\n");
211            // Simple detection - in real implementation would parse AST
212            for line in code.lines() {
213                if line.contains("fn ") {
214                    spec.push_str(&format!("- {}\n", line.trim()));
215                }
216            }
217            spec.push('\n');
218        }
219
220        // Analyze code for structs
221        if code.contains("struct ") {
222            spec.push_str("## Data Structures\n");
223            spec.push_str("The following structures were detected in the code:\n\n");
224            for line in code.lines() {
225                if line.contains("struct ") {
226                    spec.push_str(&format!("- {}\n", line.trim()));
227                }
228            }
229            spec.push('\n');
230        }
231
232        spec.push_str("## Requirements\n");
233        spec.push_str("Based on the code analysis, the following requirements are inferred:\n\n");
234        spec.push_str("1. The system should implement the detected functions\n");
235        spec.push_str("2. The system should use the detected data structures\n");
236        spec.push_str("3. The system should follow the patterns in the code\n\n");
237
238        spec.push_str("## Next Steps\n");
239        spec.push_str("1. Review the inferred requirements\n");
240        spec.push_str("2. Add acceptance criteria for each requirement\n");
241        spec.push_str("3. Define design decisions\n");
242        spec.push_str("4. Create implementation tasks\n");
243
244        Ok(spec)
245    }
246
247    /// Support converting Vibe Mode projects to spec-driven format
248    ///
249    /// This method provides a complete conversion workflow from Vibe Mode
250    /// to spec-driven development.
251    pub fn convert_project_to_specs(&self, code: &str, context: &ModeContext) -> Result<String> {
252        let mut conversion = String::new();
253        conversion.push_str("# Vibe Mode to Spec-Driven Conversion\n\n");
254
255        // Preserve context
256        conversion.push_str("## Preserved Context\n");
257        let preserved = self.preserve_code_and_context(code, context)?;
258        conversion.push_str(&preserved);
259        conversion.push_str("\n\n");
260
261        // Generate specs from code
262        conversion.push_str("## Generated Specification\n");
263        let specs = self.generate_specs_from_code(code)?;
264        conversion.push_str(&specs);
265
266        Ok(conversion)
267    }
268
269    /// Generate warnings about Vibe Mode limitations
270    ///
271    /// This method creates warnings about the limitations of Vibe Mode
272    /// and best practices for using it.
273    pub fn generate_warnings(&self) -> Vec<String> {
274        vec![
275            "⚠️  Vibe Mode bypasses formal specifications. \
276            Consider converting to spec-driven development for production code."
277                .to_string(),
278            "⚠️  Code generated in Vibe Mode may lack comprehensive testing. \
279            Add tests before deploying to production."
280                .to_string(),
281            "⚠️  Vibe Mode does not enforce code quality standards. \
282            Review code quality manually or switch to Code Mode."
283                .to_string(),
284            "⚠️  Rapid iteration may lead to technical debt. \
285            Plan for refactoring and cleanup."
286                .to_string(),
287            "💡 Best Practice: Use Vibe Mode for exploration and prototyping, \
288            then convert to spec-driven development for production."
289                .to_string(),
290        ]
291    }
292
293    /// Generate warnings about specific limitations
294    ///
295    /// This method generates warnings about specific limitations
296    /// based on the context of use.
297    pub fn generate_specific_warnings(&self, context: &str) -> Vec<String> {
298        let mut warnings = self.generate_warnings();
299
300        if context.contains("production") {
301            warnings.push(
302                "⚠️  WARNING: Vibe Mode is not recommended for production code. \
303                Use Code Mode with formal specifications instead."
304                    .to_string(),
305            );
306        }
307
308        if context.contains("test") {
309            warnings.push(
310                "⚠️  Code generated in Vibe Mode requires comprehensive testing. \
311                Add unit tests, integration tests, and property-based tests."
312                    .to_string(),
313            );
314        }
315
316        if context.contains("quality") {
317            warnings.push(
318                "⚠️  Code quality validation is not performed in Vibe Mode. \
319                Switch to Code Mode for quality validation."
320                    .to_string(),
321            );
322        }
323
324        warnings
325    }
326
327    /// Display warnings in a formatted way
328    ///
329    /// This method formats warnings for display to the user.
330    pub fn format_warnings(&self, warnings: &[String]) -> String {
331        let mut formatted = String::new();
332        formatted.push_str("=== Vibe Mode Warnings ===\n\n");
333
334        for warning in warnings {
335            formatted.push_str(&format!("{}\n", warning));
336        }
337
338        formatted.push_str("\n=== End Warnings ===\n");
339        formatted
340    }
341
342    /// Include warnings in all responses
343    ///
344    /// This method adds warnings to a response to inform users
345    /// about Vibe Mode limitations.
346    pub fn add_warnings_to_response(&self, response: &mut ModeResponse) {
347        let warnings = self.generate_warnings();
348        for warning in warnings {
349            response.add_suggestion(warning);
350        }
351    }
352
353    /// Include specific warnings based on context
354    ///
355    /// This method adds context-specific warnings to a response.
356    pub fn add_specific_warnings_to_response(&self, response: &mut ModeResponse, context: &str) {
357        let warnings = self.generate_specific_warnings(context);
358        for warning in warnings {
359            response.add_suggestion(warning);
360        }
361    }
362
363    /// Validate that an operation is allowed in Vibe Mode
364    ///
365    /// This method checks if an operation can be executed in Vibe Mode.
366    pub fn validate_operation(&self, operation: &Operation) -> Result<()> {
367        match operation {
368            Operation::GenerateCode | Operation::ModifyFile | Operation::AnswerQuestion => Ok(()),
369            Operation::ExecuteCommand => Err(crate::error::ModeError::OperationNotAllowed {
370                mode: self.id().to_string(),
371                operation: operation.to_string(),
372            }),
373            Operation::RunTests => Err(crate::error::ModeError::OperationNotAllowed {
374                mode: self.id().to_string(),
375                operation: operation.to_string(),
376            }),
377            Operation::ValidateQuality => Err(crate::error::ModeError::OperationNotAllowed {
378                mode: self.id().to_string(),
379                operation: operation.to_string(),
380            }),
381        }
382    }
383
384    /// Provide guidance on best practices
385    ///
386    /// This method generates guidance on how to best use Vibe Mode.
387    pub fn provide_best_practices(&self) -> Vec<String> {
388        vec![
389            "Start with Vibe Mode for rapid prototyping and exploration".to_string(),
390            "Use natural language descriptions to generate code quickly".to_string(),
391            "Iterate rapidly without formal review cycles".to_string(),
392            "Convert to spec-driven development when ready for production".to_string(),
393            "Add comprehensive tests before deploying code".to_string(),
394            "Review code quality and refactor as needed".to_string(),
395        ]
396    }
397}
398
399impl Default for VibeMode {
400    fn default() -> Self {
401        Self::new()
402    }
403}
404
405#[async_trait]
406impl Mode for VibeMode {
407    fn id(&self) -> &str {
408        "vibe"
409    }
410
411    fn name(&self) -> &str {
412        "Vibe Mode"
413    }
414
415    fn description(&self) -> &str {
416        "Free-form exploration and rapid prototyping without formal specifications"
417    }
418
419    fn system_prompt(&self) -> &str {
420        &self.config.system_prompt
421    }
422
423    async fn process(&self, input: &str, context: &ModeContext) -> Result<ModeResponse> {
424        let start = Instant::now();
425
426        // Create response with input as content
427        let mut response = ModeResponse::new(input.to_string(), self.id().to_string());
428
429        // Add code generation action for natural language input
430        if input.contains("generate") || input.contains("create") || input.contains("build") {
431            response.add_action(ModeAction::GenerateCode {
432                spec: input.to_string(),
433            });
434        }
435
436        // Add file operation action if input mentions files
437        if input.contains("file") || input.contains("modify") {
438            response.add_action(ModeAction::ModifyFile {
439                path: std::path::PathBuf::from("generated.rs"),
440                diff: "// Generated code".to_string(),
441            });
442        }
443
444        // Add spec conversion suggestion if input mentions specs
445        if input.contains("spec") || input.contains("formal") {
446            response.add_action(ModeAction::SuggestMode {
447                mode: "code".to_string(),
448                reason: "Consider Code Mode for spec-driven development".to_string(),
449            });
450        }
451
452        // Add warnings to all responses
453        self.add_warnings_to_response(&mut response);
454
455        // Update metadata
456        response.metadata.duration = start.elapsed();
457        response.metadata.think_more_used = context.think_more_enabled;
458
459        Ok(response)
460    }
461
462    fn capabilities(&self) -> Vec<Capability> {
463        self.config.capabilities.clone()
464    }
465
466    fn config(&self) -> &ModeConfig {
467        &self.config
468    }
469
470    fn can_execute(&self, operation: &Operation) -> bool {
471        matches!(
472            operation,
473            Operation::GenerateCode | Operation::ModifyFile | Operation::AnswerQuestion
474        )
475    }
476
477    fn constraints(&self) -> ModeConstraints {
478        self.config.constraints.clone()
479    }
480}
481
482#[cfg(test)]
483mod tests {
484    use super::*;
485
486    #[test]
487    fn test_vibe_mode_creation() {
488        let mode = VibeMode::new();
489        assert_eq!(mode.id(), "vibe");
490        assert_eq!(mode.name(), "Vibe Mode");
491    }
492
493    #[test]
494    fn test_vibe_mode_capabilities() {
495        let mode = VibeMode::new();
496        let capabilities = mode.capabilities();
497        assert!(capabilities.contains(&Capability::CodeGeneration));
498        assert!(capabilities.contains(&Capability::CodeModification));
499        assert!(capabilities.contains(&Capability::FileOperations));
500        assert!(capabilities.contains(&Capability::FreeformChat));
501        assert!(capabilities.contains(&Capability::QuestionAnswering));
502        assert!(capabilities.contains(&Capability::SpecConversion));
503    }
504
505    #[test]
506    fn test_vibe_mode_can_execute() {
507        let mode = VibeMode::new();
508        assert!(mode.can_execute(&Operation::GenerateCode));
509        assert!(mode.can_execute(&Operation::ModifyFile));
510        assert!(mode.can_execute(&Operation::AnswerQuestion));
511        assert!(!mode.can_execute(&Operation::ExecuteCommand));
512        assert!(!mode.can_execute(&Operation::RunTests));
513        assert!(!mode.can_execute(&Operation::ValidateQuality));
514    }
515
516    #[test]
517    fn test_vibe_mode_constraints() {
518        let mode = VibeMode::new();
519        let constraints = mode.constraints();
520        assert!(constraints.allow_file_operations);
521        assert!(!constraints.allow_command_execution);
522        assert!(constraints.allow_code_generation);
523        assert!(!constraints.require_specs);
524        assert_eq!(constraints.auto_think_more_threshold, None);
525    }
526
527    #[test]
528    fn test_vibe_mode_system_prompt() {
529        let mode = VibeMode::new();
530        let prompt = mode.system_prompt();
531        assert!(prompt.contains("creative coding partner"));
532        assert!(prompt.contains("rapid"));
533        assert!(prompt.contains("Bypass formal specifications"));
534    }
535
536    #[tokio::test]
537    async fn test_vibe_mode_process() {
538        let mode = VibeMode::new();
539        let context = ModeContext::new("test-session".to_string());
540        let response = mode.process("create a function", &context).await.unwrap();
541        assert_eq!(response.content, "create a function");
542        assert_eq!(response.metadata.mode, "vibe");
543        assert!(!response.metadata.think_more_used);
544        assert!(!response.actions.is_empty());
545    }
546
547    #[tokio::test]
548    async fn test_vibe_mode_process_with_think_more() {
549        let mode = VibeMode::new();
550        let mut context = ModeContext::new("test-session".to_string());
551        context.think_more_enabled = true;
552        let response = mode.process("create a function", &context).await.unwrap();
553        assert!(response.metadata.think_more_used);
554    }
555
556    #[tokio::test]
557    async fn test_vibe_mode_process_includes_warnings() {
558        let mode = VibeMode::new();
559        let context = ModeContext::new("test-session".to_string());
560        let response = mode.process("test input", &context).await.unwrap();
561        assert!(!response.suggestions.is_empty());
562        // Check that at least one suggestion contains a warning
563        assert!(response
564            .suggestions
565            .iter()
566            .any(|s| s.contains("⚠️") || s.contains("💡")));
567    }
568
569    #[test]
570    fn test_vibe_mode_default() {
571        let mode = VibeMode::default();
572        assert_eq!(mode.id(), "vibe");
573    }
574
575    #[test]
576    fn test_vibe_mode_with_custom_config() {
577        let custom_config = ModeConfig {
578            temperature: 0.8,
579            max_tokens: 2048,
580            system_prompt: "Custom prompt".to_string(),
581            capabilities: vec![Capability::CodeGeneration],
582            constraints: ModeConstraints {
583                allow_file_operations: true,
584                allow_command_execution: false,
585                allow_code_generation: true,
586                require_specs: false,
587                auto_think_more_threshold: None,
588            },
589        };
590        let mode = VibeMode::with_config(custom_config);
591        assert_eq!(mode.config().temperature, 0.8);
592        assert_eq!(mode.config().max_tokens, 2048);
593    }
594
595    #[test]
596    fn test_generate_code_from_description() {
597        let mode = VibeMode::new();
598        let description = "Create a function that adds two numbers";
599        let result = mode.generate_code_from_description(description);
600        assert!(result.is_ok());
601        let code = result.unwrap();
602        assert!(code.contains("Generated from description"));
603        assert!(code.contains(description));
604    }
605
606    #[test]
607    fn test_iterate_rapidly() {
608        let mode = VibeMode::new();
609        let iteration = "Add error handling";
610        let result = mode.iterate_rapidly(iteration);
611        assert!(result.is_ok());
612        let code = result.unwrap();
613        assert!(code.contains("Rapid iteration"));
614        assert!(code.contains(iteration));
615    }
616
617    #[test]
618    fn test_convert_to_specs() {
619        let mode = VibeMode::new();
620        let code = "fn main() { println!(\"Hello\"); }";
621        let result = mode.convert_to_specs(code);
622        assert!(result.is_ok());
623        let spec = result.unwrap();
624        assert!(spec.contains("Generated Specification"));
625        assert!(spec.contains("auto-generated from Vibe Mode"));
626        assert!(spec.contains(code));
627    }
628
629    #[test]
630    fn test_generate_warnings() {
631        let mode = VibeMode::new();
632        let warnings = mode.generate_warnings();
633        assert!(!warnings.is_empty());
634        assert!(warnings.iter().any(|w| w.contains("⚠️")));
635        assert!(warnings.iter().any(|w| w.contains("specification")));
636        assert!(warnings.iter().any(|w| w.contains("testing")));
637    }
638
639    #[tokio::test]
640    async fn test_add_warnings_to_response() {
641        let mode = VibeMode::new();
642        let mut response = ModeResponse::new("test".to_string(), "vibe".to_string());
643        let initial_suggestions = response.suggestions.len();
644        mode.add_warnings_to_response(&mut response);
645        assert!(response.suggestions.len() > initial_suggestions);
646    }
647
648    #[test]
649    fn test_validate_operation_allowed() {
650        let mode = VibeMode::new();
651        assert!(mode.validate_operation(&Operation::GenerateCode).is_ok());
652        assert!(mode.validate_operation(&Operation::ModifyFile).is_ok());
653        assert!(mode.validate_operation(&Operation::AnswerQuestion).is_ok());
654    }
655
656    #[test]
657    fn test_validate_operation_blocked_execute_command() {
658        let mode = VibeMode::new();
659        let result = mode.validate_operation(&Operation::ExecuteCommand);
660        assert!(result.is_err());
661    }
662
663    #[test]
664    fn test_validate_operation_blocked_run_tests() {
665        let mode = VibeMode::new();
666        let result = mode.validate_operation(&Operation::RunTests);
667        assert!(result.is_err());
668    }
669
670    #[test]
671    fn test_validate_operation_blocked_validate_quality() {
672        let mode = VibeMode::new();
673        let result = mode.validate_operation(&Operation::ValidateQuality);
674        assert!(result.is_err());
675    }
676
677    #[test]
678    fn test_provide_best_practices() {
679        let mode = VibeMode::new();
680        let practices = mode.provide_best_practices();
681        assert!(!practices.is_empty());
682        assert!(practices.iter().any(|p| p.contains("prototyping")));
683        assert!(practices.iter().any(|p| p.contains("spec-driven")));
684        assert!(practices.iter().any(|p| p.contains("tests")));
685    }
686
687    #[tokio::test]
688    async fn test_process_with_generate_keyword() {
689        let mode = VibeMode::new();
690        let context = ModeContext::new("test-session".to_string());
691        let response = mode.process("generate a function", &context).await.unwrap();
692        assert!(!response.actions.is_empty());
693    }
694
695    #[tokio::test]
696    async fn test_process_with_file_keyword() {
697        let mode = VibeMode::new();
698        let context = ModeContext::new("test-session".to_string());
699        let response = mode.process("modify file", &context).await.unwrap();
700        assert!(!response.actions.is_empty());
701    }
702
703    #[tokio::test]
704    async fn test_process_with_spec_keyword() {
705        let mode = VibeMode::new();
706        let context = ModeContext::new("test-session".to_string());
707        let response = mode.process("convert to spec", &context).await.unwrap();
708        assert!(!response.actions.is_empty());
709    }
710
711    #[test]
712    fn test_generate_with_iterations() {
713        let mode = VibeMode::new();
714        let description = "Create a function";
715        let result = mode.generate_with_iterations(description, 3);
716        assert!(result.is_ok());
717        let code = result.unwrap();
718        assert!(code.contains("Iteration 1"));
719        assert!(code.contains("Iteration 2"));
720        assert!(code.contains("Iteration 3"));
721    }
722
723    #[test]
724    fn test_accept_natural_language() {
725        let mode = VibeMode::new();
726        let input = "Create a function that adds two numbers";
727        let result = mode.accept_natural_language(input);
728        assert!(result.is_ok());
729        let code = result.unwrap();
730        assert!(code.contains("Natural language input"));
731        assert!(code.contains("without formal specs"));
732        assert!(code.contains(input));
733    }
734
735    #[test]
736    fn test_accept_natural_language_blocked_when_specs_required() {
737        let custom_config = ModeConfig {
738            temperature: 0.9,
739            max_tokens: 4096,
740            system_prompt: "Test".to_string(),
741            capabilities: vec![Capability::CodeGeneration],
742            constraints: ModeConstraints {
743                allow_file_operations: true,
744                allow_command_execution: false,
745                allow_code_generation: true,
746                require_specs: true,
747                auto_think_more_threshold: None,
748            },
749        };
750        let mode = VibeMode::with_config(custom_config);
751        let result = mode.accept_natural_language("test input");
752        assert!(result.is_err());
753    }
754
755    #[test]
756    fn test_generate_code_from_description_blocked_when_disabled() {
757        let custom_config = ModeConfig {
758            temperature: 0.9,
759            max_tokens: 4096,
760            system_prompt: "Test".to_string(),
761            capabilities: vec![],
762            constraints: ModeConstraints {
763                allow_file_operations: true,
764                allow_command_execution: false,
765                allow_code_generation: false,
766                require_specs: false,
767                auto_think_more_threshold: None,
768            },
769        };
770        let mode = VibeMode::with_config(custom_config);
771        let result = mode.generate_code_from_description("test");
772        assert!(result.is_err());
773    }
774
775    #[test]
776    fn test_iterate_rapidly_blocked_when_disabled() {
777        let custom_config = ModeConfig {
778            temperature: 0.9,
779            max_tokens: 4096,
780            system_prompt: "Test".to_string(),
781            capabilities: vec![],
782            constraints: ModeConstraints {
783                allow_file_operations: true,
784                allow_command_execution: false,
785                allow_code_generation: false,
786                require_specs: false,
787                auto_think_more_threshold: None,
788            },
789        };
790        let mode = VibeMode::with_config(custom_config);
791        let result = mode.iterate_rapidly("test");
792        assert!(result.is_err());
793    }
794
795    #[test]
796    fn test_generate_with_iterations_blocked_when_disabled() {
797        let custom_config = ModeConfig {
798            temperature: 0.9,
799            max_tokens: 4096,
800            system_prompt: "Test".to_string(),
801            capabilities: vec![],
802            constraints: ModeConstraints {
803                allow_file_operations: true,
804                allow_command_execution: false,
805                allow_code_generation: false,
806                require_specs: false,
807                auto_think_more_threshold: None,
808            },
809        };
810        let mode = VibeMode::with_config(custom_config);
811        let result = mode.generate_with_iterations("test", 3);
812        assert!(result.is_err());
813    }
814
815    #[test]
816    fn test_preserve_code_and_context() {
817        let mode = VibeMode::new();
818        let code = "fn main() {}";
819        let context = ModeContext::new("test-session".to_string());
820        let result = mode.preserve_code_and_context(code, &context);
821        assert!(result.is_ok());
822        let preserved = result.unwrap();
823        assert!(preserved.contains("Preserved Context"));
824        assert!(preserved.contains("test-session"));
825        assert!(preserved.contains("Preserved Code"));
826        assert!(preserved.contains(code));
827    }
828
829    #[test]
830    fn test_preserve_code_and_context_with_project_path() {
831        let mode = VibeMode::new();
832        let code = "fn main() {}";
833        let mut context = ModeContext::new("test-session".to_string());
834        context.project_path = Some(std::path::PathBuf::from("/path/to/project"));
835        let result = mode.preserve_code_and_context(code, &context);
836        assert!(result.is_ok());
837        let preserved = result.unwrap();
838        assert!(preserved.contains("/path/to/project"));
839    }
840
841    #[test]
842    fn test_generate_specs_from_code() {
843        let mode = VibeMode::new();
844        let code = "fn add(a: i32, b: i32) -> i32 { a + b }\nstruct Point { x: i32, y: i32 }";
845        let result = mode.generate_specs_from_code(code);
846        assert!(result.is_ok());
847        let spec = result.unwrap();
848        assert!(spec.contains("Auto-Generated Specification"));
849        assert!(spec.contains("Functions"));
850        assert!(spec.contains("Data Structures"));
851        assert!(spec.contains("Requirements"));
852    }
853
854    #[test]
855    fn test_generate_specs_from_code_with_functions() {
856        let mode = VibeMode::new();
857        let code = "fn add(a: i32, b: i32) -> i32 { a + b }";
858        let result = mode.generate_specs_from_code(code);
859        assert!(result.is_ok());
860        let spec = result.unwrap();
861        assert!(spec.contains("Functions"));
862        assert!(spec.contains("fn add"));
863    }
864
865    #[test]
866    fn test_generate_specs_from_code_with_structs() {
867        let mode = VibeMode::new();
868        let code = "struct Point { x: i32, y: i32 }";
869        let result = mode.generate_specs_from_code(code);
870        assert!(result.is_ok());
871        let spec = result.unwrap();
872        assert!(spec.contains("Data Structures"));
873        assert!(spec.contains("struct Point"));
874    }
875
876    #[test]
877    fn test_convert_project_to_specs() {
878        let mode = VibeMode::new();
879        let code = "fn main() {}";
880        let context = ModeContext::new("test-session".to_string());
881        let result = mode.convert_project_to_specs(code, &context);
882        assert!(result.is_ok());
883        let conversion = result.unwrap();
884        assert!(conversion.contains("Vibe Mode to Spec-Driven Conversion"));
885        assert!(conversion.contains("Preserved Context"));
886        assert!(conversion.contains("Generated Specification"));
887    }
888
889    #[test]
890    fn test_convert_project_to_specs_preserves_all_data() {
891        let mode = VibeMode::new();
892        let code = "fn add(a: i32, b: i32) -> i32 { a + b }";
893        let mut context = ModeContext::new("test-session".to_string());
894        context.project_path = Some(std::path::PathBuf::from("/project"));
895        let result = mode.convert_project_to_specs(code, &context);
896        assert!(result.is_ok());
897        let conversion = result.unwrap();
898        assert!(conversion.contains("test-session"));
899        assert!(conversion.contains("/project"));
900        assert!(conversion.contains(code));
901    }
902
903    #[test]
904    fn test_generate_specific_warnings_production() {
905        let mode = VibeMode::new();
906        let warnings = mode.generate_specific_warnings("production");
907        assert!(!warnings.is_empty());
908        assert!(warnings.iter().any(|w| w.contains("production")));
909    }
910
911    #[test]
912    fn test_generate_specific_warnings_test() {
913        let mode = VibeMode::new();
914        let warnings = mode.generate_specific_warnings("test");
915        assert!(!warnings.is_empty());
916        assert!(warnings.iter().any(|w| w.contains("testing")));
917    }
918
919    #[test]
920    fn test_generate_specific_warnings_quality() {
921        let mode = VibeMode::new();
922        let warnings = mode.generate_specific_warnings("quality");
923        assert!(!warnings.is_empty());
924        assert!(warnings.iter().any(|w| w.contains("quality")));
925    }
926
927    #[test]
928    fn test_format_warnings() {
929        let mode = VibeMode::new();
930        let warnings = vec!["Warning 1".to_string(), "Warning 2".to_string()];
931        let formatted = mode.format_warnings(&warnings);
932        assert!(formatted.contains("Vibe Mode Warnings"));
933        assert!(formatted.contains("Warning 1"));
934        assert!(formatted.contains("Warning 2"));
935    }
936
937    #[tokio::test]
938    async fn test_add_specific_warnings_to_response() {
939        let mode = VibeMode::new();
940        let mut response = ModeResponse::new("test".to_string(), "vibe".to_string());
941        let initial_suggestions = response.suggestions.len();
942        mode.add_specific_warnings_to_response(&mut response, "production");
943        assert!(response.suggestions.len() > initial_suggestions);
944        assert!(response
945            .suggestions
946            .iter()
947            .any(|s| s.contains("production")));
948    }
949
950    #[test]
951    fn test_warnings_include_best_practices() {
952        let mode = VibeMode::new();
953        let warnings = mode.generate_warnings();
954        assert!(warnings.iter().any(|w| w.contains("💡")));
955        assert!(warnings.iter().any(|w| w.contains("Best Practice")));
956    }
957
958    #[test]
959    fn test_warnings_include_limitations() {
960        let mode = VibeMode::new();
961        let warnings = mode.generate_warnings();
962        assert!(warnings.iter().any(|w| w.contains("⚠️")));
963        assert!(warnings.iter().any(|w| w.contains("specifications")));
964        assert!(warnings.iter().any(|w| w.contains("testing")));
965    }
966}