claude-mpm 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (159) hide show
  1. claude_mpm/__init__.py +17 -0
  2. claude_mpm/__main__.py +14 -0
  3. claude_mpm/_version.py +32 -0
  4. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +88 -0
  5. claude_mpm/agents/INSTRUCTIONS.md +375 -0
  6. claude_mpm/agents/__init__.py +118 -0
  7. claude_mpm/agents/agent_loader.py +621 -0
  8. claude_mpm/agents/agent_loader_integration.py +229 -0
  9. claude_mpm/agents/agents_metadata.py +204 -0
  10. claude_mpm/agents/base_agent.json +27 -0
  11. claude_mpm/agents/base_agent_loader.py +519 -0
  12. claude_mpm/agents/schema/agent_schema.json +160 -0
  13. claude_mpm/agents/system_agent_config.py +587 -0
  14. claude_mpm/agents/templates/__init__.py +101 -0
  15. claude_mpm/agents/templates/data_engineer_agent.json +46 -0
  16. claude_mpm/agents/templates/documentation_agent.json +45 -0
  17. claude_mpm/agents/templates/engineer_agent.json +49 -0
  18. claude_mpm/agents/templates/ops_agent.json +46 -0
  19. claude_mpm/agents/templates/qa_agent.json +45 -0
  20. claude_mpm/agents/templates/research_agent.json +49 -0
  21. claude_mpm/agents/templates/security_agent.json +46 -0
  22. claude_mpm/agents/templates/update-optimized-specialized-agents.json +374 -0
  23. claude_mpm/agents/templates/version_control_agent.json +46 -0
  24. claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +6 -0
  25. claude_mpm/cli.py +655 -0
  26. claude_mpm/cli_main.py +13 -0
  27. claude_mpm/cli_module/__init__.py +15 -0
  28. claude_mpm/cli_module/args.py +222 -0
  29. claude_mpm/cli_module/commands.py +203 -0
  30. claude_mpm/cli_module/migration_example.py +183 -0
  31. claude_mpm/cli_module/refactoring_guide.md +253 -0
  32. claude_mpm/cli_old/__init__.py +1 -0
  33. claude_mpm/cli_old/ticket_cli.py +102 -0
  34. claude_mpm/config/__init__.py +5 -0
  35. claude_mpm/config/hook_config.py +42 -0
  36. claude_mpm/constants.py +150 -0
  37. claude_mpm/core/__init__.py +45 -0
  38. claude_mpm/core/agent_name_normalizer.py +248 -0
  39. claude_mpm/core/agent_registry.py +627 -0
  40. claude_mpm/core/agent_registry.py.bak +312 -0
  41. claude_mpm/core/agent_session_manager.py +273 -0
  42. claude_mpm/core/base_service.py +747 -0
  43. claude_mpm/core/base_service.py.bak +406 -0
  44. claude_mpm/core/config.py +334 -0
  45. claude_mpm/core/config_aliases.py +292 -0
  46. claude_mpm/core/container.py +347 -0
  47. claude_mpm/core/factories.py +281 -0
  48. claude_mpm/core/framework_loader.py +472 -0
  49. claude_mpm/core/injectable_service.py +206 -0
  50. claude_mpm/core/interfaces.py +539 -0
  51. claude_mpm/core/logger.py +468 -0
  52. claude_mpm/core/minimal_framework_loader.py +107 -0
  53. claude_mpm/core/mixins.py +150 -0
  54. claude_mpm/core/service_registry.py +299 -0
  55. claude_mpm/core/session_manager.py +190 -0
  56. claude_mpm/core/simple_runner.py +511 -0
  57. claude_mpm/core/tool_access_control.py +173 -0
  58. claude_mpm/hooks/README.md +243 -0
  59. claude_mpm/hooks/__init__.py +5 -0
  60. claude_mpm/hooks/base_hook.py +154 -0
  61. claude_mpm/hooks/builtin/__init__.py +1 -0
  62. claude_mpm/hooks/builtin/logging_hook_example.py +165 -0
  63. claude_mpm/hooks/builtin/post_delegation_hook_example.py +124 -0
  64. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +125 -0
  65. claude_mpm/hooks/builtin/submit_hook_example.py +100 -0
  66. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +237 -0
  67. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +239 -0
  68. claude_mpm/hooks/builtin/workflow_start_hook.py +181 -0
  69. claude_mpm/hooks/hook_client.py +264 -0
  70. claude_mpm/hooks/hook_runner.py +370 -0
  71. claude_mpm/hooks/json_rpc_executor.py +259 -0
  72. claude_mpm/hooks/json_rpc_hook_client.py +319 -0
  73. claude_mpm/hooks/tool_call_interceptor.py +204 -0
  74. claude_mpm/init.py +246 -0
  75. claude_mpm/orchestration/SUBPROCESS_DESIGN.md +66 -0
  76. claude_mpm/orchestration/__init__.py +6 -0
  77. claude_mpm/orchestration/archive/direct_orchestrator.py +195 -0
  78. claude_mpm/orchestration/archive/factory.py +215 -0
  79. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +188 -0
  80. claude_mpm/orchestration/archive/hook_integration_example.py +178 -0
  81. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +826 -0
  82. claude_mpm/orchestration/archive/orchestrator.py +501 -0
  83. claude_mpm/orchestration/archive/pexpect_orchestrator.py +252 -0
  84. claude_mpm/orchestration/archive/pty_orchestrator.py +270 -0
  85. claude_mpm/orchestration/archive/simple_orchestrator.py +82 -0
  86. claude_mpm/orchestration/archive/subprocess_orchestrator.py +801 -0
  87. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +278 -0
  88. claude_mpm/orchestration/archive/wrapper_orchestrator.py +187 -0
  89. claude_mpm/scripts/__init__.py +1 -0
  90. claude_mpm/scripts/ticket.py +269 -0
  91. claude_mpm/services/__init__.py +10 -0
  92. claude_mpm/services/agent_deployment.py +955 -0
  93. claude_mpm/services/agent_lifecycle_manager.py +948 -0
  94. claude_mpm/services/agent_management_service.py +596 -0
  95. claude_mpm/services/agent_modification_tracker.py +841 -0
  96. claude_mpm/services/agent_profile_loader.py +606 -0
  97. claude_mpm/services/agent_registry.py +677 -0
  98. claude_mpm/services/base_agent_manager.py +380 -0
  99. claude_mpm/services/framework_agent_loader.py +337 -0
  100. claude_mpm/services/framework_claude_md_generator/README.md +92 -0
  101. claude_mpm/services/framework_claude_md_generator/__init__.py +206 -0
  102. claude_mpm/services/framework_claude_md_generator/content_assembler.py +151 -0
  103. claude_mpm/services/framework_claude_md_generator/content_validator.py +126 -0
  104. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +137 -0
  105. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +106 -0
  106. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +582 -0
  107. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +97 -0
  108. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +27 -0
  109. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +23 -0
  110. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +23 -0
  111. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +20 -0
  112. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +26 -0
  113. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +30 -0
  114. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +37 -0
  115. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +111 -0
  116. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +89 -0
  117. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +39 -0
  118. claude_mpm/services/framework_claude_md_generator/section_manager.py +106 -0
  119. claude_mpm/services/framework_claude_md_generator/version_manager.py +121 -0
  120. claude_mpm/services/framework_claude_md_generator.py +621 -0
  121. claude_mpm/services/hook_service.py +388 -0
  122. claude_mpm/services/hook_service_manager.py +223 -0
  123. claude_mpm/services/json_rpc_hook_manager.py +92 -0
  124. claude_mpm/services/parent_directory_manager/README.md +83 -0
  125. claude_mpm/services/parent_directory_manager/__init__.py +577 -0
  126. claude_mpm/services/parent_directory_manager/backup_manager.py +258 -0
  127. claude_mpm/services/parent_directory_manager/config_manager.py +210 -0
  128. claude_mpm/services/parent_directory_manager/deduplication_manager.py +279 -0
  129. claude_mpm/services/parent_directory_manager/framework_protector.py +143 -0
  130. claude_mpm/services/parent_directory_manager/operations.py +186 -0
  131. claude_mpm/services/parent_directory_manager/state_manager.py +624 -0
  132. claude_mpm/services/parent_directory_manager/template_deployer.py +579 -0
  133. claude_mpm/services/parent_directory_manager/validation_manager.py +378 -0
  134. claude_mpm/services/parent_directory_manager/version_control_helper.py +339 -0
  135. claude_mpm/services/parent_directory_manager/version_manager.py +222 -0
  136. claude_mpm/services/shared_prompt_cache.py +819 -0
  137. claude_mpm/services/ticket_manager.py +213 -0
  138. claude_mpm/services/ticket_manager_di.py +318 -0
  139. claude_mpm/services/ticketing_service_original.py +508 -0
  140. claude_mpm/services/version_control/VERSION +1 -0
  141. claude_mpm/services/version_control/__init__.py +70 -0
  142. claude_mpm/services/version_control/branch_strategy.py +670 -0
  143. claude_mpm/services/version_control/conflict_resolution.py +744 -0
  144. claude_mpm/services/version_control/git_operations.py +784 -0
  145. claude_mpm/services/version_control/semantic_versioning.py +703 -0
  146. claude_mpm/ui/__init__.py +1 -0
  147. claude_mpm/ui/rich_terminal_ui.py +295 -0
  148. claude_mpm/ui/terminal_ui.py +328 -0
  149. claude_mpm/utils/__init__.py +16 -0
  150. claude_mpm/utils/config_manager.py +468 -0
  151. claude_mpm/utils/import_migration_example.py +80 -0
  152. claude_mpm/utils/imports.py +182 -0
  153. claude_mpm/utils/path_operations.py +357 -0
  154. claude_mpm/utils/paths.py +289 -0
  155. claude_mpm-0.3.0.dist-info/METADATA +290 -0
  156. claude_mpm-0.3.0.dist-info/RECORD +159 -0
  157. claude_mpm-0.3.0.dist-info/WHEEL +5 -0
  158. claude_mpm-0.3.0.dist-info/entry_points.txt +4 -0
  159. claude_mpm-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,83 @@
