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.
- claude_mpm/__init__.py +17 -0
- claude_mpm/__main__.py +14 -0
- claude_mpm/_version.py +32 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +88 -0
- claude_mpm/agents/INSTRUCTIONS.md +375 -0
- claude_mpm/agents/__init__.py +118 -0
- claude_mpm/agents/agent_loader.py +621 -0
- claude_mpm/agents/agent_loader_integration.py +229 -0
- claude_mpm/agents/agents_metadata.py +204 -0
- claude_mpm/agents/base_agent.json +27 -0
- claude_mpm/agents/base_agent_loader.py +519 -0
- claude_mpm/agents/schema/agent_schema.json +160 -0
- claude_mpm/agents/system_agent_config.py +587 -0
- claude_mpm/agents/templates/__init__.py +101 -0
- claude_mpm/agents/templates/data_engineer_agent.json +46 -0
- claude_mpm/agents/templates/documentation_agent.json +45 -0
- claude_mpm/agents/templates/engineer_agent.json +49 -0
- claude_mpm/agents/templates/ops_agent.json +46 -0
- claude_mpm/agents/templates/qa_agent.json +45 -0
- claude_mpm/agents/templates/research_agent.json +49 -0
- claude_mpm/agents/templates/security_agent.json +46 -0
- claude_mpm/agents/templates/update-optimized-specialized-agents.json +374 -0
- claude_mpm/agents/templates/version_control_agent.json +46 -0
- claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +6 -0
- claude_mpm/cli.py +655 -0
- claude_mpm/cli_main.py +13 -0
- claude_mpm/cli_module/__init__.py +15 -0
- claude_mpm/cli_module/args.py +222 -0
- claude_mpm/cli_module/commands.py +203 -0
- claude_mpm/cli_module/migration_example.py +183 -0
- claude_mpm/cli_module/refactoring_guide.md +253 -0
- claude_mpm/cli_old/__init__.py +1 -0
- claude_mpm/cli_old/ticket_cli.py +102 -0
- claude_mpm/config/__init__.py +5 -0
- claude_mpm/config/hook_config.py +42 -0
- claude_mpm/constants.py +150 -0
- claude_mpm/core/__init__.py +45 -0
- claude_mpm/core/agent_name_normalizer.py +248 -0
- claude_mpm/core/agent_registry.py +627 -0
- claude_mpm/core/agent_registry.py.bak +312 -0
- claude_mpm/core/agent_session_manager.py +273 -0
- claude_mpm/core/base_service.py +747 -0
- claude_mpm/core/base_service.py.bak +406 -0
- claude_mpm/core/config.py +334 -0
- claude_mpm/core/config_aliases.py +292 -0
- claude_mpm/core/container.py +347 -0
- claude_mpm/core/factories.py +281 -0
- claude_mpm/core/framework_loader.py +472 -0
- claude_mpm/core/injectable_service.py +206 -0
- claude_mpm/core/interfaces.py +539 -0
- claude_mpm/core/logger.py +468 -0
- claude_mpm/core/minimal_framework_loader.py +107 -0
- claude_mpm/core/mixins.py +150 -0
- claude_mpm/core/service_registry.py +299 -0
- claude_mpm/core/session_manager.py +190 -0
- claude_mpm/core/simple_runner.py +511 -0
- claude_mpm/core/tool_access_control.py +173 -0
- claude_mpm/hooks/README.md +243 -0
- claude_mpm/hooks/__init__.py +5 -0
- claude_mpm/hooks/base_hook.py +154 -0
- claude_mpm/hooks/builtin/__init__.py +1 -0
- claude_mpm/hooks/builtin/logging_hook_example.py +165 -0
- claude_mpm/hooks/builtin/post_delegation_hook_example.py +124 -0
- claude_mpm/hooks/builtin/pre_delegation_hook_example.py +125 -0
- claude_mpm/hooks/builtin/submit_hook_example.py +100 -0
- claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +237 -0
- claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +239 -0
- claude_mpm/hooks/builtin/workflow_start_hook.py +181 -0
- claude_mpm/hooks/hook_client.py +264 -0
- claude_mpm/hooks/hook_runner.py +370 -0
- claude_mpm/hooks/json_rpc_executor.py +259 -0
- claude_mpm/hooks/json_rpc_hook_client.py +319 -0
- claude_mpm/hooks/tool_call_interceptor.py +204 -0
- claude_mpm/init.py +246 -0
- claude_mpm/orchestration/SUBPROCESS_DESIGN.md +66 -0
- claude_mpm/orchestration/__init__.py +6 -0
- claude_mpm/orchestration/archive/direct_orchestrator.py +195 -0
- claude_mpm/orchestration/archive/factory.py +215 -0
- claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +188 -0
- claude_mpm/orchestration/archive/hook_integration_example.py +178 -0
- claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +826 -0
- claude_mpm/orchestration/archive/orchestrator.py +501 -0
- claude_mpm/orchestration/archive/pexpect_orchestrator.py +252 -0
- claude_mpm/orchestration/archive/pty_orchestrator.py +270 -0
- claude_mpm/orchestration/archive/simple_orchestrator.py +82 -0
- claude_mpm/orchestration/archive/subprocess_orchestrator.py +801 -0
- claude_mpm/orchestration/archive/system_prompt_orchestrator.py +278 -0
- claude_mpm/orchestration/archive/wrapper_orchestrator.py +187 -0
- claude_mpm/scripts/__init__.py +1 -0
- claude_mpm/scripts/ticket.py +269 -0
- claude_mpm/services/__init__.py +10 -0
- claude_mpm/services/agent_deployment.py +955 -0
- claude_mpm/services/agent_lifecycle_manager.py +948 -0
- claude_mpm/services/agent_management_service.py +596 -0
- claude_mpm/services/agent_modification_tracker.py +841 -0
- claude_mpm/services/agent_profile_loader.py +606 -0
- claude_mpm/services/agent_registry.py +677 -0
- claude_mpm/services/base_agent_manager.py +380 -0
- claude_mpm/services/framework_agent_loader.py +337 -0
- claude_mpm/services/framework_claude_md_generator/README.md +92 -0
- claude_mpm/services/framework_claude_md_generator/__init__.py +206 -0
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +151 -0
- claude_mpm/services/framework_claude_md_generator/content_validator.py +126 -0
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +137 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +106 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +582 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +97 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +27 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +23 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +23 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +20 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +26 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +30 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +37 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +111 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +89 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +39 -0
- claude_mpm/services/framework_claude_md_generator/section_manager.py +106 -0
- claude_mpm/services/framework_claude_md_generator/version_manager.py +121 -0
- claude_mpm/services/framework_claude_md_generator.py +621 -0
- claude_mpm/services/hook_service.py +388 -0
- claude_mpm/services/hook_service_manager.py +223 -0
- claude_mpm/services/json_rpc_hook_manager.py +92 -0
- claude_mpm/services/parent_directory_manager/README.md +83 -0
- claude_mpm/services/parent_directory_manager/__init__.py +577 -0
- claude_mpm/services/parent_directory_manager/backup_manager.py +258 -0
- claude_mpm/services/parent_directory_manager/config_manager.py +210 -0
- claude_mpm/services/parent_directory_manager/deduplication_manager.py +279 -0
- claude_mpm/services/parent_directory_manager/framework_protector.py +143 -0
- claude_mpm/services/parent_directory_manager/operations.py +186 -0
- claude_mpm/services/parent_directory_manager/state_manager.py +624 -0
- claude_mpm/services/parent_directory_manager/template_deployer.py +579 -0
- claude_mpm/services/parent_directory_manager/validation_manager.py +378 -0
- claude_mpm/services/parent_directory_manager/version_control_helper.py +339 -0
- claude_mpm/services/parent_directory_manager/version_manager.py +222 -0
- claude_mpm/services/shared_prompt_cache.py +819 -0
- claude_mpm/services/ticket_manager.py +213 -0
- claude_mpm/services/ticket_manager_di.py +318 -0
- claude_mpm/services/ticketing_service_original.py +508 -0
- claude_mpm/services/version_control/VERSION +1 -0
- claude_mpm/services/version_control/__init__.py +70 -0
- claude_mpm/services/version_control/branch_strategy.py +670 -0
- claude_mpm/services/version_control/conflict_resolution.py +744 -0
- claude_mpm/services/version_control/git_operations.py +784 -0
- claude_mpm/services/version_control/semantic_versioning.py +703 -0
- claude_mpm/ui/__init__.py +1 -0
- claude_mpm/ui/rich_terminal_ui.py +295 -0
- claude_mpm/ui/terminal_ui.py +328 -0
- claude_mpm/utils/__init__.py +16 -0
- claude_mpm/utils/config_manager.py +468 -0
- claude_mpm/utils/import_migration_example.py +80 -0
- claude_mpm/utils/imports.py +182 -0
- claude_mpm/utils/path_operations.py +357 -0
- claude_mpm/utils/paths.py +289 -0
- claude_mpm-0.3.0.dist-info/METADATA +290 -0
- claude_mpm-0.3.0.dist-info/RECORD +159 -0
- claude_mpm-0.3.0.dist-info/WHEEL +5 -0
- claude_mpm-0.3.0.dist-info/entry_points.txt +4 -0
- claude_mpm-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Framework Agent Loader Service
|
|
3
|
+
|
|
4
|
+
Implements agent profile loading logic based on directory hierarchy:
|
|
5
|
+
1. Framework .claude-pm (next to agents/INSTRUCTIONS.md or CLAUDE.md): system, trained, user agents
|
|
6
|
+
2. Project .claude-pm (in project root): project agents
|
|
7
|
+
|
|
8
|
+
Loading precedence: Project → Framework (user → trained → system)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import json
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, Optional, Any
|
|
15
|
+
import logging
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
class FrameworkAgentLoader:
|
|
20
|
+
"""Loads agent profiles from framework and project .claude-pm directories"""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
self.framework_agents_dir = None
|
|
24
|
+
self.project_agents_dir = None
|
|
25
|
+
self._profile_cache = {}
|
|
26
|
+
|
|
27
|
+
def initialize(self, framework_claude_md_path: Optional[str] = None):
|
|
28
|
+
"""
|
|
29
|
+
Initialize loader with framework and project directory detection
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
framework_claude_md_path: Optional explicit path to agents/INSTRUCTIONS.md or CLAUDE.md
|
|
33
|
+
"""
|
|
34
|
+
# Find framework .claude-pm directory (next to framework/CLAUDE.md)
|
|
35
|
+
if framework_claude_md_path:
|
|
36
|
+
framework_dir = Path(framework_claude_md_path).parent.parent
|
|
37
|
+
else:
|
|
38
|
+
framework_dir = self._find_framework_directory()
|
|
39
|
+
|
|
40
|
+
if framework_dir:
|
|
41
|
+
self.framework_agents_dir = framework_dir / ".claude-pm" / "agents"
|
|
42
|
+
logger.info(f"Framework agents directory: {self.framework_agents_dir}")
|
|
43
|
+
|
|
44
|
+
# Find project .claude-pm directory
|
|
45
|
+
project_dir = self._find_project_directory()
|
|
46
|
+
if project_dir:
|
|
47
|
+
self.project_agents_dir = project_dir / ".claude-pm" / "agents"
|
|
48
|
+
logger.info(f"Project agents directory: {self.project_agents_dir}")
|
|
49
|
+
|
|
50
|
+
def _find_framework_directory(self) -> Optional[Path]:
|
|
51
|
+
"""Find directory containing agents/INSTRUCTIONS.md (or legacy CLAUDE.md)"""
|
|
52
|
+
# Check if we're running from a wheel installation
|
|
53
|
+
try:
|
|
54
|
+
import claude_pm
|
|
55
|
+
package_path = Path(claude_pm.__file__).parent
|
|
56
|
+
path_str = str(package_path.resolve())
|
|
57
|
+
if 'site-packages' in path_str or 'dist-packages' in path_str:
|
|
58
|
+
# For wheel installations, check data directory
|
|
59
|
+
data_instructions = package_path / "data" / "agents" / "INSTRUCTIONS.md"
|
|
60
|
+
data_claude = package_path / "data" / "agents" / "CLAUDE.md"
|
|
61
|
+
if data_instructions.exists() or data_claude.exists():
|
|
62
|
+
return package_path / "data"
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
current = Path.cwd()
|
|
67
|
+
|
|
68
|
+
# Check current directory and parents
|
|
69
|
+
for path in [current] + list(current.parents):
|
|
70
|
+
framework_instructions = path / "agents" / "INSTRUCTIONS.md"
|
|
71
|
+
framework_claude = path / "agents" / "CLAUDE.md" # Legacy
|
|
72
|
+
if framework_instructions.exists() or framework_claude.exists():
|
|
73
|
+
return path
|
|
74
|
+
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
def _find_project_directory(self) -> Optional[Path]:
|
|
78
|
+
"""Find project directory containing .claude-pm"""
|
|
79
|
+
current = Path.cwd()
|
|
80
|
+
|
|
81
|
+
# Check current directory and parents for .claude-pm
|
|
82
|
+
for path in [current] + list(current.parents):
|
|
83
|
+
claude_pm_dir = path / ".claude-pm"
|
|
84
|
+
if claude_pm_dir.exists():
|
|
85
|
+
return path
|
|
86
|
+
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
def load_agent_profile(self, agent_type: str) -> Optional[Dict[str, Any]]:
|
|
90
|
+
"""
|
|
91
|
+
Load agent profile with precedence: Project → Framework (user → trained → system)
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
agent_type: Agent type (Engineer, Documenter, QA, etc.)
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Agent profile dictionary or None if not found
|
|
98
|
+
"""
|
|
99
|
+
# Check cache first
|
|
100
|
+
cache_key = agent_type.lower()
|
|
101
|
+
if cache_key in self._profile_cache:
|
|
102
|
+
return self._profile_cache[cache_key]
|
|
103
|
+
|
|
104
|
+
profile = None
|
|
105
|
+
|
|
106
|
+
# 1. Try project agents first (highest precedence)
|
|
107
|
+
if self.project_agents_dir:
|
|
108
|
+
profile = self._load_profile_from_directory(
|
|
109
|
+
self.project_agents_dir / "project", agent_type
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# 2. Try framework agents (user → trained → system)
|
|
113
|
+
if not profile and self.framework_agents_dir:
|
|
114
|
+
# Framework user agents
|
|
115
|
+
profile = self._load_profile_from_directory(
|
|
116
|
+
self.framework_agents_dir / "user", agent_type
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Framework trained agents
|
|
120
|
+
if not profile:
|
|
121
|
+
profile = self._load_profile_from_directory(
|
|
122
|
+
self.framework_agents_dir / "trained", agent_type
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Framework system agents (fallback)
|
|
126
|
+
if not profile:
|
|
127
|
+
profile = self._load_profile_from_directory(
|
|
128
|
+
self.framework_agents_dir / "system", agent_type
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Cache result
|
|
132
|
+
if profile:
|
|
133
|
+
self._profile_cache[cache_key] = profile
|
|
134
|
+
|
|
135
|
+
return profile
|
|
136
|
+
|
|
137
|
+
def _load_profile_from_directory(self, directory: Path, agent_type: str) -> Optional[Dict[str, Any]]:
|
|
138
|
+
"""Load agent profile from specific directory"""
|
|
139
|
+
if not directory.exists():
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
profile_file = directory / f"{agent_type}.md"
|
|
143
|
+
if not profile_file.exists():
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
content = profile_file.read_text(encoding='utf-8')
|
|
148
|
+
return self._parse_agent_profile(content, str(profile_file))
|
|
149
|
+
except Exception as e:
|
|
150
|
+
logger.error(f"Error loading profile {profile_file}: {e}")
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
def _parse_agent_profile(self, content: str, source_path: str) -> Dict[str, Any]:
|
|
154
|
+
"""Parse agent profile markdown into structured data"""
|
|
155
|
+
profile = {
|
|
156
|
+
'source_path': source_path,
|
|
157
|
+
'raw_content': content,
|
|
158
|
+
'role': '',
|
|
159
|
+
'capabilities': [],
|
|
160
|
+
'context_preferences': {},
|
|
161
|
+
'authority_scope': [],
|
|
162
|
+
'quality_standards': [],
|
|
163
|
+
'escalation_criteria': [],
|
|
164
|
+
'integration_patterns': {}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
lines = content.split('\n')
|
|
168
|
+
current_section = None
|
|
169
|
+
current_content = []
|
|
170
|
+
|
|
171
|
+
for line in lines:
|
|
172
|
+
line = line.strip()
|
|
173
|
+
|
|
174
|
+
# Detect sections
|
|
175
|
+
if line.startswith('## Role'):
|
|
176
|
+
# Process previous section
|
|
177
|
+
if current_section and current_content:
|
|
178
|
+
self._process_section(profile, current_section, current_content)
|
|
179
|
+
current_section = 'role'
|
|
180
|
+
current_content = []
|
|
181
|
+
elif line.startswith('## Capabilities'):
|
|
182
|
+
if current_section and current_content:
|
|
183
|
+
self._process_section(profile, current_section, current_content)
|
|
184
|
+
current_section = 'capabilities'
|
|
185
|
+
current_content = []
|
|
186
|
+
elif line.startswith('## Context Preferences'):
|
|
187
|
+
if current_section and current_content:
|
|
188
|
+
self._process_section(profile, current_section, current_content)
|
|
189
|
+
current_section = 'context_preferences'
|
|
190
|
+
current_content = []
|
|
191
|
+
elif line.startswith('## Authority Scope'):
|
|
192
|
+
if current_section and current_content:
|
|
193
|
+
self._process_section(profile, current_section, current_content)
|
|
194
|
+
current_section = 'authority_scope'
|
|
195
|
+
current_content = []
|
|
196
|
+
elif line.startswith('## Quality Standards'):
|
|
197
|
+
if current_section and current_content:
|
|
198
|
+
self._process_section(profile, current_section, current_content)
|
|
199
|
+
current_section = 'quality_standards'
|
|
200
|
+
current_content = []
|
|
201
|
+
elif line.startswith('## Escalation Criteria'):
|
|
202
|
+
if current_section and current_content:
|
|
203
|
+
self._process_section(profile, current_section, current_content)
|
|
204
|
+
current_section = 'escalation_criteria'
|
|
205
|
+
current_content = []
|
|
206
|
+
elif line.startswith('## Integration Patterns'):
|
|
207
|
+
if current_section and current_content:
|
|
208
|
+
self._process_section(profile, current_section, current_content)
|
|
209
|
+
current_section = 'integration_patterns'
|
|
210
|
+
current_content = []
|
|
211
|
+
elif line.startswith('#'):
|
|
212
|
+
# Process previous section before starting new one
|
|
213
|
+
if current_section and current_content:
|
|
214
|
+
self._process_section(profile, current_section, current_content)
|
|
215
|
+
current_section = None
|
|
216
|
+
current_content = []
|
|
217
|
+
elif current_section and line:
|
|
218
|
+
current_content.append(line)
|
|
219
|
+
|
|
220
|
+
# Process final section
|
|
221
|
+
if current_section and current_content:
|
|
222
|
+
self._process_section(profile, current_section, current_content)
|
|
223
|
+
|
|
224
|
+
return profile
|
|
225
|
+
|
|
226
|
+
def _process_section(self, profile: Dict[str, Any], section: str, content: list):
|
|
227
|
+
"""Process section content into profile structure"""
|
|
228
|
+
text = '\n'.join(content).strip()
|
|
229
|
+
|
|
230
|
+
if section == 'role':
|
|
231
|
+
profile['role'] = text
|
|
232
|
+
elif section == 'capabilities':
|
|
233
|
+
# Extract bullet points
|
|
234
|
+
capabilities = []
|
|
235
|
+
for line in content:
|
|
236
|
+
if line.startswith('- **') and '**:' in line:
|
|
237
|
+
cap = line.split('**:')[0].replace('- **', '').strip()
|
|
238
|
+
capabilities.append(cap)
|
|
239
|
+
profile['capabilities'] = capabilities
|
|
240
|
+
elif section == 'context_preferences':
|
|
241
|
+
# Extract Include/Exclude/Focus
|
|
242
|
+
prefs = {}
|
|
243
|
+
for line in content:
|
|
244
|
+
if line.startswith('- **Include**:'):
|
|
245
|
+
prefs['include'] = line.replace('- **Include**:', '').strip()
|
|
246
|
+
elif line.startswith('- **Exclude**:'):
|
|
247
|
+
prefs['exclude'] = line.replace('- **Exclude**:', '').strip()
|
|
248
|
+
elif line.startswith('- **Focus**:'):
|
|
249
|
+
prefs['focus'] = line.replace('- **Focus**:', '').strip()
|
|
250
|
+
profile['context_preferences'] = prefs
|
|
251
|
+
elif section in ['authority_scope', 'quality_standards', 'escalation_criteria']:
|
|
252
|
+
# Extract bullet points
|
|
253
|
+
items = []
|
|
254
|
+
for line in content:
|
|
255
|
+
if line.startswith('- **') and '**:' in line:
|
|
256
|
+
item = line.split('**:')[0].replace('- **', '').strip()
|
|
257
|
+
items.append(item)
|
|
258
|
+
profile[section] = items
|
|
259
|
+
elif section == 'integration_patterns':
|
|
260
|
+
# Extract With X: patterns
|
|
261
|
+
patterns = {}
|
|
262
|
+
for line in content:
|
|
263
|
+
if line.startswith('- **With ') and '**:' in line:
|
|
264
|
+
agent = line.split('**:')[0].replace('- **With ', '').replace('**', '').strip()
|
|
265
|
+
desc = line.split('**:')[1].strip()
|
|
266
|
+
patterns[agent] = desc
|
|
267
|
+
profile['integration_patterns'] = patterns
|
|
268
|
+
|
|
269
|
+
def get_available_agents(self) -> Dict[str, list]:
|
|
270
|
+
"""Get list of available agents by tier"""
|
|
271
|
+
agents = {
|
|
272
|
+
'project': [],
|
|
273
|
+
'framework_user': [],
|
|
274
|
+
'framework_trained': [],
|
|
275
|
+
'framework_system': []
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
# Project agents
|
|
279
|
+
if self.project_agents_dir:
|
|
280
|
+
project_dir = self.project_agents_dir / "project"
|
|
281
|
+
if project_dir.exists():
|
|
282
|
+
agents['project'] = [f.stem for f in project_dir.glob("*.md")]
|
|
283
|
+
|
|
284
|
+
# Framework agents
|
|
285
|
+
if self.framework_agents_dir:
|
|
286
|
+
for tier in ['user', 'trained', 'system']:
|
|
287
|
+
tier_dir = self.framework_agents_dir / tier
|
|
288
|
+
if tier_dir.exists():
|
|
289
|
+
agents[f'framework_{tier}'] = [f.stem for f in tier_dir.glob("*.md")]
|
|
290
|
+
|
|
291
|
+
return agents
|
|
292
|
+
|
|
293
|
+
def generate_profile_loading_instruction(self, agent_type: str) -> str:
|
|
294
|
+
"""Generate instruction for subprocess to load its own profile"""
|
|
295
|
+
profile = self.load_agent_profile(agent_type)
|
|
296
|
+
|
|
297
|
+
if not profile:
|
|
298
|
+
return f"""
|
|
299
|
+
**{agent_type} Agent**: No profile found. Operating with basic capabilities.
|
|
300
|
+
|
|
301
|
+
**Task Context**: Please proceed with the assigned task using standard practices.
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
instruction = f"""
|
|
305
|
+
**{agent_type} Agent Profile Loaded**
|
|
306
|
+
|
|
307
|
+
**Agent Identity**: {agent_type} Agent
|
|
308
|
+
**Profile Source**: {profile.get('source_path', 'Unknown')}
|
|
309
|
+
**Primary Role**: {profile.get('role', 'Not specified')}
|
|
310
|
+
|
|
311
|
+
**Core Capabilities**:
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
for capability in profile.get('capabilities', [])[:5]: # Top 5 capabilities
|
|
315
|
+
instruction += f"- **{capability}**: Primary capability area\n"
|
|
316
|
+
|
|
317
|
+
instruction += f"""
|
|
318
|
+
**Context Preferences**:
|
|
319
|
+
- **Include**: {profile.get('context_preferences', {}).get('include', 'Not specified')}
|
|
320
|
+
- **Exclude**: {profile.get('context_preferences', {}).get('exclude', 'Not specified')}
|
|
321
|
+
- **Focus**: {profile.get('context_preferences', {}).get('focus', 'Not specified')}
|
|
322
|
+
|
|
323
|
+
**Authority Scope**:
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
for authority in profile.get('authority_scope', [])[:3]: # Top 3 authorities
|
|
327
|
+
instruction += f"- **{authority}**: Authorized operation area\n"
|
|
328
|
+
|
|
329
|
+
instruction += f"""
|
|
330
|
+
**Quality Standards**: {len(profile.get('quality_standards', []))} standards defined
|
|
331
|
+
**Escalation Triggers**: {len(profile.get('escalation_criteria', []))} criteria defined
|
|
332
|
+
**Integration Partners**: {len(profile.get('integration_patterns', {}))} agent coordination patterns
|
|
333
|
+
|
|
334
|
+
Please operate according to your profile specifications and maintain quality standards.
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
return instruction.strip()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Framework CLAUDE.md Generator
|
|
2
|
+
|
|
3
|
+
This directory contains the refactored framework CLAUDE.md generator service, originally a single 1,267-line file.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
### Core Modules
|
|
8
|
+
|
|
9
|
+
- **`__init__.py`** (~250 lines) - Main facade class that coordinates all functionality
|
|
10
|
+
- **`version_manager.py`** (~100 lines) - Handles version parsing, incrementing, and comparison
|
|
11
|
+
- **`content_assembler.py`** (~120 lines) - Assembles sections and applies template variables
|
|
12
|
+
- **`content_validator.py`** (~80 lines) - Validates generated content structure and completeness
|
|
13
|
+
- **`deployment_manager.py`** (~80 lines) - Handles deployment to parent directories
|
|
14
|
+
- **`section_manager.py`** (~60 lines) - Manages section registration, ordering, and updates
|
|
15
|
+
|
|
16
|
+
### Section Generators
|
|
17
|
+
|
|
18
|
+
The `section_generators/` subdirectory contains individual generators for each section:
|
|
19
|
+
|
|
20
|
+
- **`__init__.py`** - Base classes and registry
|
|
21
|
+
- **`header.py`** - Header with version metadata
|
|
22
|
+
- **`role_designation.py`** - AI Assistant role designation
|
|
23
|
+
- **`agents.py`** (~570 lines) - Comprehensive agents documentation (largest section)
|
|
24
|
+
- **`todo_task_tools.py`** - Todo and Task Tools integration
|
|
25
|
+
- **`claude_pm_init.py`** - Claude-PM initialization procedures
|
|
26
|
+
- **`orchestration_principles.py`** - Core orchestration principles
|
|
27
|
+
- **`subprocess_validation.py`** - Subprocess validation protocol
|
|
28
|
+
- **`delegation_constraints.py`** - Critical delegation constraints
|
|
29
|
+
- **`environment_config.py`** - Environment configuration
|
|
30
|
+
- **`troubleshooting.py`** - Troubleshooting guide
|
|
31
|
+
- **`core_responsibilities.py`** - Core responsibilities list
|
|
32
|
+
- **`footer.py`** - Footer with metadata
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
The API remains unchanged from the original implementation:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from claude_pm.services.framework_claude_md_generator import FrameworkClaudeMdGenerator
|
|
40
|
+
|
|
41
|
+
# Create generator instance
|
|
42
|
+
generator = FrameworkClaudeMdGenerator()
|
|
43
|
+
|
|
44
|
+
# Generate content
|
|
45
|
+
content = generator.generate(
|
|
46
|
+
current_content=existing_content, # Optional: for version auto-increment
|
|
47
|
+
template_variables={'PLATFORM': 'darwin', 'PYTHON_CMD': 'python3'}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Deploy to parent directory
|
|
51
|
+
success, message = generator.deploy_to_parent(Path('/parent/dir'))
|
|
52
|
+
|
|
53
|
+
# Update a section
|
|
54
|
+
generator.update_section('agents', 'Custom agents content')
|
|
55
|
+
|
|
56
|
+
# Add custom section
|
|
57
|
+
generator.add_custom_section('custom', 'Custom content', after='agents')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Design Benefits
|
|
61
|
+
|
|
62
|
+
1. **Modularity**: Each concern is separated into its own module
|
|
63
|
+
2. **Maintainability**: Smaller, focused modules are easier to understand and modify
|
|
64
|
+
3. **Testability**: Individual components can be tested in isolation
|
|
65
|
+
4. **Extensibility**: New section generators can be added easily
|
|
66
|
+
5. **Performance**: Section generators are loaded on demand
|
|
67
|
+
6. **Backward Compatibility**: Original API preserved through facade pattern
|
|
68
|
+
|
|
69
|
+
## Section Generator Pattern
|
|
70
|
+
|
|
71
|
+
To add a new section generator:
|
|
72
|
+
|
|
73
|
+
1. Create a new file in `section_generators/`
|
|
74
|
+
2. Inherit from `BaseSectionGenerator`
|
|
75
|
+
3. Implement the `generate()` method
|
|
76
|
+
4. Register in `section_generators/__init__.py`
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
```python
|
|
80
|
+
from . import BaseSectionGenerator
|
|
81
|
+
|
|
82
|
+
class CustomSectionGenerator(BaseSectionGenerator):
|
|
83
|
+
def generate(self, data: Dict[str, Any]) -> str:
|
|
84
|
+
return "## Custom Section\n\nContent here..."
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Refactoring Summary
|
|
88
|
+
|
|
89
|
+
- **Original**: 1,267 lines in a single file
|
|
90
|
+
- **Refactored**: ~250 lines in main module + well-organized submodules
|
|
91
|
+
- **Total line reduction**: Main module reduced by 80%
|
|
92
|
+
- **Improved organization**: 13 focused modules instead of 1 large file
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Framework INSTRUCTIONS.md Generator Service
|
|
3
|
+
|
|
4
|
+
This service provides structured generation of the framework INSTRUCTIONS.md template
|
|
5
|
+
(legacy: CLAUDE.md) with auto-versioning, section management, and deployment capabilities.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Optional, Any, List, Tuple
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from .version_manager import VersionManager
|
|
12
|
+
from .content_validator import ContentValidator
|
|
13
|
+
from .content_assembler import ContentAssembler
|
|
14
|
+
from .deployment_manager import DeploymentManager
|
|
15
|
+
from .section_manager import SectionManager
|
|
16
|
+
from .section_generators import section_registry
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class FrameworkClaudeMdGenerator:
|
|
20
|
+
"""
|
|
21
|
+
Generates and manages the framework INSTRUCTIONS.md template (legacy: CLAUDE.md)
|
|
22
|
+
with structured sections, auto-versioning, and deployment capabilities.
|
|
23
|
+
|
|
24
|
+
This is the main facade class that coordinates all the submodules.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
"""Initialize the generator with current framework version."""
|
|
29
|
+
# Initialize managers
|
|
30
|
+
self.version_manager = VersionManager()
|
|
31
|
+
self.validator = ContentValidator()
|
|
32
|
+
self.assembler = ContentAssembler()
|
|
33
|
+
self.section_manager = SectionManager()
|
|
34
|
+
|
|
35
|
+
# Initialize deployment manager with dependencies
|
|
36
|
+
self.deployment_manager = DeploymentManager(
|
|
37
|
+
self.version_manager,
|
|
38
|
+
self.validator
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Get framework version
|
|
42
|
+
self.framework_version = self.version_manager.framework_version
|
|
43
|
+
|
|
44
|
+
# Initialize sections
|
|
45
|
+
self._initialize_sections()
|
|
46
|
+
|
|
47
|
+
def _initialize_sections(self):
|
|
48
|
+
"""Initialize all sections in the required order."""
|
|
49
|
+
# Register all default sections with their generators
|
|
50
|
+
section_order = [
|
|
51
|
+
'header',
|
|
52
|
+
'role_designation',
|
|
53
|
+
'agents',
|
|
54
|
+
'todo_task_tools',
|
|
55
|
+
'claude_pm_init',
|
|
56
|
+
'orchestration_principles',
|
|
57
|
+
'subprocess_validation',
|
|
58
|
+
'delegation_constraints',
|
|
59
|
+
'environment_config',
|
|
60
|
+
'troubleshooting',
|
|
61
|
+
'core_responsibilities',
|
|
62
|
+
'footer'
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
for section_name in section_order:
|
|
66
|
+
generator_class = section_registry.get(section_name)
|
|
67
|
+
if generator_class:
|
|
68
|
+
generator_instance = generator_class(self.framework_version)
|
|
69
|
+
self.section_manager.register_section(
|
|
70
|
+
section_name,
|
|
71
|
+
generator_instance.generate
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def generate(self,
|
|
75
|
+
current_content: Optional[str] = None,
|
|
76
|
+
template_variables: Optional[Dict[str, str]] = None) -> str:
|
|
77
|
+
"""
|
|
78
|
+
Generate the complete INSTRUCTIONS.md/CLAUDE.md content.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
current_content: Current INSTRUCTIONS.md/CLAUDE.md content for version parsing
|
|
82
|
+
template_variables: Variables to substitute in the template
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
str: Complete INSTRUCTIONS.md/CLAUDE.md content
|
|
86
|
+
"""
|
|
87
|
+
# Auto-increment version if current content provided
|
|
88
|
+
version = self.version_manager.auto_increment_version(current_content)
|
|
89
|
+
|
|
90
|
+
# Create metadata for header
|
|
91
|
+
metadata = self.assembler.create_metadata_dict(
|
|
92
|
+
version=version,
|
|
93
|
+
framework_version=self.framework_version
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Update header section with metadata
|
|
97
|
+
sections = self.section_manager.get_sections()
|
|
98
|
+
if 'header' in sections:
|
|
99
|
+
generator_func, _ = sections['header']
|
|
100
|
+
sections['header'] = (generator_func, metadata)
|
|
101
|
+
|
|
102
|
+
# Assemble content
|
|
103
|
+
content = self.assembler.assemble_content(
|
|
104
|
+
sections,
|
|
105
|
+
template_variables
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return content
|
|
109
|
+
|
|
110
|
+
def validate_content(self, content: str) -> Tuple[bool, List[str]]:
|
|
111
|
+
"""
|
|
112
|
+
Validate that generated content has all required sections.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
content: Content to validate
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Tuple of (is_valid, list_of_issues)
|
|
119
|
+
"""
|
|
120
|
+
return self.validator.validate_content(content)
|
|
121
|
+
|
|
122
|
+
def deploy_to_parent(self, parent_path: Path, force: bool = False) -> Tuple[bool, str]:
|
|
123
|
+
"""
|
|
124
|
+
Deploy generated content to a parent directory.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
parent_path: Path to parent directory
|
|
128
|
+
force: Force deployment even if versions match
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Tuple of (success, message)
|
|
132
|
+
"""
|
|
133
|
+
# Check if we need to read existing content
|
|
134
|
+
# Try INSTRUCTIONS.md first, fallback to CLAUDE.md for compatibility
|
|
135
|
+
target_file = parent_path / "INSTRUCTIONS.md"
|
|
136
|
+
if not target_file.exists() and (parent_path / "CLAUDE.md").exists():
|
|
137
|
+
target_file = parent_path / "CLAUDE.md"
|
|
138
|
+
current_content = None
|
|
139
|
+
|
|
140
|
+
if target_file.exists():
|
|
141
|
+
with open(target_file, 'r') as f:
|
|
142
|
+
current_content = f.read()
|
|
143
|
+
|
|
144
|
+
# Generate new content
|
|
145
|
+
new_content = self.generate(current_content=current_content)
|
|
146
|
+
|
|
147
|
+
# Deploy using deployment manager
|
|
148
|
+
return self.deployment_manager.deploy_to_parent(
|
|
149
|
+
new_content,
|
|
150
|
+
parent_path,
|
|
151
|
+
force
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def get_section_list(self) -> List[str]:
|
|
155
|
+
"""
|
|
156
|
+
Get list of all section names in order.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
List of section names
|
|
160
|
+
"""
|
|
161
|
+
return self.section_manager.get_section_list()
|
|
162
|
+
|
|
163
|
+
def update_section(self, section_name: str, content: str) -> bool:
|
|
164
|
+
"""
|
|
165
|
+
Update a specific section's generator to return custom content.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
section_name: Name of section to update
|
|
169
|
+
content: New content for the section
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
bool: Success status
|
|
173
|
+
"""
|
|
174
|
+
return self.section_manager.update_section(section_name, content)
|
|
175
|
+
|
|
176
|
+
def add_custom_section(self, section_name: str, content: str, after: Optional[str] = None):
|
|
177
|
+
"""
|
|
178
|
+
Add a custom section to the generator.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
section_name: Name for the new section
|
|
182
|
+
content: Content for the section
|
|
183
|
+
after: Section name to insert after (None = append at end)
|
|
184
|
+
"""
|
|
185
|
+
self.section_manager.add_custom_section(section_name, content, after)
|
|
186
|
+
|
|
187
|
+
# Compatibility methods to match original API
|
|
188
|
+
def _get_framework_version(self) -> str:
|
|
189
|
+
"""Get framework version (compatibility method)."""
|
|
190
|
+
return self.version_manager._get_framework_version()
|
|
191
|
+
|
|
192
|
+
def _parse_current_version(self, content: str) -> Tuple[str, int]:
|
|
193
|
+
"""Parse current version (compatibility method)."""
|
|
194
|
+
return self.version_manager.parse_current_version(content)
|
|
195
|
+
|
|
196
|
+
def _auto_increment_version(self, current_content: Optional[str] = None) -> str:
|
|
197
|
+
"""Auto-increment version (compatibility method)."""
|
|
198
|
+
return self.version_manager.auto_increment_version(current_content)
|
|
199
|
+
|
|
200
|
+
def _generate_content_hash(self) -> str:
|
|
201
|
+
"""Generate content hash (compatibility method)."""
|
|
202
|
+
return self.assembler.generate_content_hash()
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# Export the main class
|
|
206
|
+
__all__ = ['FrameworkClaudeMdGenerator']
|