claude-mpm 5.6.1__py3-none-any.whl → 5.6.76__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +8 -3
- claude_mpm/auth/__init__.py +35 -0
- claude_mpm/auth/callback_server.py +328 -0
- claude_mpm/auth/models.py +104 -0
- claude_mpm/auth/oauth_manager.py +266 -0
- claude_mpm/auth/providers/__init__.py +12 -0
- claude_mpm/auth/providers/base.py +165 -0
- claude_mpm/auth/providers/google.py +261 -0
- claude_mpm/auth/token_storage.py +252 -0
- claude_mpm/cli/commands/commander.py +174 -4
- claude_mpm/cli/commands/mcp.py +29 -17
- claude_mpm/cli/commands/mcp_command_router.py +39 -0
- claude_mpm/cli/commands/mcp_service_commands.py +304 -0
- claude_mpm/cli/commands/oauth.py +481 -0
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/executor.py +9 -0
- claude_mpm/cli/helpers.py +1 -1
- claude_mpm/cli/parsers/base_parser.py +13 -0
- claude_mpm/cli/parsers/commander_parser.py +43 -10
- claude_mpm/cli/parsers/mcp_parser.py +79 -0
- claude_mpm/cli/parsers/oauth_parser.py +165 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +5 -0
- claude_mpm/cli/startup.py +300 -33
- claude_mpm/cli/startup_display.py +4 -2
- claude_mpm/cli/startup_migrations.py +236 -0
- claude_mpm/commander/__init__.py +6 -0
- claude_mpm/commander/adapters/__init__.py +32 -3
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +98 -1
- claude_mpm/commander/adapters/claude_code.py +32 -1
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/app.py +32 -16
- claude_mpm/commander/api/errors.py +21 -0
- claude_mpm/commander/api/routes/messages.py +11 -11
- claude_mpm/commander/api/routes/projects.py +20 -20
- claude_mpm/commander/api/routes/sessions.py +37 -26
- claude_mpm/commander/api/routes/work.py +86 -50
- claude_mpm/commander/api/schemas.py +4 -0
- claude_mpm/commander/chat/cli.py +47 -5
- claude_mpm/commander/chat/commands.py +44 -16
- claude_mpm/commander/chat/repl.py +1729 -82
- claude_mpm/commander/config.py +5 -3
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +215 -10
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/manager.py +61 -1
- claude_mpm/commander/frameworks/base.py +91 -1
- claude_mpm/commander/frameworks/mpm.py +9 -14
- claude_mpm/commander/git/__init__.py +5 -0
- claude_mpm/commander/git/worktree_manager.py +212 -0
- claude_mpm/commander/instance_manager.py +546 -15
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/events.py +6 -0
- claude_mpm/commander/persistence/state_store.py +95 -1
- claude_mpm/commander/registry.py +10 -4
- claude_mpm/commander/runtime/monitor.py +32 -2
- claude_mpm/commander/tmux_orchestrator.py +3 -2
- claude_mpm/commander/work/executor.py +38 -20
- claude_mpm/commander/workflow/event_handler.py +25 -3
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +5 -0
- claude_mpm/core/claude_runner.py +152 -0
- claude_mpm/core/config.py +30 -22
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/hook_manager.py +2 -1
- claude_mpm/core/interactive_session.py +5 -4
- claude_mpm/core/logger.py +16 -2
- claude_mpm/core/logging_utils.py +40 -16
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/output_style_manager.py +37 -7
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_paths.py +68 -80
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +30 -31
- claude_mpm/hooks/claude_hooks/event_handlers.py +285 -194
- claude_mpm/hooks/claude_hooks/hook_handler.py +115 -32
- claude_mpm/hooks/claude_hooks/installer.py +222 -54
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +40 -59
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +25 -30
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +24 -28
- claude_mpm/hooks/claude_hooks/services/container.py +326 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +49 -75
- claude_mpm/hooks/session_resume_hook.py +22 -18
- claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
- claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
- claude_mpm/init.py +21 -14
- claude_mpm/mcp/__init__.py +9 -0
- claude_mpm/mcp/google_workspace_server.py +610 -0
- claude_mpm/scripts/claude-hook-handler.sh +10 -9
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/command_deployment_service.py +44 -26
- claude_mpm/services/hook_installer_service.py +77 -8
- claude_mpm/services/mcp_config_manager.py +99 -19
- claude_mpm/services/mcp_service_registry.py +294 -0
- claude_mpm/services/monitor/server.py +6 -1
- claude_mpm/services/pm_skills_deployer.py +5 -3
- claude_mpm/services/skills/git_skill_source_manager.py +79 -8
- claude_mpm/services/skills/selective_skill_deployer.py +28 -0
- claude_mpm/services/skills/skill_discovery_service.py +17 -1
- claude_mpm/services/skills_deployer.py +31 -5
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/registry.py +295 -90
- {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/METADATA +28 -3
- {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/RECORD +131 -93
- {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/WHEEL +1 -1
- {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/entry_points.txt +2 -0
- {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/top_level.txt +0 -0
|
@@ -9,7 +9,13 @@ import re
|
|
|
9
9
|
import shlex
|
|
10
10
|
from typing import List, Optional, Set
|
|
11
11
|
|
|
12
|
-
from .base import
|
|
12
|
+
from .base import (
|
|
13
|
+
Capability,
|
|
14
|
+
ParsedResponse,
|
|
15
|
+
RuntimeAdapter,
|
|
16
|
+
RuntimeCapability,
|
|
17
|
+
RuntimeInfo,
|
|
18
|
+
)
|
|
13
19
|
|
|
14
20
|
logger = logging.getLogger(__name__)
|
|
15
21
|
|
|
@@ -96,6 +102,31 @@ class ClaudeCodeAdapter(RuntimeAdapter):
|
|
|
96
102
|
Capability.COMPLEX_REASONING,
|
|
97
103
|
}
|
|
98
104
|
|
|
105
|
+
@property
|
|
106
|
+
def runtime_info(self) -> RuntimeInfo:
|
|
107
|
+
"""Return detailed runtime information."""
|
|
108
|
+
return RuntimeInfo(
|
|
109
|
+
name="claude-code",
|
|
110
|
+
version=None, # Version detection could be added
|
|
111
|
+
capabilities={
|
|
112
|
+
RuntimeCapability.FILE_READ,
|
|
113
|
+
RuntimeCapability.FILE_EDIT,
|
|
114
|
+
RuntimeCapability.FILE_CREATE,
|
|
115
|
+
RuntimeCapability.BASH_EXECUTION,
|
|
116
|
+
RuntimeCapability.GIT_OPERATIONS,
|
|
117
|
+
RuntimeCapability.TOOL_USE,
|
|
118
|
+
RuntimeCapability.WEB_SEARCH,
|
|
119
|
+
RuntimeCapability.COMPLEX_REASONING,
|
|
120
|
+
RuntimeCapability.AGENT_DELEGATION, # Claude Code supports Task tool
|
|
121
|
+
RuntimeCapability.HOOKS, # Claude Code supports hooks
|
|
122
|
+
RuntimeCapability.SKILLS, # Claude Code can load skills
|
|
123
|
+
RuntimeCapability.MONITOR, # Can be monitored
|
|
124
|
+
},
|
|
125
|
+
command="claude",
|
|
126
|
+
supports_agents=True, # Claude Code supports agent delegation
|
|
127
|
+
instruction_file="CLAUDE.md",
|
|
128
|
+
)
|
|
129
|
+
|
|
99
130
|
def build_launch_command(
|
|
100
131
|
self, project_path: str, agent_prompt: Optional[str] = None
|
|
101
132
|
) -> str:
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Codex CLI runtime adapter.
|
|
2
|
+
|
|
3
|
+
This module implements the RuntimeAdapter interface for Codex,
|
|
4
|
+
an AI coding assistant (limited support currently).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import re
|
|
9
|
+
import shlex
|
|
10
|
+
from typing import List, Optional, Set
|
|
11
|
+
|
|
12
|
+
from .base import (
|
|
13
|
+
Capability,
|
|
14
|
+
ParsedResponse,
|
|
15
|
+
RuntimeAdapter,
|
|
16
|
+
RuntimeCapability,
|
|
17
|
+
RuntimeInfo,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CodexAdapter(RuntimeAdapter):
|
|
24
|
+
"""Adapter for Codex CLI.
|
|
25
|
+
|
|
26
|
+
Codex is an AI coding assistant. This adapter provides basic support,
|
|
27
|
+
with limited capabilities compared to Claude Code or MPM.
|
|
28
|
+
|
|
29
|
+
Note:
|
|
30
|
+
Agent delegation and advanced features not yet supported.
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> adapter = CodexAdapter()
|
|
34
|
+
>>> cmd = adapter.build_launch_command("/home/user/project")
|
|
35
|
+
>>> print(cmd)
|
|
36
|
+
cd '/home/user/project' && codex
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
# Idle detection patterns
|
|
40
|
+
IDLE_PATTERNS = [
|
|
41
|
+
r"^>\s*$", # Simple prompt
|
|
42
|
+
r"codex>\s*$", # Named prompt
|
|
43
|
+
r"Ready",
|
|
44
|
+
r"Waiting for input",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
# Error patterns
|
|
48
|
+
ERROR_PATTERNS = [
|
|
49
|
+
r"Error:",
|
|
50
|
+
r"Failed:",
|
|
51
|
+
r"Exception:",
|
|
52
|
+
r"Permission denied",
|
|
53
|
+
r"not found",
|
|
54
|
+
r"Traceback",
|
|
55
|
+
r"FATAL:",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
# Question patterns
|
|
59
|
+
QUESTION_PATTERNS = [
|
|
60
|
+
r"Which option",
|
|
61
|
+
r"Should I proceed",
|
|
62
|
+
r"Please choose",
|
|
63
|
+
r"\(y/n\)\?",
|
|
64
|
+
r"Are you sure",
|
|
65
|
+
r"\[Y/n\]",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
# ANSI escape code pattern
|
|
69
|
+
ANSI_ESCAPE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def name(self) -> str:
|
|
73
|
+
"""Return the runtime identifier."""
|
|
74
|
+
return "codex"
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def capabilities(self) -> Set[Capability]:
|
|
78
|
+
"""Return the set of capabilities supported by Codex."""
|
|
79
|
+
return {
|
|
80
|
+
Capability.TOOL_USE,
|
|
81
|
+
Capability.FILE_EDIT,
|
|
82
|
+
Capability.FILE_CREATE,
|
|
83
|
+
Capability.SHELL_COMMANDS,
|
|
84
|
+
Capability.COMPLEX_REASONING,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def runtime_info(self) -> RuntimeInfo:
|
|
89
|
+
"""Return detailed runtime information."""
|
|
90
|
+
return RuntimeInfo(
|
|
91
|
+
name="codex",
|
|
92
|
+
version=None, # Version detection could be added
|
|
93
|
+
capabilities={
|
|
94
|
+
RuntimeCapability.FILE_READ,
|
|
95
|
+
RuntimeCapability.FILE_EDIT,
|
|
96
|
+
RuntimeCapability.FILE_CREATE,
|
|
97
|
+
RuntimeCapability.BASH_EXECUTION,
|
|
98
|
+
RuntimeCapability.TOOL_USE,
|
|
99
|
+
RuntimeCapability.COMPLEX_REASONING,
|
|
100
|
+
},
|
|
101
|
+
command="codex",
|
|
102
|
+
supports_agents=False, # No agent support
|
|
103
|
+
instruction_file=None, # No custom instructions support
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def build_launch_command(
|
|
107
|
+
self, project_path: str, agent_prompt: Optional[str] = None
|
|
108
|
+
) -> str:
|
|
109
|
+
"""Generate shell command to start Codex.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
project_path: Absolute path to the project directory
|
|
113
|
+
agent_prompt: Optional system prompt (may not be supported)
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Shell command string ready to execute
|
|
117
|
+
|
|
118
|
+
Example:
|
|
119
|
+
>>> adapter = CodexAdapter()
|
|
120
|
+
>>> adapter.build_launch_command("/home/user/project")
|
|
121
|
+
"cd '/home/user/project' && codex"
|
|
122
|
+
"""
|
|
123
|
+
quoted_path = shlex.quote(project_path)
|
|
124
|
+
cmd = f"cd {quoted_path} && codex"
|
|
125
|
+
|
|
126
|
+
# Note: Codex may not support custom prompts
|
|
127
|
+
# Adjust based on actual Codex CLI capabilities
|
|
128
|
+
if agent_prompt:
|
|
129
|
+
logger.warning("Codex may not support custom prompts")
|
|
130
|
+
|
|
131
|
+
logger.debug(f"Built Codex launch command: {cmd}")
|
|
132
|
+
return cmd
|
|
133
|
+
|
|
134
|
+
def format_input(self, message: str) -> str:
|
|
135
|
+
"""Prepare message for Codex's input format."""
|
|
136
|
+
formatted = message.strip()
|
|
137
|
+
logger.debug(f"Formatted input: {formatted[:100]}...")
|
|
138
|
+
return formatted
|
|
139
|
+
|
|
140
|
+
def strip_ansi(self, text: str) -> str:
|
|
141
|
+
"""Remove ANSI escape codes from text."""
|
|
142
|
+
return self.ANSI_ESCAPE.sub("", text)
|
|
143
|
+
|
|
144
|
+
def detect_idle(self, output: str) -> bool:
|
|
145
|
+
"""Recognize when Codex is waiting for input."""
|
|
146
|
+
if not output:
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
clean = self.strip_ansi(output)
|
|
150
|
+
lines = clean.strip().split("\n")
|
|
151
|
+
|
|
152
|
+
if not lines:
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
last_line = lines[-1].strip()
|
|
156
|
+
|
|
157
|
+
for pattern in self.IDLE_PATTERNS:
|
|
158
|
+
if re.search(pattern, last_line):
|
|
159
|
+
logger.debug(f"Detected idle state with pattern: {pattern}")
|
|
160
|
+
return True
|
|
161
|
+
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
def detect_error(self, output: str) -> Optional[str]:
|
|
165
|
+
"""Recognize error states and extract error message."""
|
|
166
|
+
clean = self.strip_ansi(output)
|
|
167
|
+
|
|
168
|
+
for pattern in self.ERROR_PATTERNS:
|
|
169
|
+
match = re.search(pattern, clean, re.IGNORECASE)
|
|
170
|
+
if match:
|
|
171
|
+
for line in clean.split("\n"):
|
|
172
|
+
if re.search(pattern, line, re.IGNORECASE):
|
|
173
|
+
error_msg = line.strip()
|
|
174
|
+
logger.warning(f"Detected error: {error_msg}")
|
|
175
|
+
return error_msg
|
|
176
|
+
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
def detect_question(
|
|
180
|
+
self, output: str
|
|
181
|
+
) -> tuple[bool, Optional[str], Optional[List[str]]]:
|
|
182
|
+
"""Detect if Codex is asking a question."""
|
|
183
|
+
clean = self.strip_ansi(output)
|
|
184
|
+
|
|
185
|
+
for pattern in self.QUESTION_PATTERNS:
|
|
186
|
+
if re.search(pattern, clean, re.IGNORECASE):
|
|
187
|
+
lines = clean.strip().split("\n")
|
|
188
|
+
question = None
|
|
189
|
+
options = []
|
|
190
|
+
|
|
191
|
+
for line in lines:
|
|
192
|
+
if re.search(pattern, line, re.IGNORECASE):
|
|
193
|
+
question = line.strip()
|
|
194
|
+
|
|
195
|
+
# Look for numbered options
|
|
196
|
+
opt_match = re.match(r"^\s*(\d+)[.):]\s*(.+)$", line)
|
|
197
|
+
if opt_match:
|
|
198
|
+
options.append(opt_match.group(2).strip())
|
|
199
|
+
|
|
200
|
+
logger.debug(
|
|
201
|
+
f"Detected question: {question}, options: {options if options else 'none'}"
|
|
202
|
+
)
|
|
203
|
+
return True, question, options if options else None
|
|
204
|
+
|
|
205
|
+
return False, None, None
|
|
206
|
+
|
|
207
|
+
def parse_response(self, output: str) -> ParsedResponse:
|
|
208
|
+
"""Extract meaningful content from Codex output."""
|
|
209
|
+
if not output:
|
|
210
|
+
return ParsedResponse(
|
|
211
|
+
content="",
|
|
212
|
+
is_complete=False,
|
|
213
|
+
is_error=False,
|
|
214
|
+
is_question=False,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
clean = self.strip_ansi(output)
|
|
218
|
+
error_msg = self.detect_error(output)
|
|
219
|
+
is_question, question_text, options = self.detect_question(output)
|
|
220
|
+
is_complete = self.detect_idle(output)
|
|
221
|
+
|
|
222
|
+
response = ParsedResponse(
|
|
223
|
+
content=clean,
|
|
224
|
+
is_complete=is_complete,
|
|
225
|
+
is_error=error_msg is not None,
|
|
226
|
+
error_message=error_msg,
|
|
227
|
+
is_question=is_question,
|
|
228
|
+
question_text=question_text,
|
|
229
|
+
options=options,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
logger.debug(
|
|
233
|
+
f"Parsed response: complete={is_complete}, error={error_msg is not None}, "
|
|
234
|
+
f"question={is_question}"
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
return response
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Example usage of multi-runtime adapter architecture.
|
|
2
|
+
|
|
3
|
+
This module demonstrates how to use the adapter registry and
|
|
4
|
+
individual adapters for different AI coding runtimes.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from claude_mpm.commander.adapters import (
|
|
11
|
+
AdapterRegistry,
|
|
12
|
+
AuggieAdapter,
|
|
13
|
+
ClaudeCodeAdapter,
|
|
14
|
+
CodexAdapter,
|
|
15
|
+
MPMAdapter,
|
|
16
|
+
RuntimeAdapter,
|
|
17
|
+
RuntimeCapability,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Configure logging
|
|
21
|
+
logging.basicConfig(
|
|
22
|
+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
23
|
+
)
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def example_registry_usage() -> None:
|
|
28
|
+
"""Demonstrate adapter registry usage."""
|
|
29
|
+
print("\n" + "=" * 60)
|
|
30
|
+
print("ADAPTER REGISTRY USAGE")
|
|
31
|
+
print("=" * 60 + "\n")
|
|
32
|
+
|
|
33
|
+
# List all registered adapters
|
|
34
|
+
registered = AdapterRegistry.list_registered()
|
|
35
|
+
print(f"Registered adapters: {registered}")
|
|
36
|
+
|
|
37
|
+
# Detect available runtimes on system
|
|
38
|
+
available = AdapterRegistry.detect_available()
|
|
39
|
+
print(f"Available runtimes: {available}")
|
|
40
|
+
|
|
41
|
+
# Get default adapter (best available)
|
|
42
|
+
default_adapter = AdapterRegistry.get_default()
|
|
43
|
+
if default_adapter:
|
|
44
|
+
print(f"\nDefault adapter: {default_adapter.name}")
|
|
45
|
+
print(f"Capabilities: {default_adapter.capabilities}")
|
|
46
|
+
else:
|
|
47
|
+
print("\nNo adapters available on this system")
|
|
48
|
+
|
|
49
|
+
# Get specific adapter
|
|
50
|
+
mpm_adapter = AdapterRegistry.get("mpm")
|
|
51
|
+
if mpm_adapter:
|
|
52
|
+
print(f"\nMPM adapter available: {mpm_adapter.name}")
|
|
53
|
+
else:
|
|
54
|
+
print("\nMPM adapter not available")
|
|
55
|
+
|
|
56
|
+
# Check if specific runtime is available
|
|
57
|
+
if AdapterRegistry.is_available("claude-code"):
|
|
58
|
+
print("\nClaude Code is available")
|
|
59
|
+
else:
|
|
60
|
+
print("\nClaude Code is NOT available")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def example_adapter_capabilities() -> None:
|
|
64
|
+
"""Demonstrate checking adapter capabilities."""
|
|
65
|
+
print("\n" + "=" * 60)
|
|
66
|
+
print("ADAPTER CAPABILITIES")
|
|
67
|
+
print("=" * 60 + "\n")
|
|
68
|
+
|
|
69
|
+
adapters = [
|
|
70
|
+
ClaudeCodeAdapter(),
|
|
71
|
+
AuggieAdapter(),
|
|
72
|
+
CodexAdapter(),
|
|
73
|
+
MPMAdapter(),
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
for adapter in adapters:
|
|
77
|
+
print(f"\n{adapter.name.upper()} Adapter:")
|
|
78
|
+
print(
|
|
79
|
+
f" Command: {adapter.runtime_info.command if adapter.runtime_info else 'N/A'}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Check for specific capabilities
|
|
83
|
+
info = adapter.runtime_info
|
|
84
|
+
if info:
|
|
85
|
+
print(f" Supports agents: {info.supports_agents}")
|
|
86
|
+
print(f" Instruction file: {info.instruction_file or 'None'}")
|
|
87
|
+
|
|
88
|
+
# Check for advanced features
|
|
89
|
+
if RuntimeCapability.AGENT_DELEGATION in info.capabilities:
|
|
90
|
+
print(" ✓ Agent delegation supported")
|
|
91
|
+
else:
|
|
92
|
+
print(" ✗ Agent delegation NOT supported")
|
|
93
|
+
|
|
94
|
+
if RuntimeCapability.HOOKS in info.capabilities:
|
|
95
|
+
print(" ✓ Lifecycle hooks supported")
|
|
96
|
+
else:
|
|
97
|
+
print(" ✗ Lifecycle hooks NOT supported")
|
|
98
|
+
|
|
99
|
+
if RuntimeCapability.MCP_TOOLS in info.capabilities:
|
|
100
|
+
print(" ✓ MCP tools supported")
|
|
101
|
+
else:
|
|
102
|
+
print(" ✗ MCP tools NOT supported")
|
|
103
|
+
|
|
104
|
+
if RuntimeCapability.SKILLS in info.capabilities:
|
|
105
|
+
print(" ✓ Skills supported")
|
|
106
|
+
else:
|
|
107
|
+
print(" ✗ Skills NOT supported")
|
|
108
|
+
|
|
109
|
+
if RuntimeCapability.MONITOR in info.capabilities:
|
|
110
|
+
print(" ✓ Real-time monitoring supported")
|
|
111
|
+
else:
|
|
112
|
+
print(" ✗ Real-time monitoring NOT supported")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def example_build_commands() -> None:
|
|
116
|
+
"""Demonstrate building launch commands."""
|
|
117
|
+
print("\n" + "=" * 60)
|
|
118
|
+
print("BUILD LAUNCH COMMANDS")
|
|
119
|
+
print("=" * 60 + "\n")
|
|
120
|
+
|
|
121
|
+
project_path = "/home/user/my-project"
|
|
122
|
+
agent_prompt = "You are a Python expert specializing in FastAPI and async code."
|
|
123
|
+
|
|
124
|
+
adapters = [
|
|
125
|
+
ClaudeCodeAdapter(),
|
|
126
|
+
AuggieAdapter(),
|
|
127
|
+
CodexAdapter(),
|
|
128
|
+
MPMAdapter(),
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
for adapter in adapters:
|
|
132
|
+
print(f"\n{adapter.name.upper()}:")
|
|
133
|
+
|
|
134
|
+
# Basic launch command
|
|
135
|
+
cmd = adapter.build_launch_command(project_path)
|
|
136
|
+
print(f" Basic: {cmd}")
|
|
137
|
+
|
|
138
|
+
# With agent prompt
|
|
139
|
+
cmd_with_prompt = adapter.build_launch_command(project_path, agent_prompt)
|
|
140
|
+
print(f" With prompt: {cmd_with_prompt}")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def example_inject_instructions() -> None:
|
|
144
|
+
"""Demonstrate injecting custom instructions."""
|
|
145
|
+
print("\n" + "=" * 60)
|
|
146
|
+
print("INJECT CUSTOM INSTRUCTIONS")
|
|
147
|
+
print("=" * 60 + "\n")
|
|
148
|
+
|
|
149
|
+
instructions = """You are a senior Python engineer.
|
|
150
|
+
Follow PEP 8 strictly.
|
|
151
|
+
Write comprehensive tests for all code.
|
|
152
|
+
Use type hints everywhere."""
|
|
153
|
+
|
|
154
|
+
adapters = [
|
|
155
|
+
ClaudeCodeAdapter(),
|
|
156
|
+
AuggieAdapter(),
|
|
157
|
+
CodexAdapter(),
|
|
158
|
+
MPMAdapter(),
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
for adapter in adapters:
|
|
162
|
+
print(f"\n{adapter.name.upper()}:")
|
|
163
|
+
|
|
164
|
+
cmd = adapter.inject_instructions(instructions)
|
|
165
|
+
if cmd:
|
|
166
|
+
print(f" Command: {cmd}")
|
|
167
|
+
else:
|
|
168
|
+
print(" Not supported")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def example_inject_agent_context() -> None:
|
|
172
|
+
"""Demonstrate injecting agent context."""
|
|
173
|
+
print("\n" + "=" * 60)
|
|
174
|
+
print("INJECT AGENT CONTEXT")
|
|
175
|
+
print("=" * 60 + "\n")
|
|
176
|
+
|
|
177
|
+
agent_id = "eng-001"
|
|
178
|
+
context = {
|
|
179
|
+
"role": "Engineer",
|
|
180
|
+
"specialty": "Backend Python",
|
|
181
|
+
"task": "Implement API endpoints",
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
adapters = [
|
|
185
|
+
ClaudeCodeAdapter(),
|
|
186
|
+
AuggieAdapter(),
|
|
187
|
+
CodexAdapter(),
|
|
188
|
+
MPMAdapter(),
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
for adapter in adapters:
|
|
192
|
+
print(f"\n{adapter.name.upper()}:")
|
|
193
|
+
|
|
194
|
+
cmd = adapter.inject_agent_context(agent_id, context)
|
|
195
|
+
if cmd:
|
|
196
|
+
print(f" Command: {cmd[:100]}...")
|
|
197
|
+
else:
|
|
198
|
+
print(" Not supported")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def example_parse_response() -> None:
|
|
202
|
+
"""Demonstrate parsing runtime output."""
|
|
203
|
+
print("\n" + "=" * 60)
|
|
204
|
+
print("PARSE RUNTIME OUTPUT")
|
|
205
|
+
print("=" * 60 + "\n")
|
|
206
|
+
|
|
207
|
+
# Simulate different output scenarios
|
|
208
|
+
outputs = {
|
|
209
|
+
"idle": "File created successfully.\n> ",
|
|
210
|
+
"error": "Error: File not found: config.py\n> ",
|
|
211
|
+
"question": "Should I proceed with the changes? (y/n)?",
|
|
212
|
+
"processing": "Processing your request...",
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
adapter = ClaudeCodeAdapter()
|
|
216
|
+
|
|
217
|
+
for scenario, output in outputs.items():
|
|
218
|
+
print(f"\n{scenario.upper()}:")
|
|
219
|
+
parsed = adapter.parse_response(output)
|
|
220
|
+
print(f" Content: {parsed.content[:50]}...")
|
|
221
|
+
print(f" Is complete: {parsed.is_complete}")
|
|
222
|
+
print(f" Is error: {parsed.is_error}")
|
|
223
|
+
print(f" Is question: {parsed.is_question}")
|
|
224
|
+
if parsed.error_message:
|
|
225
|
+
print(f" Error message: {parsed.error_message}")
|
|
226
|
+
if parsed.question_text:
|
|
227
|
+
print(f" Question: {parsed.question_text}")
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def example_runtime_selection() -> None:
|
|
231
|
+
"""Demonstrate selecting runtime based on requirements."""
|
|
232
|
+
print("\n" + "=" * 60)
|
|
233
|
+
print("RUNTIME SELECTION LOGIC")
|
|
234
|
+
print("=" * 60 + "\n")
|
|
235
|
+
|
|
236
|
+
def select_runtime(
|
|
237
|
+
needs_agents: bool = False, needs_mcp: bool = False
|
|
238
|
+
) -> Optional[RuntimeAdapter]:
|
|
239
|
+
"""Select appropriate runtime based on requirements."""
|
|
240
|
+
# Get all available adapters
|
|
241
|
+
available = AdapterRegistry.detect_available()
|
|
242
|
+
|
|
243
|
+
# Filter by requirements
|
|
244
|
+
for name in available:
|
|
245
|
+
adapter = AdapterRegistry.get(name)
|
|
246
|
+
if not adapter or not adapter.runtime_info:
|
|
247
|
+
continue
|
|
248
|
+
|
|
249
|
+
info = adapter.runtime_info
|
|
250
|
+
|
|
251
|
+
# Check agent requirement
|
|
252
|
+
if needs_agents and not info.supports_agents:
|
|
253
|
+
continue
|
|
254
|
+
|
|
255
|
+
# Check MCP requirement
|
|
256
|
+
if needs_mcp and RuntimeCapability.MCP_TOOLS not in info.capabilities:
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
# Found suitable runtime
|
|
260
|
+
return adapter
|
|
261
|
+
|
|
262
|
+
return None
|
|
263
|
+
|
|
264
|
+
# Example 1: Need agent delegation
|
|
265
|
+
print("Requirement: Agent delegation")
|
|
266
|
+
adapter = select_runtime(needs_agents=True)
|
|
267
|
+
if adapter:
|
|
268
|
+
print(f" Selected: {adapter.name}")
|
|
269
|
+
else:
|
|
270
|
+
print(" No suitable runtime found")
|
|
271
|
+
|
|
272
|
+
# Example 2: Need MCP tools
|
|
273
|
+
print("\nRequirement: MCP tools")
|
|
274
|
+
adapter = select_runtime(needs_mcp=True)
|
|
275
|
+
if adapter:
|
|
276
|
+
print(f" Selected: {adapter.name}")
|
|
277
|
+
else:
|
|
278
|
+
print(" No suitable runtime found")
|
|
279
|
+
|
|
280
|
+
# Example 3: Need both
|
|
281
|
+
print("\nRequirement: Agent delegation + MCP tools")
|
|
282
|
+
adapter = select_runtime(needs_agents=True, needs_mcp=True)
|
|
283
|
+
if adapter:
|
|
284
|
+
print(f" Selected: {adapter.name}")
|
|
285
|
+
else:
|
|
286
|
+
print(" No suitable runtime found")
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def main() -> None:
|
|
290
|
+
"""Run all examples."""
|
|
291
|
+
print("\n" + "#" * 60)
|
|
292
|
+
print("# MULTI-RUNTIME ADAPTER ARCHITECTURE EXAMPLES")
|
|
293
|
+
print("#" * 60)
|
|
294
|
+
|
|
295
|
+
# Run all examples
|
|
296
|
+
example_registry_usage()
|
|
297
|
+
example_adapter_capabilities()
|
|
298
|
+
example_build_commands()
|
|
299
|
+
example_inject_instructions()
|
|
300
|
+
example_inject_agent_context()
|
|
301
|
+
example_parse_response()
|
|
302
|
+
example_runtime_selection()
|
|
303
|
+
|
|
304
|
+
print("\n" + "#" * 60)
|
|
305
|
+
print("# EXAMPLES COMPLETE")
|
|
306
|
+
print("#" * 60 + "\n")
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
if __name__ == "__main__":
|
|
310
|
+
main()
|