1
+ # Parent Directory Manager
2
+
3
+ This directory contains the modularized components of the Parent Directory Manager service.
4
+
5
+ ## Module Structure
6
+
7
+ The Parent Directory Manager has been refactored into specialized modules following the single-responsibility principle:
8
+
9
+ ### Core Module
10
+ - `__init__.py` - Main ParentDirectoryManager class that orchestrates all operations
11
+
12
+ ### Specialized Modules
13
+
14
+ 1. **backup_manager.py** - Handles backup operations
15
+ - Creates backups of files before modifications
16
+ - Manages backup retention and cleanup
17
+ - Handles framework template backup protection
18
+
19
+ 2. **template_deployer.py** - Manages template deployment
20
+ - Handles version comparison and deployment decisions
21
+ - Renders templates with variable substitution
22
+ - Integrates with framework template generator
23
+
24
+ 3. **framework_protector.py** - Framework protection mechanisms
25
+ - Protects critical framework files
26
+ - Manages protection rules and validation
27
+
28
+ 4. **version_control_helper.py** - Version control integration
29
+ - Git operations and version control checks
30
+ - Branch management support
31
+
32
+ 5. **deduplication_manager.py** - CLAUDE.md deduplication
33
+ - Detects and removes duplicate CLAUDE.md files
34
+ - Manages deduplication hierarchy and precedence
35
+
36
+ 6. **operations.py** (formerly parent_directory_operations.py) - Directory operations
37
+ - Auto-detection of parent directory contexts
38
+ - Directory registration and management
39
+
40
+ 7. **config_manager.py** - Configuration management
41
+ - Manages directory configurations
42
+ - Handles registration and configuration persistence
43
+
44
+ 8. **state_manager.py** - State and lifecycle management
45
+ - Initialization and cleanup operations
46
+ - Operation history tracking
47
+ - Logging and error handling
48
+
49
+ 9. **validation_manager.py** - Validation operations
50
+ - Template validation
51
+ - Compatibility checking
52
+ - Directory status validation
53
+
54
+ 10. **version_manager.py** - Version tracking
55
+ - Subsystem version management
56
+ - Version compatibility validation
57
+ - Version reporting
58
+
59
+ ## Usage
60
+
61
+ The main entry point remains the `ParentDirectoryManager` class, which delegates to these specialized modules:
62
+
63
+ ```python
64
+ from claude_pm.services.parent_directory_manager import ParentDirectoryManager
65
+
66
+ # Initialize the manager
67
+ manager = ParentDirectoryManager()
68
+
69
+ # All public APIs remain the same
70
+ await manager.deploy_framework_template(target_dir)
71
+ ```
72
+
73
+ ## Backward Compatibility
74
+
75
+ A stub file at `claude_pm/services/parent_directory_manager.py` ensures backward compatibility for existing imports.
76
+
77
+ ## Design Principles
78
+
79
+ 1. **Single Responsibility** - Each module has a focused purpose
80
+ 2. **Delegation Pattern** - Main class delegates to specialized modules
81
+ 3. **Dependency Injection** - Modules receive dependencies via constructor
82
+ 4. **Async Support** - All operations support async/await patterns
83
+ 5. **Comprehensive Logging** - Each module uses consistent logging
@@ -0,0 +1,577 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Parent Directory Manager Service - CMPM-104: Parent Directory Template Installation
4
+ ================================================================================
5
+
6
+ This service provides comprehensive parent directory template management with
7
+ deployment awareness, building on CMPM-101, CMPM-102, and CMPM-103.
8
+
9
+ Key Features:
10
+ - Parent directory CLAUDE.md management with deployment awareness
11
+ - Template installation workflow with conflict resolution
12
+ - Existing file detection and backup system
13
+ - Version control integration
14
+ - Cross-platform compatibility
15
+ - Integration with all previous CMPM implementations
16
+
17
+ Dependencies:
18
+ - CMPM-101 (Deployment Detection System)
19
+ - CMPM-102 (Versioned Template Management)
20
+ - CMPM-103 (Dependency Management)
21
+ """
22
+
23
+ import os
24
+ from pathlib import Path
25
+ from typing import Dict, List, Optional, Any, Tuple
26
+
27
+ from ...core.base_service import BaseService
28
+ from ...core.logger import setup_logging
29
+
30
+ # Import extracted modules for delegation
31
+ from .backup_manager import BackupManager
32
+ from .template_deployer import TemplateDeployer, DeploymentContext
33
+ from .framework_protector import FrameworkProtector
34
+ from .version_control_helper import VersionControlHelper
35
+ from .deduplication_manager import DeduplicationManager
36
+ from .operations import ParentDirectoryOperations, ParentDirectoryContext
37
+ from .config_manager import ConfigManager, ParentDirectoryConfig
38
+ from .state_manager import StateManager, ParentDirectoryStatus, ParentDirectoryOperation, ParentDirectoryAction
39
+ from .validation_manager import ValidationManager
40
+ from .version_manager import VersionManager
41
+
42
+
43
+ class ParentDirectoryManager(BaseService):
44
+ """
45
+ Parent Directory Template Management Service for Claude PM Framework.
46
+
47
+ This service provides:
48
+ - Parent directory CLAUDE.md management with deployment awareness
49
+ - Template installation workflow with conflict resolution
50
+ - Existing file detection and backup system
51
+ - Version control integration
52
+ - Integration with CMPM-101, CMPM-102, and CMPM-103
53
+
54
+ This is now a facade that delegates to specialized modules for:
55
+ - Backup management
56
+ - Template deployment
57
+ - Framework protection
58
+ - Version control
59
+ - Deduplication
60
+ - Directory operations
61
+ - Configuration management
62
+ - State management
63
+ - Validation
64
+ - Version tracking
65
+ """
66
+
67
+ def __init__(self, config: Optional[Dict[str, Any]] = None, quiet_mode: bool = False):
68
+ """
69
+ Initialize the Parent Directory Manager.
70
+
71
+ Args:
72
+ config: Optional configuration dictionary
73
+ quiet_mode: If True, suppress INFO level logging
74
+ """
75
+ super().__init__(name="parent_directory_manager", config=config)
76
+
77
+ # Setup logger based on quiet mode
78
+ level = "WARNING" if quiet_mode or os.getenv('CLAUDE_PM_QUIET_MODE') == 'true' else "INFO"
79
+ self.logger = setup_logging(__name__, level=level)
80
+
81
+ self._quiet_mode = quiet_mode # Store quiet mode setting
82
+
83
+ # Configuration
84
+ self.backup_retention_days = self.get_config("backup_retention_days", 30)
85
+ self.deployment_aware = self.get_config("deployment_aware", True)
86
+
87
+ # Working paths
88
+ self.working_dir = Path.cwd()
89
+ # Temporarily set framework_path - will be properly set after state manager init
90
+ self.framework_path = Path(__file__).resolve().parent.parent.parent.parent
91
+ self.parent_directory_manager_dir = (
92
+ self.working_dir / ".claude-pm" / "parent_directory_manager"
93
+ )
94
+
95
+
96
+ # Initialize extracted service modules for delegation
97
+ self._backup_manager = BackupManager(
98
+ base_dir=self.working_dir,
99
+ retention_days=self.backup_retention_days,
100
+ logger=self.logger
101
+ )
102
+
103
+ self._template_deployer = TemplateDeployer(
104
+ framework_path=self.framework_path,
105
+ logger=self.logger
106
+ )
107
+
108
+ self._deduplication_manager = DeduplicationManager(
109
+ logger=self.logger
110
+ )
111
+
112
+ self._directory_ops = ParentDirectoryOperations(
113
+ logger=self.logger
114
+ )
115
+
116
+ self._config_manager = ConfigManager(
117
+ configs_dir=self.parent_directory_manager_dir / "configs",
118
+ logger=self.logger
119
+ )
120
+
121
+ # Initialize version manager early
122
+ self._version_manager = VersionManager(
123
+ framework_path=self.framework_path,
124
+ logger=self.logger
125
+ )
126
+
127
+ self._state_manager = StateManager(
128
+ working_dir=self.working_dir,
129
+ parent_directory_manager_dir=self.parent_directory_manager_dir,
130
+ framework_path=self.framework_path,
131
+ quiet_mode=quiet_mode,
132
+ logger=self.logger
133
+ )
134
+
135
+ # Now properly detect framework path using state manager
136
+ self.framework_path = self._detect_framework_path()
137
+ # Update all managers' framework paths
138
+ self._state_manager.framework_path = self.framework_path
139
+ self._template_deployer.framework_path = self.framework_path
140
+ self._version_manager.framework_path = self.framework_path
141
+
142
+ # Initialize paths
143
+ paths = self._state_manager.initialize_paths(self.parent_directory_manager_dir, self.working_dir)
144
+ self.backups_dir = paths['backups_dir']
145
+ self.configs_dir = paths['configs_dir']
146
+ self.versions_dir = paths['versions_dir']
147
+ self.logs_dir = paths['logs_dir']
148
+ self.managed_directories_file = paths['managed_directories_file']
149
+ self.operation_history_file = paths['operation_history_file']
150
+
151
+ self._validation_manager = ValidationManager(
152
+ logger=self.logger
153
+ )
154
+
155
+ # Integration with other CMPM services removed - use Claude Code Task Tool instead
156
+ self.template_manager = None
157
+ self.dependency_manager = None
158
+ self.deployment_context = None # Loaded during initialization
159
+
160
+ @property
161
+ def quiet(self) -> bool:
162
+ """Get quiet mode setting."""
163
+ return self._quiet_mode
164
+
165
+ @property
166
+ def version_manager(self):
167
+ """Get version manager for direct access to version operations."""
168
+ return self._version_manager
169
+
170
+ @property
171
+ def validation_manager(self):
172
+ """Get validation manager for direct access to validation operations."""
173
+ return self._validation_manager
174
+
175
+ # Delegation methods for public API
176
+ def _log_info_if_not_quiet(self, message: str) -> None:
177
+ self._state_manager.log_info_if_not_quiet(message)
178
+
179
+ def _detect_framework_path(self) -> Path:
180
+ return self._state_manager.detect_framework_path()
181
+
182
+
183
+
184
+ # Main lifecycle methods
185
+ async def _initialize(self) -> None:
186
+ """Initialize the Parent Directory Manager service."""
187
+ # Delegate initialization to StateManager
188
+ await self._state_manager.initialize(
189
+ self._state_manager.create_directory_structure,
190
+ self._config_manager,
191
+ self._validation_manager,
192
+ self._version_manager,
193
+ self._deduplicate_claude_md_files,
194
+ self.deployment_aware,
195
+ self.dependency_manager
196
+ )
197
+
198
+ # Update local references
199
+ self.managed_directories = self._config_manager.managed_directories
200
+ self.operation_history = self._state_manager.operation_history
201
+ self.deployment_context = self._state_manager.deployment_context
202
+ self.subsystem_versions = self._version_manager.subsystem_versions
203
+
204
+ async def _cleanup(self) -> None:
205
+ """Cleanup the Parent Directory Manager service."""
206
+ # Delegate cleanup to StateManager
207
+ await self._state_manager.cleanup(
208
+ self._config_manager,
209
+ self.backups_dir,
210
+ self.backup_retention_days
211
+ )
212
+
213
+ # Public API Methods - all delegating to specialized modules
214
+
215
+ async def register_parent_directory(
216
+ self,
217
+ target_directory: Path,
218
+ context: ParentDirectoryContext,
219
+ template_id: str,
220
+ template_variables: Dict[str, Any] = None,
221
+ **kwargs,
222
+ ) -> bool:
223
+ """
224
+ Register a parent directory for management.
225
+
226
+ Args:
227
+ target_directory: Directory to manage
228
+ context: Context type for the directory
229
+ template_id: Template to use for management
230
+ template_variables: Variables for template rendering
231
+ **kwargs: Additional configuration options
232
+
233
+ Returns:
234
+ True if registration successful, False otherwise
235
+ """
236
+ result = await self._config_manager.register_parent_directory(
237
+ target_directory, context, template_id, template_variables, **kwargs
238
+ )
239
+ if result:
240
+ self.managed_directories = self._config_manager.managed_directories
241
+ return result
242
+
243
+ async def deploy_framework_template(
244
+ self,
245
+ target_directory: Path,
246
+ force: bool = False,
247
+ ) -> ParentDirectoryOperation:
248
+ """
249
+ Deploy framework template using the new generator with integrated deployment.
250
+
251
+ Args:
252
+ target_directory: Directory to deploy template to
253
+ force: Force deployment even if version is current
254
+
255
+ Returns:
256
+ ParentDirectoryOperation result
257
+ """
258
+ # Delegate to TemplateDeployer
259
+ success, target_path, error_message, changes_made = await self._template_deployer.deploy_framework_template(
260
+ target_directory=target_directory,
261
+ force=force,
262
+ deduplication_handler=self._deduplicate_claude_md_files,
263
+ backup_manager=self._backup_manager,
264
+ state_manager=self._state_manager,
265
+ quiet=self.quiet
266
+ )
267
+
268
+ # Handle protection guidance if error
269
+ if not success and "Permanent protection" in error_message:
270
+ self._state_manager.handle_protection_error(target_path, error_message, simple=True)
271
+
272
+ # Create operation result
273
+ operation = self._state_manager.create_operation_result(
274
+ action=ParentDirectoryAction.INSTALL,
275
+ target_path=target_path,
276
+ success=success,
277
+ template_id="framework_claude_md",
278
+ backup_manager=self._backup_manager,
279
+ changes_made=changes_made if success else [],
280
+ error_message=error_message if not success else None
281
+ )
282
+
283
+ if success:
284
+ self._state_manager.add_operation(operation)
285
+
286
+ return operation
287
+
288
+ async def install_template_to_parent_directory(
289
+ self,
290
+ target_directory: Path,
291
+ template_id: str,
292
+ template_variables: Dict[str, Any] = None,
293
+ force: bool = False,
294
+ ) -> ParentDirectoryOperation:
295
+ """
296
+ Install a template to a parent directory with version checking.
297
+
298
+ Args:
299
+ target_directory: Directory to install template to
300
+ template_id: Template to install
301
+ template_variables: Variables for template rendering
302
+ force: Force installation even if version is current (overrides version checking)
303
+
304
+ Returns:
305
+ ParentDirectoryOperation result
306
+ """
307
+ # Handle streaming logging setup
308
+ self.logger, original_logger, deployment_streaming = self._state_manager.setup_deployment_logger(self.logger)
309
+
310
+ try:
311
+ target_file = target_directory / "CLAUDE.md"
312
+ self._current_target_file = target_file
313
+
314
+ # Delegate to TemplateDeployer
315
+ success, target_path, version, error_message, changes_made = await self._template_deployer.install_template(
316
+ target_directory=target_directory,
317
+ template_id=template_id,
318
+ template_variables=template_variables,
319
+ force=force,
320
+ deduplication_handler=self._deduplicate_claude_md_files,
321
+ backup_manager=self._backup_manager,
322
+ state_manager=self._state_manager,
323
+ quiet=self.quiet,
324
+ current_target_file=target_file
325
+ )
326
+
327
+ # Handle protection guidance if error
328
+ if not success and "Permanent protection" in error_message:
329
+ self._state_manager.handle_protection_error(target_path, error_message)
330
+
331
+ # Handle warnings for skipped deployments
332
+ warnings = []
333
+ if success and "Deployment skipped" in str(changes_made):
334
+ warnings = changes_made
335
+ changes_made = []
336
+
337
+ # Create and return operation result
338
+ operation = self._state_manager.create_operation_result(
339
+ action=ParentDirectoryAction.INSTALL,
340
+ target_path=target_path,
341
+ success=success,
342
+ template_id=template_id,
343
+ version=version,
344
+ backup_manager=self._backup_manager,
345
+ changes_made=changes_made if success else [],
346
+ warnings=warnings,
347
+ error_message=error_message if not success else None
348
+ )
349
+
350
+ if success:
351
+ self._state_manager.add_operation(operation)
352
+
353
+ if hasattr(self, '_current_target_file'):
354
+ del self._current_target_file
355
+
356
+ self.logger = self._state_manager.finalize_deployment_logger(self.logger, original_logger, deployment_streaming)
357
+ return operation
358
+
359
+ except Exception as e:
360
+ self.logger.error(f"Failed to install template {template_id} to {target_directory}: {e}")
361
+
362
+ # Clean up temporary attribute
363
+ if hasattr(self, '_current_target_file'):
364
+ del self._current_target_file
365
+
366
+ # Finalize streaming logs if we used streaming logger
367
+ self.logger = self._state_manager.finalize_deployment_logger(self.logger, original_logger, deployment_streaming)
368
+
369
+ return self._state_manager.create_operation_result(
370
+ action=ParentDirectoryAction.INSTALL,
371
+ target_path=target_directory / "CLAUDE.md",
372
+ success=False,
373
+ template_id=template_id,
374
+ error_message=str(e)
375
+ )
376
+
377
+ async def update_parent_directory_template(
378
+ self, target_directory: Path, template_variables: Dict[str, Any] = None, force: bool = False
379
+ ) -> ParentDirectoryOperation:
380
+ """
381
+ Update a template in a parent directory.
382
+
383
+ Args:
384
+ target_directory: Directory containing template to update
385
+ template_variables: New variables for template rendering
386
+ force: Force update even if no changes detected
387
+
388
+ Returns:
389
+ ParentDirectoryOperation result
390
+ """
391
+ try:
392
+ # Check if directory is managed
393
+ directory_key = str(target_directory)
394
+ if not self._config_manager.is_directory_managed(directory_key):
395
+ raise ValueError(f"Directory not managed: {target_directory}")
396
+
397
+ config = self._config_manager.get_directory_config(directory_key)
398
+
399
+ # Get current status
400
+ status = await self.get_parent_directory_status(target_directory)
401
+
402
+ if not status.exists:
403
+ # File doesn't exist, perform installation
404
+ return await self.install_template_to_parent_directory(
405
+ target_directory, config.template_id, template_variables, force
406
+ )
407
+
408
+ # Update template variables if provided
409
+ if template_variables:
410
+ config.template_variables.update(template_variables)
411
+
412
+ # For updates, delegate to install with force flag to ensure update happens
413
+ result = await self.install_template_to_parent_directory(
414
+ target_directory, config.template_id, config.template_variables, force=True
415
+ )
416
+
417
+ # Change the action to UPDATE in the result
418
+ result.action = ParentDirectoryAction.UPDATE
419
+
420
+ return result
421
+
422
+ except Exception as e:
423
+ self.logger.error(f"Failed to update template in {target_directory}: {e}")
424
+ return self._state_manager.create_operation_result(
425
+ action=ParentDirectoryAction.UPDATE,
426
+ target_path=target_directory / "CLAUDE.md",
427
+ success=False,
428
+ error_message=str(e)
429
+ )
430
+
431
+ async def get_parent_directory_status(self, target_directory: Path) -> ParentDirectoryStatus:
432
+ """Get status of a parent directory."""
433
+ return await self._state_manager.get_parent_directory_status(
434
+ target_directory, self._config_manager, self.backups_dir
435
+ )
436
+
437
+ async def backup_parent_directory(self, target_directory: Path) -> Optional[Path]:
438
+ """
439
+ Create a backup of a parent directory's CLAUDE.md file.
440
+
441
+ Args:
442
+ target_directory: Directory containing file to backup
443
+
444
+ Returns:
445
+ Path to backup file or None if failed
446
+ """
447
+ return await self._backup_manager.backup_parent_directory(target_directory, self.backups_dir)
448
+
449
+ async def restore_parent_directory(
450
+ self, target_directory: Path, backup_timestamp: Optional[str] = None
451
+ ) -> ParentDirectoryOperation:
452
+ """
453
+ Restore a parent directory from backup.
454
+
455
+ Args:
456
+ target_directory: Directory to restore
457
+ backup_timestamp: Specific backup to restore (latest if None)
458
+
459
+ Returns:
460
+ ParentDirectoryOperation result
461
+ """
462
+ # Delegate to BackupManager
463
+ operation = await self._backup_manager.restore_from_backup(
464
+ target_directory,
465
+ self.backups_dir,
466
+ backup_timestamp
467
+ )
468
+
469
+ # Store operation in history if successful
470
+ if operation.success:
471
+ self._state_manager.add_operation(operation)
472
+
473
+ return operation
474
+
475
+ async def validate_parent_directory(self, target_directory: Path) -> ParentDirectoryOperation:
476
+ """Validate a parent directory's template."""
477
+ return await self._validation_manager.validate_parent_directory(
478
+ target_directory, self.managed_directories
479
+ )
480
+
481
+ async def list_managed_directories(self) -> List[Dict[str, Any]]:
482
+ """List all managed directories."""
483
+ return await self._state_manager.list_managed_directories(
484
+ self._config_manager, self.get_parent_directory_status
485
+ )
486
+
487
+ async def get_operation_history(self, limit: int = 50) -> List[Dict[str, Any]]:
488
+ """Get operation history."""
489
+ return await self._state_manager.get_operation_history(limit)
490
+
491
+ # Subsystem Version Management Methods - delegating to version manager
492
+ # Subsystem Version Management - direct delegation to version manager
493
+ def get_subsystem_versions(self) -> Dict[str, Any]:
494
+ return self._version_manager.get_subsystem_versions()
495
+
496
+ def get_subsystem_version(self, subsystem: str) -> Optional[str]:
497
+ return self._version_manager.get_subsystem_version(subsystem)
498
+
499
+ async def validate_subsystem_compatibility(self, required_versions: Dict[str, str]) -> Dict[str, Any]:
500
+ return await self._validation_manager.validate_subsystem_compatibility(
501
+ required_versions, self._version_manager.get_subsystem_version
502
+ )
503
+
504
+ async def update_subsystem_version(self, subsystem: str, new_version: str) -> bool:
505
+ return await self._version_manager.update_subsystem_version(
506
+ subsystem, new_version,
507
+ lambda file_path: self._backup_manager.create_backup(file_path, self.backups_dir)
508
+ )
509
+
510
+ def get_subsystem_version_report(self) -> Dict[str, Any]:
511
+ return self._version_manager.get_subsystem_version_report()
512
+
513
+ # Directory operations - delegating to directory operations module
514
+ async def detect_parent_directory_context(self, target_directory: Path) -> ParentDirectoryContext:
515
+ return await self._directory_ops.detect_parent_directory_context(target_directory)
516
+
517
+ async def auto_register_parent_directories(
518
+ self, search_paths: List[Path], template_id: str = "parent_directory_claude_md"
519
+ ) -> List[Path]:
520
+ """Automatically register parent directories that should be managed."""
521
+ return await self._directory_ops.auto_register_parent_directories(
522
+ search_paths,
523
+ template_id,
524
+ self.register_parent_directory,
525
+ lambda path, ctx: self._directory_ops.get_default_template_variables(
526
+ path, ctx, self.deployment_context
527
+ )
528
+ )
529
+
530
+ # Deduplication - delegating to deduplication manager
531
+ async def _deduplicate_claude_md_files(self) -> List[Tuple[Path, str]]:
532
+ """Deduplicate CLAUDE.md files in parent directory hierarchy."""
533
+ return await self._deduplication_manager.deduplicate_claude_md_files(
534
+ self._template_deployer.is_framework_deployment_template,
535
+ self._template_deployer.extract_claude_md_version,
536
+ self._template_deployer.compare_versions,
537
+ lambda file_path: self._backup_manager.create_backup(file_path, self.backups_dir)
538
+ )
539
+
540
+ async def deduplicate_parent_claude_md(self) -> Dict[str, Any]:
541
+ """Public method to manually trigger CLAUDE.md deduplication in parent hierarchy."""
542
+ return await self._deduplication_manager.deduplicate_parent_claude_md(
543
+ self._template_deployer.is_framework_deployment_template,
544
+ self._template_deployer.extract_claude_md_version,
545
+ self._template_deployer.compare_versions,
546
+ lambda file_path: self._backup_manager.create_backup(file_path, self.backups_dir)
547
+ )
548
+
549
+ # Helper Methods
550
+
551
+
552
+ async def _get_framework_template(
553
+ self, template_id: str
554
+ ) -> Tuple[Optional[str], Optional[Any]]:
555
+ """Get template from deployment framework path using the new generator."""
556
+ current_target_file = getattr(self, '_current_target_file', None)
557
+ return await self._template_deployer.get_framework_template(
558
+ template_id,
559
+ current_target_file,
560
+ self._backup_manager,
561
+ self._log_info_if_not_quiet
562
+ )
563
+
564
+ def get_framework_backup_status(self) -> Dict[str, Any]:
565
+ return self._backup_manager.get_framework_backup_status()
566
+
567
+
568
+ # Export all public symbols
569
+ __all__ = [
570
+ 'ParentDirectoryManager',
571
+ 'ParentDirectoryContext',
572
+ 'ParentDirectoryStatus',
573
+ 'ParentDirectoryOperation',
574
+ 'ParentDirectoryAction',
575
+ 'ParentDirectoryConfig',
576
+ 'DeploymentContext'
577
+ ]