Coverage for src/interactive_context.py: 97%

33 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-06-05 22:56 -0700

1""" 

2Interactive context management for Chuck command handlers. 

3 

4This module provides a centralized system for tracking and managing 

5interactive command contexts, allowing commands to prompt for and 

6process user input across multiple steps. 

7""" 

8 

9from typing import Dict, Any, Optional 

10 

11 

12class InteractiveContext: 

13 """ 

14 Global manager for interactive context states. 

15 Helps coordinate between command handlers and the TUI. 

16 """ 

17 

18 _instance = None 

19 

20 def __new__(cls): 

21 if cls._instance is None: 

22 cls._instance = super(InteractiveContext, cls).__new__(cls) 

23 cls._instance._active_contexts = {} 

24 cls._instance._current_command = None 

25 return cls._instance 

26 

27 @property 

28 def current_command(self) -> Optional[str]: 

29 """Get the currently active command, if any.""" 

30 return self._current_command 

31 

32 def set_active_context(self, command: str) -> None: 

33 """ 

34 Set a command as active in interactive mode. 

35 

36 Args: 

37 command: The command name (e.g., "setup_wizard" or "/setup_wizard") 

38 Slash prefix will be removed internally for consistency. 

39 """ 

40 # Normalize command name by removing slash prefix if present 

41 normalized_cmd = command.lstrip("/") 

42 

43 # Store original command for UI reference but normalize for internal storage 

44 self._current_command = command 

45 if normalized_cmd not in self._active_contexts: 

46 self._active_contexts[normalized_cmd] = {} 

47 

48 def clear_active_context(self, command: str) -> None: 

49 """ 

50 Clear the interactive context for a command. 

51 

52 Args: 

53 command: The command name (e.g., "setup_wizard" or "/setup_wizard") 

54 Slash prefix will be removed internally for consistency. 

55 """ 

56 # Normalize command name by removing slash prefix if present 

57 normalized_cmd = command.lstrip("/") 

58 

59 # Compare normalized versions of commands to avoid mismatches 

60 if ( 

61 self._current_command 

62 and self._current_command.lstrip("/") == normalized_cmd 

63 ): 

64 self._current_command = None 

65 

66 if normalized_cmd in self._active_contexts: 

67 del self._active_contexts[normalized_cmd] 

68 

69 def is_in_interactive_mode(self) -> bool: 

70 """Check if any command is in interactive mode.""" 

71 return self._current_command is not None 

72 

73 def get_context_data(self, command: str) -> Dict[str, Any]: 

74 """ 

75 Get stored context data for a command. 

76 

77 Args: 

78 command: The command name (e.g., "setup_wizard" or "/setup_wizard") 

79 Slash prefix will be removed internally for consistency. 

80 

81 Returns: 

82 Dictionary of context data for the command 

83 """ 

84 # Normalize command name by removing slash prefix if present 

85 normalized_cmd = command.lstrip("/") 

86 

87 return self._active_contexts.get(normalized_cmd, {}) 

88 

89 def store_context_data(self, command: str, key: str, value: Any) -> None: 

90 """ 

91 Store data in the context for a command. 

92 

93 Args: 

94 command: The command name (e.g., "setup_wizard" or "/setup_wizard") 

95 Slash prefix will be removed internally for consistency. 

96 key: The key to store the data under 

97 value: The value to store 

98 """ 

99 # Normalize command name by removing slash prefix if present 

100 normalized_cmd = command.lstrip("/") 

101 

102 if normalized_cmd not in self._active_contexts: 

103 self._active_contexts[normalized_cmd] = {} 

104 

105 self._active_contexts[normalized_cmd][key] = value