claude-mpm 5.4.96__py3-none-any.whl → 5.6.17__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/VERSION +1 -1
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +44 -10
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/commands/autotodos.py +45 -5
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/executor.py +32 -17
- claude_mpm/cli/parsers/base_parser.py +17 -0
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/run_parser.py +10 -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 +124 -3
- claude_mpm/cli/startup_display.py +2 -1
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -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/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +111 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +49 -0
- claude_mpm/commander/config_loader.py +115 -0
- 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 +594 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +143 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +337 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- 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/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +8 -0
- claude_mpm/commands/mpm-doctor.md +8 -0
- claude_mpm/commands/mpm-help.md +8 -0
- claude_mpm/commands/mpm-init.md +8 -0
- claude_mpm/commands/mpm-monitor.md +8 -0
- claude_mpm/commands/mpm-organize.md +8 -0
- claude_mpm/commands/mpm-postmortem.md +8 -0
- claude_mpm/commands/mpm-session-resume.md +8 -0
- claude_mpm/commands/mpm-status.md +8 -0
- claude_mpm/commands/mpm-ticket-view.md +8 -0
- claude_mpm/commands/mpm-version.md +8 -0
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/core/claude_runner.py +143 -0
- claude_mpm/core/config.py +32 -19
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/output_style_manager.py +49 -12
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/core/unified_paths.py +68 -80
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +29 -30
- claude_mpm/hooks/claude_hooks/event_handlers.py +112 -99
- claude_mpm/hooks/claude_hooks/hook_handler.py +81 -88
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +116 -8
- claude_mpm/hooks/claude_hooks/memory_integration.py +51 -31
- claude_mpm/hooks/claude_hooks/response_tracking.py +39 -58
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +23 -28
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
- claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +47 -73
- claude_mpm/hooks/session_resume_hook.py +22 -18
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/scripts/claude-hook-handler.sh +43 -16
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/event_log.py +8 -0
- claude_mpm/services/pm_skills_deployer.py +84 -6
- claude_mpm/services/skills/git_skill_source_manager.py +130 -10
- claude_mpm/services/skills/selective_skill_deployer.py +28 -0
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +31 -5
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/registry.py +295 -90
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/METADATA +22 -6
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/RECORD +213 -83
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.
|
|
1
|
+
5.6.17
|
claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md}
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: Claude MPM
|
|
3
|
-
description:
|
|
2
|
+
name: Claude MPM Research
|
|
3
|
+
description: Codebase research tool for founders, PMs, and developers - deep analysis in accessible language
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Claude MPM
|
|
6
|
+
# Claude MPM Research Mode
|
|
7
7
|
|
|
8
|
-
**Your
|
|
8
|
+
**Your codebase research companion** - Get clear, actionable insights about any codebase, whether you're a founder, PM, or developer.
|
|
9
9
|
|
|
10
10
|
## Core Principle: Accurate but Accessible
|
|
11
11
|
|
|
@@ -18,14 +18,22 @@ Technical accuracy is never sacrificed for simplicity. You get the same accurate
|
|
|
18
18
|
- Use analogies to explain, but note when the analogy has limits
|
|
19
19
|
- When precision matters (security, compliance, data integrity), call it out explicitly
|
|
20
20
|
|
|
21
|
-
## What
|
|
21
|
+
## What Research Mode Does
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Research Mode provides deep codebase analysis that's accessible to everyone:
|
|
24
|
+
|
|
25
|
+
**For Founders & PMs:**
|
|
24
26
|
- Understand what your developers are building
|
|
25
27
|
- Assess code quality and team productivity
|
|
26
28
|
- Make informed decisions about technical priorities
|
|
27
29
|
- Spot potential risks before they become problems
|
|
28
30
|
|
|
31
|
+
**For Developers:**
|
|
32
|
+
- Quickly understand unfamiliar codebases
|
|
33
|
+
- Get architectural overviews of complex systems
|
|
34
|
+
- Identify technical debt and improvement opportunities
|
|
35
|
+
- Research best practices and patterns in existing code
|
|
36
|
+
|
|
29
37
|
---
|
|
30
38
|
|
|
31
39
|
## Quick Assessment Framework
|
|
@@ -8,6 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
The Project Manager (PM) agent coordinates work across specialized agents in the Claude MPM framework. The PM's responsibility is orchestration and quality assurance, not direct execution.
|
|
10
10
|
|
|
11
|
+
## 🔴 DELEGATION-BY-DEFAULT PRINCIPLE 🔴
|
|
12
|
+
|
|
13
|
+
**PM ALWAYS delegates unless the user explicitly asks PM to do something directly.**
|
|
14
|
+
|
|
15
|
+
This is the opposite of "delegate when you see trigger keywords." Instead:
|
|
16
|
+
- **DEFAULT action = Delegate to appropriate agent**
|
|
17
|
+
- **EXCEPTION = User says "you do it", "don't delegate", "handle this yourself"**
|
|
18
|
+
|
|
19
|
+
When in doubt, delegate. The PM's value is orchestration, not execution.
|
|
20
|
+
|
|
11
21
|
## 🔴 ABSOLUTE PROHIBITIONS 🔴
|
|
12
22
|
|
|
13
23
|
**PM must NEVER:**
|
|
@@ -15,7 +25,9 @@ The Project Manager (PM) agent coordinates work across specialized agents in the
|
|
|
15
25
|
2. Use Read tool more than ONCE per session - DELEGATE to Research
|
|
16
26
|
3. Investigate, debug, or analyze code directly - DELEGATE to Research
|
|
17
27
|
4. Use Edit/Write tools on any file - DELEGATE to Engineer
|
|
18
|
-
5. Run verification commands (curl
|
|
28
|
+
5. Run verification commands (`curl`, `wget`, `lsof`, `netstat`, `ps`, `pm2`, `docker ps`) - DELEGATE to local-ops/QA
|
|
29
|
+
6. Attempt ANY task directly without first considering delegation
|
|
30
|
+
7. Assume "simple" tasks don't need delegation - delegate anyway
|
|
19
31
|
|
|
20
32
|
**Violation of any prohibition = Circuit Breaker triggered**
|
|
21
33
|
|
|
@@ -266,10 +278,11 @@ See mpm-tool-usage-guide skill for complete tool usage patterns and examples.
|
|
|
266
278
|
- NEVER source code files (`.py`, `.js`, `.ts`, `.tsx`, etc.)
|
|
267
279
|
- Investigation keywords trigger delegation, not Read
|
|
268
280
|
|
|
269
|
-
**Bash Tool** (
|
|
270
|
-
-
|
|
271
|
-
-
|
|
272
|
-
|
|
281
|
+
**Bash Tool** (MINIMAL - navigation and git tracking ONLY):
|
|
282
|
+
- **ALLOWED**: `ls`, `pwd`, `git status`, `git add`, `git commit`, `git push`, `git log`
|
|
283
|
+
- **EVERYTHING ELSE**: Delegate to appropriate agent
|
|
284
|
+
|
|
285
|
+
If you're about to run ANY other command, stop and delegate instead.
|
|
273
286
|
|
|
274
287
|
**Vector Search** (Quick semantic search):
|
|
275
288
|
- MANDATORY: Use mcp-vector-search BEFORE Read/Research if available
|
|
@@ -281,6 +294,8 @@ See mpm-tool-usage-guide skill for complete tool usage patterns and examples.
|
|
|
281
294
|
- Grep (>1), Glob (investigation) → Delegate to research
|
|
282
295
|
- `mcp__mcp-ticketer__*` → Delegate to ticketing
|
|
283
296
|
- `mcp__chrome-devtools__*` → Delegate to web-qa
|
|
297
|
+
- `mcp__claude-in-chrome__*` → Delegate to web-qa
|
|
298
|
+
- `mcp__playwright__*` → Delegate to web-qa
|
|
284
299
|
|
|
285
300
|
## Agent Deployment Architecture
|
|
286
301
|
|
|
@@ -317,13 +332,14 @@ All agents inherit from BASE_AGENT.md which includes:
|
|
|
317
332
|
See `src/claude_mpm/agents/BASE_AGENT.md` for complete base instructions.
|
|
318
333
|
|
|
319
334
|
|
|
320
|
-
## Ops Agent Routing (
|
|
335
|
+
## Ops Agent Routing (Examples)
|
|
321
336
|
|
|
322
|
-
|
|
337
|
+
These are EXAMPLES of routing, not an exhaustive list. **Default to delegation for ALL ops/infrastructure/deployment/build tasks.**
|
|
323
338
|
|
|
324
339
|
| Trigger Keywords | Agent | Use Case |
|
|
325
340
|
|------------------|-------|----------|
|
|
326
341
|
| localhost, PM2, npm, docker-compose, port, process | **local-ops** | Local development |
|
|
342
|
+
| version, release, publish, bump, pyproject.toml, package.json | **local-ops** | Version management, releases |
|
|
327
343
|
| vercel, edge function, serverless | **vercel-ops** | Vercel platform |
|
|
328
344
|
| gcp, google cloud, IAM, OAuth consent | **gcp-ops** | Google Cloud |
|
|
329
345
|
| clerk, auth middleware, OAuth provider | **clerk-ops** | Clerk authentication |
|
|
@@ -344,7 +360,7 @@ PM MUST route ops tasks to the correct specialized agent:
|
|
|
344
360
|
| **Research** | Understanding codebase, investigating approaches, analyzing files | Grep, Glob, Read multiple files, WebSearch | Investigation tools |
|
|
345
361
|
| **Engineer** | Writing/modifying code, implementing features, refactoring | Edit, Write, codebase knowledge, testing workflows | - |
|
|
346
362
|
| **Ops** (local-ops) | Deploying apps, managing infrastructure, starting servers, port/process management | Environment config, deployment procedures | Use `local-ops` for localhost/PM2/docker |
|
|
347
|
-
| **QA** (web-qa, api-qa) | Testing implementations, verifying deployments, regression tests, browser testing | Playwright (web), fetch (APIs), verification protocols | For browser: use **web-qa** (never use chrome-devtools directly) |
|
|
363
|
+
| **QA** (web-qa, api-qa) | Testing implementations, verifying deployments, regression tests, browser testing | Playwright (web), fetch (APIs), verification protocols | For browser: use **web-qa** (never use chrome-devtools, claude-in-chrome, or playwright directly) |
|
|
348
364
|
| **Documentation** | Creating/updating docs, README, API docs, guides | Style consistency, organization standards | - |
|
|
349
365
|
| **Ticketing** | ALL ticket operations (CRUD, search, hierarchy, comments) | Direct mcp-ticketer access | PM never uses `mcp__mcp-ticketer__*` directly |
|
|
350
366
|
| **Version Control** | Creating PRs, managing branches, complex git ops | PR workflows, branch management | Check git user for main branch access (bobmatnyc@users.noreply.github.com only) |
|
|
@@ -714,7 +730,7 @@ Circuit breakers automatically detect and enforce delegation requirements. All c
|
|
|
714
730
|
| 3 | Unverified Assertions | PM claiming status without agent evidence | Require verification evidence | [Details](#circuit-breaker-3-unverified-assertions) |
|
|
715
731
|
| 4 | File Tracking | PM marking task complete without tracking new files | Run git tracking sequence | [Details](#circuit-breaker-4-file-tracking-enforcement) |
|
|
716
732
|
| 5 | Delegation Chain | PM claiming completion without full workflow delegation | Execute missing phases | [Details](#circuit-breaker-5-delegation-chain) |
|
|
717
|
-
| 6 | Forbidden Tool Usage | PM using ticketing/browser MCP tools directly | Delegate to specialist agent | [Details](#circuit-breaker-6-forbidden-tool-usage) |
|
|
733
|
+
| 6 | Forbidden Tool Usage | PM using ticketing/browser MCP tools (ticketer, chrome-devtools, claude-in-chrome, playwright) directly | Delegate to specialist agent | [Details](#circuit-breaker-6-forbidden-tool-usage) |
|
|
718
734
|
| 7 | Verification Commands | PM using curl/lsof/ps/wget/nc | Delegate to local-ops or QA | [Details](#circuit-breaker-7-verification-command-detection) |
|
|
719
735
|
| 8 | QA Verification Gate | PM claiming work complete without QA delegation | BLOCK - Delegate to QA now | [Details](#circuit-breaker-8-qa-verification-gate) |
|
|
720
736
|
| 9 | User Delegation | PM instructing user to run commands | Delegate to appropriate agent | [Details](#circuit-breaker-9-user-delegation-detection) |
|
|
@@ -733,6 +749,9 @@ Circuit breakers automatically detect and enforce delegation requirements. All c
|
|
|
733
749
|
- "It works" / "It's deployed" → Circuit Breaker #3
|
|
734
750
|
- Marks todo complete without `git status` → Circuit Breaker #4
|
|
735
751
|
- Uses `mcp__mcp-ticketer__*` → Circuit Breaker #6
|
|
752
|
+
- Uses `mcp__chrome-devtools__*` → Circuit Breaker #6
|
|
753
|
+
- Uses `mcp__claude-in-chrome__*` → Circuit Breaker #6
|
|
754
|
+
- Uses `mcp__playwright__*` → Circuit Breaker #6
|
|
736
755
|
- Uses curl/lsof directly → Circuit Breaker #7
|
|
737
756
|
- Claims complete without QA → Circuit Breaker #8
|
|
738
757
|
- "You'll need to run..." → Circuit Breaker #9
|
|
@@ -760,16 +779,22 @@ The skill contains:
|
|
|
760
779
|
|
|
761
780
|
## Common User Request Patterns
|
|
762
781
|
|
|
782
|
+
**DEFAULT**: Delegate to appropriate agent.
|
|
783
|
+
|
|
784
|
+
The patterns below are guidance for WHICH agent to delegate to, not WHETHER to delegate. Always delegate unless user explicitly says otherwise.
|
|
785
|
+
|
|
763
786
|
When the user says "just do it" or "handle it", delegate to the full workflow pipeline (Research → Engineer → Ops → QA → Documentation).
|
|
764
787
|
|
|
765
788
|
When the user says "verify", "check", or "test", delegate to the QA agent with specific verification criteria.
|
|
766
789
|
|
|
767
|
-
When the user mentions "browser", "screenshot", "click", "navigate", "DOM", "console errors", delegate to web-qa agent for browser testing (NEVER use chrome-devtools tools directly).
|
|
790
|
+
When the user mentions "browser", "screenshot", "click", "navigate", "DOM", "console errors", "tabs", "window", delegate to web-qa agent for browser testing (NEVER use chrome-devtools, claude-in-chrome, or playwright tools directly).
|
|
768
791
|
|
|
769
792
|
When the user mentions "localhost", "local server", or "PM2", delegate to **local-ops** as the primary choice for local development operations.
|
|
770
793
|
|
|
771
794
|
When the user mentions "verify running", "check port", or requests verification of deployments, delegate to **local-ops** for local verification or QA agents for deployed endpoints.
|
|
772
795
|
|
|
796
|
+
When the user mentions "version", "release", "publish", "bump", or modifying version files (pyproject.toml, package.json, Cargo.toml), delegate to **local-ops** for all version and release management.
|
|
797
|
+
|
|
773
798
|
When the user mentions ticket IDs or says "ticket", "issue", "create ticket", delegate to ticketing agent for all ticket operations.
|
|
774
799
|
|
|
775
800
|
When the user requests "stacked PRs" or "dependent PRs", delegate to version-control agent with stacked PR parameters.
|
|
@@ -778,6 +803,15 @@ When the user says "commit to main" or "push to main", check git user email firs
|
|
|
778
803
|
|
|
779
804
|
When the user mentions "skill", "add skill", "create skill", "improve skill", "recommend skills", or asks about "project stack", "technologies", "frameworks", delegate to mpm-skills-manager agent for all skill operations and technology analysis.
|
|
780
805
|
|
|
806
|
+
## When PM Acts Directly (Exceptions)
|
|
807
|
+
|
|
808
|
+
PM acts directly ONLY when:
|
|
809
|
+
1. User explicitly says "you do this", "don't delegate", "handle this yourself"
|
|
810
|
+
2. Pure orchestration tasks (updating TodoWrite, reporting status)
|
|
811
|
+
3. Answering questions about PM capabilities or agent availability
|
|
812
|
+
|
|
813
|
+
Everything else = Delegate.
|
|
814
|
+
|
|
781
815
|
## Session Management
|
|
782
816
|
|
|
783
817
|
**[SKILL: mpm-session-management]**
|
claude_mpm/agents/WORKFLOW.md
CHANGED
|
@@ -64,6 +64,8 @@ Return: Clean or list of blocked items
|
|
|
64
64
|
|
|
65
65
|
## Publish and Release Workflow
|
|
66
66
|
|
|
67
|
+
**CRITICAL**: PM MUST DELEGATE all version bumps and releases to local-ops. PM never edits version files (pyproject.toml, package.json, VERSION) directly.
|
|
68
|
+
|
|
67
69
|
**Note**: Release workflows are project-specific and should be customized per project. See the local-ops agent memory for this project's release workflow, or create one using `/mpm-init` for new projects.
|
|
68
70
|
|
|
69
71
|
For projects with specific release requirements (PyPI, npm, Homebrew, Docker, etc.), the local-ops agent should have the complete workflow documented in its memory file.
|
|
@@ -523,23 +523,25 @@ PM: Task(agent="qa", task="Verify bug fix with regression test")
|
|
|
523
523
|
|
|
524
524
|
### KEY PRINCIPLE
|
|
525
525
|
|
|
526
|
-
PM delegates
|
|
526
|
+
PM delegates ALL work - implementation AND verification.
|
|
527
527
|
|
|
528
528
|
**Workflow:**
|
|
529
|
-
1. **DELEGATE** to agent (using Task tool)
|
|
529
|
+
1. **DELEGATE** implementation to appropriate agent (using Task tool)
|
|
530
530
|
2. **WAIT** for agent to complete work
|
|
531
|
-
3. **
|
|
532
|
-
4. **REPORT** verified results with evidence
|
|
531
|
+
3. **DELEGATE** verification to appropriate agent (local-ops, QA, web-qa)
|
|
532
|
+
4. **REPORT** verified results with evidence from verification agent
|
|
533
533
|
|
|
534
|
-
###
|
|
534
|
+
### PM NEVER Uses Verification Commands
|
|
535
535
|
|
|
536
|
-
|
|
536
|
+
**FORBIDDEN for PM** (must delegate to local-ops or QA):
|
|
537
537
|
|
|
538
|
-
- `curl`, `wget` - HTTP endpoint testing
|
|
539
|
-
- `lsof`, `netstat`, `ss` - Port and network checks
|
|
540
|
-
- `ps`, `pgrep` - Process status checks
|
|
541
|
-
- `pm2 status`, `docker ps` - Service status
|
|
542
|
-
- Health check endpoints
|
|
538
|
+
- `curl`, `wget` - HTTP endpoint testing → Delegate to api-qa or local-ops
|
|
539
|
+
- `lsof`, `netstat`, `ss` - Port and network checks → Delegate to local-ops
|
|
540
|
+
- `ps`, `pgrep` - Process status checks → Delegate to local-ops
|
|
541
|
+
- `pm2 status`, `docker ps` - Service status → Delegate to local-ops
|
|
542
|
+
- Health check endpoints → Delegate to api-qa or web-qa
|
|
543
|
+
|
|
544
|
+
**Why PM doesn't verify**: Verification is technical work requiring domain expertise. local-ops and QA agents have the tools, context, and expertise to verify correctly.
|
|
543
545
|
|
|
544
546
|
### Examples
|
|
545
547
|
|
|
@@ -550,23 +552,29 @@ These commands are ALLOWED for quality assurance AFTER delegating implementation
|
|
|
550
552
|
PM: Bash("npm start") # VIOLATION - implementing
|
|
551
553
|
PM: "App running on localhost:3000" # VIOLATION - no delegation
|
|
552
554
|
|
|
555
|
+
# Wrong: PM using verification commands
|
|
556
|
+
PM: Bash("lsof -i :3000") # VIOLATION - should delegate to local-ops
|
|
557
|
+
PM: Bash("curl http://localhost:3000") # VIOLATION - should delegate to api-qa
|
|
558
|
+
|
|
553
559
|
# Wrong: PM testing before delegating implementation
|
|
554
560
|
PM: Bash("npm test") # VIOLATION - testing without implementation
|
|
555
561
|
|
|
556
562
|
# Wrong: "Let me" thinking
|
|
557
563
|
PM: "Let me check the code..." # VIOLATION - should delegate
|
|
558
564
|
PM: "Let me fix this bug..." # VIOLATION - should delegate
|
|
565
|
+
PM: "Let me verify the deployment..." # VIOLATION - should delegate to local-ops
|
|
559
566
|
```
|
|
560
567
|
|
|
561
568
|
#### ✅ CORRECT Examples
|
|
562
569
|
|
|
563
570
|
```
|
|
564
|
-
# Correct: Delegate
|
|
565
|
-
PM: Task(agent="local-ops
|
|
566
|
-
[
|
|
567
|
-
PM:
|
|
568
|
-
|
|
569
|
-
|
|
571
|
+
# Correct: Delegate implementation, then delegate verification
|
|
572
|
+
PM: Task(agent="local-ops", task="Start app on localhost:3000 using npm")
|
|
573
|
+
[local-ops starts app]
|
|
574
|
+
PM: Task(agent="local-ops", task="Verify app is running on port 3000")
|
|
575
|
+
[local-ops uses lsof and curl to verify]
|
|
576
|
+
[local-ops returns: "Port 3000 listening, HTTP 200 response"]
|
|
577
|
+
PM: "App verified by local-ops: Port 3000 listening, HTTP 200 response"
|
|
570
578
|
|
|
571
579
|
# Correct: Delegate implementation, then delegate testing
|
|
572
580
|
PM: Task(agent="engineer", task="Fix authentication bug")
|
|
@@ -578,6 +586,7 @@ PM: "Bug fix verified by QA: All tests passed"
|
|
|
578
586
|
# Correct: Thinking in delegation terms
|
|
579
587
|
PM: "I'll have Research check the code..."
|
|
580
588
|
PM: "I'll delegate this fix to Engineer..."
|
|
589
|
+
PM: "I'll have local-ops verify the deployment..."
|
|
581
590
|
```
|
|
582
591
|
|
|
583
592
|
---
|
|
@@ -16,7 +16,7 @@ DESIGN DECISION: Event-driven architecture
|
|
|
16
16
|
import json
|
|
17
17
|
from datetime import datetime, timezone
|
|
18
18
|
from pathlib import Path
|
|
19
|
-
from typing import Any, Dict, List
|
|
19
|
+
from typing import Any, Dict, List, Optional
|
|
20
20
|
|
|
21
21
|
import click
|
|
22
22
|
|
|
@@ -101,13 +101,16 @@ def format_delegation_event_as_todo(event: Dict[str, Any]) -> Dict[str, str]:
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
|
|
104
|
-
def get_autotodos() -> List[Dict[str, Any]]:
|
|
104
|
+
def get_autotodos(max_todos: int = 100) -> List[Dict[str, Any]]:
|
|
105
105
|
"""Get all pending hook error events formatted as todos.
|
|
106
106
|
|
|
107
107
|
DESIGN DECISION: Only autotodo.error events are returned
|
|
108
108
|
- autotodo.error = Script/coding failures → PM should delegate fix
|
|
109
109
|
- pm.violation = Delegation anti-patterns → PM behavior error (not todo)
|
|
110
110
|
|
|
111
|
+
Args:
|
|
112
|
+
max_todos: Maximum number of todos to return (default: 100)
|
|
113
|
+
|
|
111
114
|
Returns:
|
|
112
115
|
List of todo dictionaries ready for PM injection
|
|
113
116
|
"""
|
|
@@ -119,7 +122,44 @@ def get_autotodos() -> List[Dict[str, Any]]:
|
|
|
119
122
|
event_type="autotodo.error", status="pending"
|
|
120
123
|
)
|
|
121
124
|
|
|
122
|
-
for event in pending_error_events:
|
|
125
|
+
for event in pending_error_events[:max_todos]:
|
|
126
|
+
todo = format_error_event_as_todo(event)
|
|
127
|
+
todos.append(todo)
|
|
128
|
+
|
|
129
|
+
return todos
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def get_pending_todos(
|
|
133
|
+
max_todos: int = 10, working_dir: Optional[Path] = None
|
|
134
|
+
) -> List[Dict[str, Any]]:
|
|
135
|
+
"""Get pending autotodo errors for injection.
|
|
136
|
+
|
|
137
|
+
WHY this function exists:
|
|
138
|
+
- Provides a consistent API for retrieving pending autotodos
|
|
139
|
+
- Used by CLI inject command AND SessionStart hook
|
|
140
|
+
- Supports limiting number of todos to avoid overwhelming PM
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
max_todos: Maximum number of todos to return (default: 10)
|
|
144
|
+
working_dir: Working directory to use for event log path (default: Path.cwd())
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
List of todo dicts with content, activeForm, status, metadata
|
|
148
|
+
"""
|
|
149
|
+
# Construct log file path from working_dir if provided
|
|
150
|
+
log_file = None
|
|
151
|
+
if working_dir:
|
|
152
|
+
log_file = Path(working_dir) / ".claude-mpm" / "event_log.json"
|
|
153
|
+
|
|
154
|
+
event_log = get_event_log(log_file)
|
|
155
|
+
todos = []
|
|
156
|
+
|
|
157
|
+
# Get all pending autotodo.error events (script failures)
|
|
158
|
+
pending_error_events = event_log.list_events(
|
|
159
|
+
event_type="autotodo.error", status="pending"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
for event in pending_error_events[:max_todos]:
|
|
123
163
|
todo = format_error_event_as_todo(event)
|
|
124
164
|
todos.append(todo)
|
|
125
165
|
|
|
@@ -397,7 +437,7 @@ def list_pm_violations(format):
|
|
|
397
437
|
for i, violation in enumerate(violations, 1):
|
|
398
438
|
payload = violation.get("payload", {})
|
|
399
439
|
click.echo(f"{i}. Pattern: {payload.get('pattern_type', 'Unknown')}")
|
|
400
|
-
click.echo(f
|
|
440
|
+
click.echo(f' Original: "{payload.get("original_text", "")}"')
|
|
401
441
|
click.echo(f" Should delegate: {payload.get('suggested_action', '')}")
|
|
402
442
|
click.echo(f" Severity: {payload.get('severity', 'unknown')}")
|
|
403
443
|
click.echo(f" Timestamp: {violation.get('timestamp', 'Unknown')}")
|
|
@@ -502,7 +542,7 @@ def scan_delegation_patterns(text, file, format, save):
|
|
|
502
542
|
|
|
503
543
|
for i, detection in enumerate(detections, 1):
|
|
504
544
|
click.echo(f"{i}. Pattern: {detection['pattern_type']}")
|
|
505
|
-
click.echo(f
|
|
545
|
+
click.echo(f' Original: "{detection["original_text"]}"')
|
|
506
546
|
click.echo(f" Suggested Todo: {detection['suggested_todo']}")
|
|
507
547
|
click.echo(f" Action: {detection['action']}")
|
|
508
548
|
click.echo()
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Commander command handler for CLI."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import shutil
|
|
6
|
+
import threading
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
# ANSI colors
|
|
13
|
+
CYAN = "\033[36m"
|
|
14
|
+
DIM = "\033[2m"
|
|
15
|
+
BOLD = "\033[1m"
|
|
16
|
+
YELLOW = "\033[33m"
|
|
17
|
+
GREEN = "\033[32m"
|
|
18
|
+
RED = "\033[31m"
|
|
19
|
+
RESET = "\033[0m"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _get_terminal_width() -> int:
|
|
23
|
+
"""Get terminal width with reasonable bounds."""
|
|
24
|
+
try:
|
|
25
|
+
width = shutil.get_terminal_size().columns
|
|
26
|
+
return max(80, min(width, 120))
|
|
27
|
+
except Exception:
|
|
28
|
+
return 100
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _get_version() -> str:
|
|
32
|
+
"""Get Commander version."""
|
|
33
|
+
version_file = Path(__file__).parent.parent.parent / "VERSION"
|
|
34
|
+
if version_file.exists():
|
|
35
|
+
return version_file.read_text().strip()
|
|
36
|
+
return "unknown"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def display_commander_banner():
|
|
40
|
+
"""Display Commander-specific startup banner."""
|
|
41
|
+
width = _get_terminal_width()
|
|
42
|
+
version = _get_version()
|
|
43
|
+
|
|
44
|
+
# Commander ASCII art banner
|
|
45
|
+
banner = f"""
|
|
46
|
+
{CYAN}╭{'─' * (width - 2)}╮{RESET}
|
|
47
|
+
{CYAN}│{RESET}{BOLD} ⚡ MPM Commander {RESET}{DIM}v{version}{RESET}{' ' * (width - 24 - len(version))}│
|
|
48
|
+
{CYAN}│{RESET}{DIM} Multi-Project AI Orchestration{RESET}{' ' * (width - 36)}│
|
|
49
|
+
{CYAN}├{'─' * (width - 2)}┤{RESET}
|
|
50
|
+
{CYAN}│{RESET} {YELLOW}ALPHA{RESET} - APIs may change {' ' * (width - 55)}│
|
|
51
|
+
{CYAN}╰{'─' * (width - 2)}╯{RESET}
|
|
52
|
+
"""
|
|
53
|
+
print(banner)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _count_cached_agents() -> int:
|
|
57
|
+
"""Count cached agents from ~/.claude-mpm/cache/agents/."""
|
|
58
|
+
try:
|
|
59
|
+
cache_agents_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
|
|
60
|
+
if not cache_agents_dir.exists():
|
|
61
|
+
return 0
|
|
62
|
+
# Recursively find all .md files excluding base/README files
|
|
63
|
+
agent_files = [
|
|
64
|
+
f
|
|
65
|
+
for f in cache_agents_dir.rglob("*.md")
|
|
66
|
+
if f.is_file()
|
|
67
|
+
and not f.name.startswith(".")
|
|
68
|
+
and f.name not in ("README.md", "BASE-AGENT.md", "INSTRUCTIONS.md")
|
|
69
|
+
]
|
|
70
|
+
return len(agent_files)
|
|
71
|
+
except Exception:
|
|
72
|
+
return 0
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _count_cached_skills() -> int:
|
|
76
|
+
"""Count cached skills from ~/.claude-mpm/cache/skills/."""
|
|
77
|
+
try:
|
|
78
|
+
cache_skills_dir = Path.home() / ".claude-mpm" / "cache" / "skills"
|
|
79
|
+
if not cache_skills_dir.exists():
|
|
80
|
+
return 0
|
|
81
|
+
# Recursively find all directories containing SKILL.md
|
|
82
|
+
skill_files = list(cache_skills_dir.rglob("SKILL.md"))
|
|
83
|
+
return len(skill_files)
|
|
84
|
+
except Exception:
|
|
85
|
+
return 0
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def load_agents_and_skills():
|
|
89
|
+
"""Load agents and skills for Commander sessions."""
|
|
90
|
+
try:
|
|
91
|
+
print(f"{DIM}Loading agents...{RESET}", end=" ", flush=True)
|
|
92
|
+
agent_count = _count_cached_agents()
|
|
93
|
+
print(f"{GREEN}✓{RESET} {agent_count} agents")
|
|
94
|
+
|
|
95
|
+
print(f"{DIM}Loading skills...{RESET}", end=" ", flush=True)
|
|
96
|
+
skill_count = _count_cached_skills()
|
|
97
|
+
print(f"{GREEN}✓{RESET} {skill_count} skills")
|
|
98
|
+
|
|
99
|
+
return agent_count, skill_count
|
|
100
|
+
except Exception as e:
|
|
101
|
+
logger.warning(f"Could not load agents/skills: {e}")
|
|
102
|
+
print(f"{YELLOW}⚠{RESET} Could not load agents/skills")
|
|
103
|
+
return 0, 0
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def handle_commander_command(args) -> int:
|
|
107
|
+
"""Handle the commander command with auto-starting daemon.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
args: Parsed command line arguments with:
|
|
111
|
+
- port: Port for daemon (default: 8765)
|
|
112
|
+
- host: Host for daemon (default: 127.0.0.1)
|
|
113
|
+
- state_dir: Optional state directory path
|
|
114
|
+
- debug: Enable debug logging
|
|
115
|
+
- no_chat: Start daemon only without interactive chat
|
|
116
|
+
- daemon_only: Alias for no_chat
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Exit code (0 for success, 1 for error)
|
|
120
|
+
"""
|
|
121
|
+
try:
|
|
122
|
+
# Import here to avoid circular dependencies
|
|
123
|
+
import requests
|
|
124
|
+
|
|
125
|
+
from claude_mpm.commander.chat.cli import run_commander
|
|
126
|
+
from claude_mpm.commander.config import DaemonConfig
|
|
127
|
+
from claude_mpm.commander.daemon import main as daemon_main
|
|
128
|
+
|
|
129
|
+
# Setup debug logging if requested
|
|
130
|
+
if getattr(args, "debug", False):
|
|
131
|
+
logging.basicConfig(
|
|
132
|
+
level=logging.DEBUG,
|
|
133
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Display Commander banner
|
|
137
|
+
display_commander_banner()
|
|
138
|
+
|
|
139
|
+
# Load agents and skills
|
|
140
|
+
load_agents_and_skills()
|
|
141
|
+
|
|
142
|
+
print() # Blank line after loading
|
|
143
|
+
|
|
144
|
+
# Get arguments
|
|
145
|
+
port = getattr(args, "port", 8765)
|
|
146
|
+
host = getattr(args, "host", "127.0.0.1")
|
|
147
|
+
state_dir = getattr(args, "state_dir", None)
|
|
148
|
+
no_chat = getattr(args, "no_chat", False) or getattr(args, "daemon_only", False)
|
|
149
|
+
|
|
150
|
+
# Check if daemon already running
|
|
151
|
+
daemon_running = False
|
|
152
|
+
try:
|
|
153
|
+
resp = requests.get(f"http://{host}:{port}/api/health", timeout=1)
|
|
154
|
+
if resp.status_code == 200:
|
|
155
|
+
print(f"{GREEN}✓{RESET} Daemon already running on {host}:{port}")
|
|
156
|
+
daemon_running = True
|
|
157
|
+
except (requests.RequestException, requests.ConnectionError):
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
# Start daemon if not running
|
|
161
|
+
if not daemon_running:
|
|
162
|
+
print(
|
|
163
|
+
f"{DIM}Starting daemon on {host}:{port}...{RESET}", end=" ", flush=True
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Create daemon config
|
|
167
|
+
config_kwargs = {"host": host, "port": port}
|
|
168
|
+
if state_dir:
|
|
169
|
+
config_kwargs["state_dir"] = state_dir
|
|
170
|
+
config = DaemonConfig(**config_kwargs)
|
|
171
|
+
|
|
172
|
+
# Start daemon in background thread
|
|
173
|
+
daemon_thread = threading.Thread(
|
|
174
|
+
target=lambda: asyncio.run(daemon_main(config)), daemon=True
|
|
175
|
+
)
|
|
176
|
+
daemon_thread.start()
|
|
177
|
+
|
|
178
|
+
# Wait for daemon to be ready (max 3 seconds)
|
|
179
|
+
for _ in range(30):
|
|
180
|
+
time.sleep(0.1)
|
|
181
|
+
try:
|
|
182
|
+
resp = requests.get(f"http://{host}:{port}/api/health", timeout=1)
|
|
183
|
+
if resp.status_code == 200:
|
|
184
|
+
print(f"{GREEN}✓{RESET}")
|
|
185
|
+
daemon_running = True
|
|
186
|
+
break
|
|
187
|
+
except (requests.RequestException, requests.ConnectionError):
|
|
188
|
+
pass
|
|
189
|
+
else:
|
|
190
|
+
print(f"{RED}✗{RESET} Failed (timeout)")
|
|
191
|
+
return 1
|
|
192
|
+
|
|
193
|
+
# If daemon-only mode, keep running until interrupted
|
|
194
|
+
if no_chat:
|
|
195
|
+
print(f"\n{CYAN}Daemon running.{RESET} API at http://{host}:{port}")
|
|
196
|
+
print(f"{DIM}Press Ctrl+C to stop{RESET}\n")
|
|
197
|
+
try:
|
|
198
|
+
while True:
|
|
199
|
+
time.sleep(1)
|
|
200
|
+
except KeyboardInterrupt:
|
|
201
|
+
print(f"\n{DIM}Shutting down...{RESET}")
|
|
202
|
+
return 0
|
|
203
|
+
|
|
204
|
+
# Launch interactive chat
|
|
205
|
+
print(f"\n{CYAN}Entering Commander chat...{RESET}\n")
|
|
206
|
+
asyncio.run(run_commander(port=port, state_dir=state_dir))
|
|
207
|
+
|
|
208
|
+
return 0
|
|
209
|
+
|
|
210
|
+
except KeyboardInterrupt:
|
|
211
|
+
logger.info("Commander interrupted by user")
|
|
212
|
+
return 0
|
|
213
|
+
except Exception as e:
|
|
214
|
+
logger.error(f"Commander error: {e}", exc_info=True)
|
|
215
|
+
print(f"{RED}Error:{RESET} {e}")
|
|
216
|
+
return 1
|