claude-mpm 5.4.85__py3-none-any.whl → 5.6.1__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/CLAUDE_MPM_OUTPUT_STYLE.md +8 -5
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +101 -703
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +46 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +2 -2
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/executor.py +119 -16
- claude_mpm/cli/parsers/base_parser.py +71 -1
- claude_mpm/cli/parsers/commander_parser.py +83 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/startup.py +54 -16
- claude_mpm/cli/startup_display.py +72 -5
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +72 -0
- claude_mpm/commander/adapters/__init__.py +31 -0
- claude_mpm/commander/adapters/base.py +191 -0
- claude_mpm/commander/adapters/claude_code.py +361 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +105 -0
- claude_mpm/commander/api/errors.py +112 -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 +215 -0
- claude_mpm/commander/api/routes/work.py +260 -0
- claude_mpm/commander/api/schemas.py +182 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +107 -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/daemon.py +398 -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/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 +404 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +316 -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 +189 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +219 -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 +9 -1
- 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/core/config.py +5 -0
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/logger.py +10 -7
- claude_mpm/core/logging_utils.py +4 -2
- claude_mpm/core/output_style_manager.py +15 -5
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +9 -9
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +486 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +250 -11
- claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +69 -5
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +20 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +14 -77
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +30 -6
- claude_mpm/hooks/session_resume_hook.py +85 -1
- claude_mpm/init.py +1 -1
- claude_mpm/scripts/claude-hook-handler.sh +36 -10
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -2
- claude_mpm/services/monitor/server.py +106 -16
- claude_mpm/services/pm_skills_deployer.py +259 -87
- claude_mpm/services/skills/git_skill_source_manager.py +51 -2
- claude_mpm/services/skills/selective_skill_deployer.py +114 -16
- claude_mpm/services/skills/skill_discovery_service.py +57 -3
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -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-management/SKILL.md +312 -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/{pm-teaching-mode → mpm-teaching-mode}/SKILL.md +2 -2
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/skill_manager.py +4 -4
- claude_mpm-5.6.1.dist-info/METADATA +391 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/RECORD +244 -145
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
- claude_mpm-5.4.85.dist-info/METADATA +0 -1023
- /claude_mpm/skills/bundled/pm/{pm-bug-reporting/pm-bug-reporting.md → mpm-bug-reporting/SKILL.md} +0 -0
- /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Commander command handler for CLI."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def handle_commander_command(args) -> int:
|
|
10
|
+
"""Handle the commander command.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
args: Parsed command line arguments with:
|
|
14
|
+
- port: Port for internal services (default: 8765)
|
|
15
|
+
- state_dir: Optional state directory path
|
|
16
|
+
- debug: Enable debug logging
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Exit code (0 for success, 1 for error)
|
|
20
|
+
"""
|
|
21
|
+
try:
|
|
22
|
+
# Import here to avoid circular dependencies
|
|
23
|
+
from claude_mpm.commander.chat.cli import run_commander
|
|
24
|
+
|
|
25
|
+
# Setup debug logging if requested
|
|
26
|
+
if getattr(args, "debug", False):
|
|
27
|
+
logging.basicConfig(
|
|
28
|
+
level=logging.DEBUG,
|
|
29
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Get arguments
|
|
33
|
+
port = getattr(args, "port", 8765)
|
|
34
|
+
state_dir = getattr(args, "state_dir", None)
|
|
35
|
+
|
|
36
|
+
# Run commander
|
|
37
|
+
asyncio.run(run_commander(port=port, state_dir=state_dir))
|
|
38
|
+
|
|
39
|
+
return 0
|
|
40
|
+
|
|
41
|
+
except KeyboardInterrupt:
|
|
42
|
+
logger.info("Commander interrupted by user")
|
|
43
|
+
return 0
|
|
44
|
+
except Exception as e:
|
|
45
|
+
logger.error(f"Commander error: {e}", exc_info=True)
|
|
46
|
+
return 1
|
|
@@ -57,33 +57,33 @@ def list_errors(format, hook_type):
|
|
|
57
57
|
|
|
58
58
|
if not errors:
|
|
59
59
|
if hook_type:
|
|
60
|
-
click.echo(f"No errors recorded for hook type: {hook_type}")
|
|
60
|
+
click.echo(f"No errors recorded for hook type: {hook_type}", err=True)
|
|
61
61
|
else:
|
|
62
|
-
click.echo("No errors recorded. Hook system is healthy! ✅")
|
|
62
|
+
click.echo("No errors recorded. Hook system is healthy! ✅", err=True)
|
|
63
63
|
return
|
|
64
64
|
|
|
65
65
|
if format == "json":
|
|
66
66
|
# JSON output
|
|
67
|
-
click.echo(json.dumps(errors, indent=2))
|
|
67
|
+
click.echo(json.dumps(errors, indent=2), err=True)
|
|
68
68
|
else:
|
|
69
69
|
# Table output
|
|
70
|
-
click.echo("\n" + "=" * 80)
|
|
71
|
-
click.echo("Hook Error Memory Report")
|
|
72
|
-
click.echo("=" * 80)
|
|
70
|
+
click.echo("\n" + "=" * 80, err=True)
|
|
71
|
+
click.echo("Hook Error Memory Report", err=True)
|
|
72
|
+
click.echo("=" * 80, err=True)
|
|
73
73
|
|
|
74
74
|
for key, data in errors.items():
|
|
75
|
-
click.echo(f"\n🔴 Error: {data['type']}")
|
|
76
|
-
click.echo(f" Hook Type: {data['hook_type']}")
|
|
77
|
-
click.echo(f" Details: {data['details']}")
|
|
78
|
-
click.echo(f" Match: {data['match']}")
|
|
79
|
-
click.echo(f" Count: {data['count']} occurrences")
|
|
80
|
-
click.echo(f" First Seen: {data['first_seen']}")
|
|
81
|
-
click.echo(f" Last Seen: {data['last_seen']}")
|
|
75
|
+
click.echo(f"\n🔴 Error: {data['type']}", err=True)
|
|
76
|
+
click.echo(f" Hook Type: {data['hook_type']}", err=True)
|
|
77
|
+
click.echo(f" Details: {data['details']}", err=True)
|
|
78
|
+
click.echo(f" Match: {data['match']}", err=True)
|
|
79
|
+
click.echo(f" Count: {data['count']} occurrences", err=True)
|
|
80
|
+
click.echo(f" First Seen: {data['first_seen']}", err=True)
|
|
81
|
+
click.echo(f" Last Seen: {data['last_seen']}", err=True)
|
|
82
82
|
|
|
83
|
-
click.echo("\n" + "=" * 80)
|
|
84
|
-
click.echo(f"Total unique errors: {len(errors)}")
|
|
85
|
-
click.echo(f"Memory file: {error_memory.memory_file}")
|
|
86
|
-
click.echo("\nTo clear errors: claude-mpm hook-errors clear")
|
|
83
|
+
click.echo("\n" + "=" * 80, err=True)
|
|
84
|
+
click.echo(f"Total unique errors: {len(errors)}", err=True)
|
|
85
|
+
click.echo(f"Memory file: {error_memory.memory_file}", err=True)
|
|
86
|
+
click.echo("\nTo clear errors: claude-mpm hook-errors clear", err=True)
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
@hook_errors_group.command(name="summary")
|
|
@@ -99,28 +99,28 @@ def show_summary():
|
|
|
99
99
|
summary = error_memory.get_error_summary()
|
|
100
100
|
|
|
101
101
|
if summary["total_errors"] == 0:
|
|
102
|
-
click.echo("No errors recorded. Hook system is healthy! ✅")
|
|
102
|
+
click.echo("No errors recorded. Hook system is healthy! ✅", err=True)
|
|
103
103
|
return
|
|
104
104
|
|
|
105
|
-
click.echo("\n" + "=" * 80)
|
|
106
|
-
click.echo("Hook Error Summary")
|
|
107
|
-
click.echo("=" * 80)
|
|
108
|
-
click.echo("\n📊 Statistics:")
|
|
109
|
-
click.echo(f" Total Errors: {summary['total_errors']}")
|
|
110
|
-
click.echo(f" Unique Errors: {summary['unique_errors']}")
|
|
105
|
+
click.echo("\n" + "=" * 80, err=True)
|
|
106
|
+
click.echo("Hook Error Summary", err=True)
|
|
107
|
+
click.echo("=" * 80, err=True)
|
|
108
|
+
click.echo("\n📊 Statistics:", err=True)
|
|
109
|
+
click.echo(f" Total Errors: {summary['total_errors']}", err=True)
|
|
110
|
+
click.echo(f" Unique Errors: {summary['unique_errors']}", err=True)
|
|
111
111
|
|
|
112
112
|
if summary["errors_by_type"]:
|
|
113
|
-
click.echo("\n🔍 Errors by Type:")
|
|
113
|
+
click.echo("\n🔍 Errors by Type:", err=True)
|
|
114
114
|
for error_type, count in summary["errors_by_type"].items():
|
|
115
|
-
click.echo(f" {error_type}: {count}")
|
|
115
|
+
click.echo(f" {error_type}: {count}", err=True)
|
|
116
116
|
|
|
117
117
|
if summary["errors_by_hook"]:
|
|
118
|
-
click.echo("\n🎣 Errors by Hook Type:")
|
|
118
|
+
click.echo("\n🎣 Errors by Hook Type:", err=True)
|
|
119
119
|
for hook_type, count in summary["errors_by_hook"].items():
|
|
120
|
-
click.echo(f" {hook_type}: {count}")
|
|
120
|
+
click.echo(f" {hook_type}: {count}", err=True)
|
|
121
121
|
|
|
122
|
-
click.echo(f"\n📁 Memory File: {summary['memory_file']}")
|
|
123
|
-
click.echo("\nFor detailed list: claude-mpm hook-errors list")
|
|
122
|
+
click.echo(f"\n📁 Memory File: {summary['memory_file']}", err=True)
|
|
123
|
+
click.echo("\nFor detailed list: claude-mpm hook-errors list", err=True)
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
@hook_errors_group.command(name="clear")
|
|
@@ -158,21 +158,21 @@ def clear_errors(hook_type, yes):
|
|
|
158
158
|
scope = "all hook types"
|
|
159
159
|
|
|
160
160
|
if count == 0:
|
|
161
|
-
click.echo(f"No errors to clear {scope}.")
|
|
161
|
+
click.echo(f"No errors to clear {scope}.", err=True)
|
|
162
162
|
return
|
|
163
163
|
|
|
164
164
|
# Confirm if not using -y flag
|
|
165
165
|
if not yes:
|
|
166
166
|
message = f"Clear {count} error(s) {scope}?"
|
|
167
167
|
if not click.confirm(message):
|
|
168
|
-
click.echo("Cancelled.")
|
|
168
|
+
click.echo("Cancelled.", err=True)
|
|
169
169
|
return
|
|
170
170
|
|
|
171
171
|
# Clear errors
|
|
172
172
|
error_memory.clear_errors(hook_type)
|
|
173
173
|
|
|
174
|
-
click.echo(f"✅ Cleared {count} error(s) {scope}.")
|
|
175
|
-
click.echo("\nHooks will be retried on next execution.")
|
|
174
|
+
click.echo(f"✅ Cleared {count} error(s) {scope}.", err=True)
|
|
175
|
+
click.echo("\nHooks will be retried on next execution.", err=True)
|
|
176
176
|
|
|
177
177
|
|
|
178
178
|
@hook_errors_group.command(name="diagnose")
|
|
@@ -201,19 +201,19 @@ def diagnose_errors(hook_type):
|
|
|
201
201
|
|
|
202
202
|
if not errors:
|
|
203
203
|
if hook_type:
|
|
204
|
-
click.echo(f"No errors to diagnose for hook type: {hook_type}")
|
|
204
|
+
click.echo(f"No errors to diagnose for hook type: {hook_type}", err=True)
|
|
205
205
|
else:
|
|
206
|
-
click.echo("No errors to diagnose. Hook system is healthy! ✅")
|
|
206
|
+
click.echo("No errors to diagnose. Hook system is healthy! ✅", err=True)
|
|
207
207
|
return
|
|
208
208
|
|
|
209
|
-
click.echo("\n" + "=" * 80)
|
|
210
|
-
click.echo("Hook Error Diagnostics")
|
|
211
|
-
click.echo("=" * 80)
|
|
209
|
+
click.echo("\n" + "=" * 80, err=True)
|
|
210
|
+
click.echo("Hook Error Diagnostics", err=True)
|
|
211
|
+
click.echo("=" * 80, err=True)
|
|
212
212
|
|
|
213
213
|
for key, data in errors.items():
|
|
214
|
-
click.echo(f"\n🔴 Error: {data['type']}")
|
|
215
|
-
click.echo(f" Hook: {data['hook_type']}")
|
|
216
|
-
click.echo(f" Count: {data['count']} failures")
|
|
214
|
+
click.echo(f"\n🔴 Error: {data['type']}", err=True)
|
|
215
|
+
click.echo(f" Hook: {data['hook_type']}", err=True)
|
|
216
|
+
click.echo(f" Count: {data['count']} failures", err=True)
|
|
217
217
|
|
|
218
218
|
# Generate and show fix suggestion
|
|
219
219
|
error_info = {
|
|
@@ -223,13 +223,13 @@ def diagnose_errors(hook_type):
|
|
|
223
223
|
}
|
|
224
224
|
suggestion = error_memory.suggest_fix(error_info)
|
|
225
225
|
|
|
226
|
-
click.echo("\n" + "-" * 80)
|
|
227
|
-
click.echo(suggestion)
|
|
228
|
-
click.echo("-" * 80)
|
|
226
|
+
click.echo("\n" + "-" * 80, err=True)
|
|
227
|
+
click.echo(suggestion, err=True)
|
|
228
|
+
click.echo("-" * 80, err=True)
|
|
229
229
|
|
|
230
|
-
click.echo("\n" + "=" * 80)
|
|
231
|
-
click.echo("After fixing issues, clear errors to retry:")
|
|
232
|
-
click.echo(" claude-mpm hook-errors clear")
|
|
230
|
+
click.echo("\n" + "=" * 80, err=True)
|
|
231
|
+
click.echo("After fixing issues, clear errors to retry:", err=True)
|
|
232
|
+
click.echo(" claude-mpm hook-errors clear", err=True)
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
@hook_errors_group.command(name="status")
|
|
@@ -244,27 +244,27 @@ def show_status():
|
|
|
244
244
|
error_memory = get_hook_error_memory()
|
|
245
245
|
summary = error_memory.get_error_summary()
|
|
246
246
|
|
|
247
|
-
click.echo("\n📊 Hook Error Memory Status")
|
|
248
|
-
click.echo("=" * 80)
|
|
247
|
+
click.echo("\n📊 Hook Error Memory Status", err=True)
|
|
248
|
+
click.echo("=" * 80, err=True)
|
|
249
249
|
|
|
250
250
|
if summary["total_errors"] == 0:
|
|
251
|
-
click.echo("✅ Status: Healthy (no errors recorded)")
|
|
251
|
+
click.echo("✅ Status: Healthy (no errors recorded)", err=True)
|
|
252
252
|
else:
|
|
253
|
-
click.echo(f"⚠️ Status: {summary['total_errors']} error(s) recorded")
|
|
254
|
-
click.echo(f" Unique errors: {summary['unique_errors']}")
|
|
253
|
+
click.echo(f"⚠️ Status: {summary['total_errors']} error(s) recorded", err=True)
|
|
254
|
+
click.echo(f" Unique errors: {summary['unique_errors']}", err=True)
|
|
255
255
|
|
|
256
256
|
# Show which hooks are affected
|
|
257
257
|
if summary["errors_by_hook"]:
|
|
258
258
|
affected_hooks = list(summary["errors_by_hook"].keys())
|
|
259
|
-
click.echo(f" Affected hooks: {', '.join(affected_hooks)}")
|
|
259
|
+
click.echo(f" Affected hooks: {', '.join(affected_hooks)}", err=True)
|
|
260
260
|
|
|
261
|
-
click.echo(f"\n📁 Memory file: {summary['memory_file']}")
|
|
262
|
-
click.echo(f" Exists: {Path(summary['memory_file']).exists()}")
|
|
261
|
+
click.echo(f"\n📁 Memory file: {summary['memory_file']}", err=True)
|
|
262
|
+
click.echo(f" Exists: {Path(summary['memory_file']).exists()}", err=True)
|
|
263
263
|
|
|
264
|
-
click.echo("\nCommands:")
|
|
265
|
-
click.echo(" claude-mpm hook-errors list # View detailed errors")
|
|
266
|
-
click.echo(" claude-mpm hook-errors diagnose # Get fix suggestions")
|
|
267
|
-
click.echo(" claude-mpm hook-errors clear # Clear and retry")
|
|
264
|
+
click.echo("\nCommands:", err=True)
|
|
265
|
+
click.echo(" claude-mpm hook-errors list # View detailed errors", err=True)
|
|
266
|
+
click.echo(" claude-mpm hook-errors diagnose # Get fix suggestions", err=True)
|
|
267
|
+
click.echo(" claude-mpm hook-errors clear # Clear and retry", err=True)
|
|
268
268
|
|
|
269
269
|
|
|
270
270
|
# Register the command group
|
|
@@ -118,7 +118,7 @@ class MonitorCommand(BaseCommand):
|
|
|
118
118
|
# Check if it's actually running
|
|
119
119
|
if not self.daemon.lifecycle.is_running():
|
|
120
120
|
return CommandResult.error_result(
|
|
121
|
-
"Monitor daemon failed to start. Check ~/.claude-mpm/monitor-daemon
|
|
121
|
+
"Monitor daemon failed to start. Check ~/.claude-mpm/logs/monitor-daemon-*.log for details."
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
# Get the actual PID
|
|
@@ -146,7 +146,7 @@ class MonitorCommand(BaseCommand):
|
|
|
146
146
|
pass
|
|
147
147
|
|
|
148
148
|
return CommandResult.error_result(
|
|
149
|
-
"Failed to start unified monitor daemon. Check ~/.claude-mpm/monitor-daemon
|
|
149
|
+
"Failed to start unified monitor daemon. Check ~/.claude-mpm/logs/monitor-daemon-*.log for details."
|
|
150
150
|
)
|
|
151
151
|
|
|
152
152
|
def _stop_monitor(self, args) -> CommandResult:
|
|
@@ -688,9 +688,9 @@ class MPMInitCommand:
|
|
|
688
688
|
return len(text) // 4
|
|
689
689
|
|
|
690
690
|
def _deploy_pm_skills(self) -> None:
|
|
691
|
-
"""Deploy PM skills templates to project .claude
|
|
691
|
+
"""Deploy PM skills templates to project .claude directory.
|
|
692
692
|
|
|
693
|
-
Copies PM skills from bundled templates to .claude
|
|
693
|
+
Copies PM skills from bundled templates to .claude/skills/
|
|
694
694
|
with version tracking and checksum validation.
|
|
695
695
|
"""
|
|
696
696
|
try:
|
claude_mpm/cli/commands/run.py
CHANGED
|
@@ -13,7 +13,7 @@ DESIGN DECISIONS:
|
|
|
13
13
|
- Support multiple output formats (json, yaml, table, text)
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
import subprocess
|
|
16
|
+
import subprocess # nosec B404 - required for process management
|
|
17
17
|
import sys
|
|
18
18
|
from datetime import datetime, timezone
|
|
19
19
|
from typing import Optional
|
|
@@ -489,6 +489,18 @@ class RunCommand(BaseCommand):
|
|
|
489
489
|
if hasattr(args, "claude_args") and args.claude_args:
|
|
490
490
|
claude_args.extend(args.claude_args)
|
|
491
491
|
|
|
492
|
+
# Add --resume if flag is set
|
|
493
|
+
if getattr(args, "resume", False) and "--resume" not in claude_args:
|
|
494
|
+
claude_args.insert(0, "--resume")
|
|
495
|
+
|
|
496
|
+
# Add --chrome if flag is set
|
|
497
|
+
if getattr(args, "chrome", False) and "--chrome" not in claude_args:
|
|
498
|
+
claude_args.insert(0, "--chrome")
|
|
499
|
+
|
|
500
|
+
# Add --no-chrome if flag is set
|
|
501
|
+
if getattr(args, "no_chrome", False) and "--no-chrome" not in claude_args:
|
|
502
|
+
claude_args.insert(0, "--no-chrome")
|
|
503
|
+
|
|
492
504
|
# Create runner
|
|
493
505
|
runner = ClaudeRunner(
|
|
494
506
|
enable_tickets=enable_tickets,
|
|
@@ -553,7 +565,7 @@ class RunCommand(BaseCommand):
|
|
|
553
565
|
wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
|
|
554
566
|
if wrapper_path.exists():
|
|
555
567
|
print("Starting interactive session with command interception...")
|
|
556
|
-
subprocess.run([sys.executable, str(wrapper_path)], check=False)
|
|
568
|
+
subprocess.run([sys.executable, str(wrapper_path)], check=False) # nosec B603 - trusted internal paths
|
|
557
569
|
else:
|
|
558
570
|
self.logger.warning(
|
|
559
571
|
"Interactive wrapper not found, falling back to normal mode"
|
|
@@ -907,6 +919,26 @@ def run_session_legacy(args):
|
|
|
907
919
|
else:
|
|
908
920
|
logger.info("[INFO]️ --resume already in claude_args")
|
|
909
921
|
|
|
922
|
+
# Add --chrome to claude_args if the flag is set
|
|
923
|
+
chrome_flag_present = getattr(args, "chrome", False)
|
|
924
|
+
if chrome_flag_present:
|
|
925
|
+
logger.info("📌 --chrome flag detected in args")
|
|
926
|
+
if "--chrome" not in raw_claude_args:
|
|
927
|
+
raw_claude_args = ["--chrome", *raw_claude_args]
|
|
928
|
+
logger.info("✅ Added --chrome to claude_args")
|
|
929
|
+
else:
|
|
930
|
+
logger.info("ℹ️ --chrome already in claude_args")
|
|
931
|
+
|
|
932
|
+
# Add --no-chrome to claude_args if the flag is set
|
|
933
|
+
no_chrome_flag_present = getattr(args, "no_chrome", False)
|
|
934
|
+
if no_chrome_flag_present:
|
|
935
|
+
logger.info("📌 --no-chrome flag detected in args")
|
|
936
|
+
if "--no-chrome" not in raw_claude_args:
|
|
937
|
+
raw_claude_args = ["--no-chrome", *raw_claude_args]
|
|
938
|
+
logger.info("✅ Added --no-chrome to claude_args")
|
|
939
|
+
else:
|
|
940
|
+
logger.info("ℹ️ --no-chrome already in claude_args")
|
|
941
|
+
|
|
910
942
|
# Filter out claude-mpm specific flags before passing to Claude CLI
|
|
911
943
|
logger.debug(f"Pre-filter claude_args: {raw_claude_args}")
|
|
912
944
|
claude_args = filter_claude_mpm_args(raw_claude_args)
|
|
@@ -1044,7 +1076,7 @@ def run_session_legacy(args):
|
|
|
1044
1076
|
wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
|
|
1045
1077
|
if wrapper_path.exists():
|
|
1046
1078
|
print("Starting interactive session with command interception...")
|
|
1047
|
-
subprocess.run([sys.executable, str(wrapper_path)], check=False)
|
|
1079
|
+
subprocess.run([sys.executable, str(wrapper_path)], check=False) # nosec B603 - trusted internal paths
|
|
1048
1080
|
else:
|
|
1049
1081
|
logger.warning("Interactive wrapper not found, falling back to normal mode")
|
|
1050
1082
|
runner.run_interactive(context)
|
claude_mpm/cli/executor.py
CHANGED
|
@@ -127,6 +127,14 @@ def execute_command(command: str, args) -> int:
|
|
|
127
127
|
result = handle_verify(args)
|
|
128
128
|
return result if result is not None else 0
|
|
129
129
|
|
|
130
|
+
# Handle commander command with lazy import
|
|
131
|
+
if command == "commander":
|
|
132
|
+
# Lazy import to avoid loading unless needed
|
|
133
|
+
from .commands.commander import handle_commander_command
|
|
134
|
+
|
|
135
|
+
result = handle_commander_command(args)
|
|
136
|
+
return result if result is not None else 0
|
|
137
|
+
|
|
130
138
|
# Handle skill-source command with lazy import
|
|
131
139
|
if command == "skill-source":
|
|
132
140
|
# Lazy import to avoid loading unless needed
|
|
@@ -206,35 +214,127 @@ def execute_command(command: str, args) -> int:
|
|
|
206
214
|
"status": show_status,
|
|
207
215
|
}
|
|
208
216
|
|
|
209
|
-
# Get handler and
|
|
217
|
+
# Get handler and call it with argument list (same pattern as autotodos)
|
|
210
218
|
handler = handlers.get(subcommand)
|
|
211
219
|
if handler:
|
|
212
|
-
|
|
213
|
-
|
|
220
|
+
try:
|
|
221
|
+
# Build argument list for Click command based on subcommand
|
|
222
|
+
click_args = []
|
|
223
|
+
|
|
224
|
+
# list command: --format, --hook-type
|
|
225
|
+
if subcommand == "list":
|
|
226
|
+
if hasattr(args, "format") and args.format:
|
|
227
|
+
click_args.extend(["--format", args.format])
|
|
228
|
+
if hasattr(args, "hook_type") and args.hook_type:
|
|
229
|
+
click_args.extend(["--hook-type", args.hook_type])
|
|
230
|
+
# clear command: --hook-type, -y
|
|
231
|
+
elif subcommand == "clear":
|
|
232
|
+
if hasattr(args, "hook_type") and args.hook_type:
|
|
233
|
+
click_args.extend(["--hook-type", args.hook_type])
|
|
234
|
+
if hasattr(args, "yes") and args.yes:
|
|
235
|
+
click_args.append("-y")
|
|
236
|
+
# diagnose command: hook_type (positional argument)
|
|
237
|
+
elif subcommand == "diagnose":
|
|
238
|
+
if hasattr(args, "hook_type") and args.hook_type:
|
|
239
|
+
click_args.append(args.hook_type)
|
|
240
|
+
# status and summary commands: no options
|
|
241
|
+
|
|
242
|
+
# Call Click command with argument list and standalone_mode=False
|
|
243
|
+
handler(click_args, standalone_mode=False)
|
|
244
|
+
return 0
|
|
245
|
+
except SystemExit as e:
|
|
246
|
+
return e.code if e.code is not None else 0
|
|
247
|
+
except Exception as e:
|
|
248
|
+
print(f"Error: {e}")
|
|
249
|
+
return 1
|
|
250
|
+
else:
|
|
251
|
+
print(f"Unknown hook-errors subcommand: {subcommand}")
|
|
252
|
+
return 1
|
|
214
253
|
|
|
215
|
-
|
|
254
|
+
# Handle autotodos command with lazy import
|
|
255
|
+
if command == "autotodos":
|
|
256
|
+
# Lazy import to avoid loading unless needed
|
|
257
|
+
from .commands.autotodos import (
|
|
258
|
+
clear_autotodos,
|
|
259
|
+
inject_autotodos,
|
|
260
|
+
list_autotodos,
|
|
261
|
+
list_pm_violations,
|
|
262
|
+
scan_delegation_patterns,
|
|
263
|
+
show_autotodos_status,
|
|
264
|
+
)
|
|
216
265
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if hasattr(args, "hook_type"):
|
|
222
|
-
kwargs["hook_type"] = args.hook_type
|
|
223
|
-
if hasattr(args, "yes"):
|
|
224
|
-
kwargs["yes"] = args.yes
|
|
266
|
+
# Get subcommand
|
|
267
|
+
subcommand = getattr(args, "autotodos_command", "status")
|
|
268
|
+
if not subcommand:
|
|
269
|
+
subcommand = "status"
|
|
225
270
|
|
|
271
|
+
# Map subcommands to functions
|
|
272
|
+
handlers = {
|
|
273
|
+
"list": list_autotodos,
|
|
274
|
+
"inject": inject_autotodos,
|
|
275
|
+
"clear": clear_autotodos,
|
|
276
|
+
"status": show_autotodos_status,
|
|
277
|
+
"scan": scan_delegation_patterns,
|
|
278
|
+
"violations": list_pm_violations,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
# Get handler and call it with standalone_mode=False
|
|
282
|
+
handler = handlers.get(subcommand)
|
|
283
|
+
if handler:
|
|
226
284
|
try:
|
|
227
|
-
#
|
|
228
|
-
|
|
229
|
-
|
|
285
|
+
# Build argument list for Click command
|
|
286
|
+
click_args = []
|
|
287
|
+
|
|
288
|
+
if subcommand == "list":
|
|
289
|
+
fmt = getattr(args, "format", "table")
|
|
290
|
+
click_args = ["--format", fmt]
|
|
291
|
+
elif subcommand == "inject":
|
|
292
|
+
output = getattr(args, "output", None)
|
|
293
|
+
if output:
|
|
294
|
+
click_args = ["--output", output]
|
|
295
|
+
elif subcommand == "clear":
|
|
296
|
+
error_key = getattr(args, "error_key", None)
|
|
297
|
+
event_type = getattr(args, "event_type", "all")
|
|
298
|
+
if error_key:
|
|
299
|
+
click_args.append("--error-key")
|
|
300
|
+
click_args.append(error_key)
|
|
301
|
+
if event_type != "all":
|
|
302
|
+
click_args.append("--event-type")
|
|
303
|
+
click_args.append(event_type)
|
|
304
|
+
if getattr(args, "yes", False):
|
|
305
|
+
click_args.append("-y")
|
|
306
|
+
elif subcommand == "scan":
|
|
307
|
+
text = getattr(args, "text", None)
|
|
308
|
+
file = getattr(args, "file", None)
|
|
309
|
+
fmt = getattr(args, "format", "table")
|
|
310
|
+
save = getattr(args, "save", False)
|
|
311
|
+
|
|
312
|
+
if text:
|
|
313
|
+
click_args.append(text)
|
|
314
|
+
if file:
|
|
315
|
+
click_args.extend(["--file", file])
|
|
316
|
+
if fmt != "table":
|
|
317
|
+
click_args.extend(["--format", fmt])
|
|
318
|
+
if save:
|
|
319
|
+
click_args.append("--save")
|
|
320
|
+
elif subcommand == "violations":
|
|
321
|
+
fmt = getattr(args, "format", "table")
|
|
322
|
+
if fmt != "table":
|
|
323
|
+
click_args.extend(["--format", fmt])
|
|
324
|
+
|
|
325
|
+
# Call Click command with argument list and standalone_mode=False
|
|
326
|
+
handler(click_args, standalone_mode=False)
|
|
230
327
|
return 0
|
|
231
328
|
except SystemExit as e:
|
|
232
329
|
return e.code if e.code is not None else 0
|
|
233
330
|
except Exception as e:
|
|
234
331
|
print(f"Error: {e}")
|
|
332
|
+
import traceback
|
|
333
|
+
|
|
334
|
+
traceback.print_exc()
|
|
235
335
|
return 1
|
|
236
336
|
else:
|
|
237
|
-
print(f"Unknown
|
|
337
|
+
print(f"Unknown autotodos subcommand: {subcommand}")
|
|
238
338
|
return 1
|
|
239
339
|
|
|
240
340
|
# Map stable commands to their implementations
|
|
@@ -260,6 +360,7 @@ def execute_command(command: str, args) -> int:
|
|
|
260
360
|
CLICommands.SKILLS.value: manage_skills,
|
|
261
361
|
"debug": manage_debug, # Add debug command
|
|
262
362
|
"mpm-init": None, # Will be handled separately with lazy import
|
|
363
|
+
"commander": None, # Will be handled separately with lazy import
|
|
263
364
|
}
|
|
264
365
|
|
|
265
366
|
# Execute command if found
|
|
@@ -287,6 +388,8 @@ def execute_command(command: str, args) -> int:
|
|
|
287
388
|
"local-deploy",
|
|
288
389
|
"skill-source",
|
|
289
390
|
"agent-source",
|
|
391
|
+
"hook-errors",
|
|
392
|
+
"autotodos",
|
|
290
393
|
]
|
|
291
394
|
|
|
292
395
|
suggestion = suggest_similar_commands(command, all_commands)
|
|
@@ -125,7 +125,7 @@ def _get_enhanced_version(base_version: str) -> str:
|
|
|
125
125
|
|
|
126
126
|
if enhanced and enhanced != base_version:
|
|
127
127
|
return enhanced
|
|
128
|
-
except Exception:
|
|
128
|
+
except Exception: # nosec B110
|
|
129
129
|
# If anything fails, fall back to base version
|
|
130
130
|
pass
|
|
131
131
|
|
|
@@ -297,6 +297,16 @@ def add_top_level_run_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
297
297
|
action="store_true",
|
|
298
298
|
help="Force refresh agents and skills from remote repos, bypassing ETag cache",
|
|
299
299
|
)
|
|
300
|
+
run_group.add_argument(
|
|
301
|
+
"--chrome",
|
|
302
|
+
action="store_true",
|
|
303
|
+
help="Enable Claude in Chrome integration (passed to Claude Code)",
|
|
304
|
+
)
|
|
305
|
+
run_group.add_argument(
|
|
306
|
+
"--no-chrome",
|
|
307
|
+
action="store_true",
|
|
308
|
+
help="Disable Claude in Chrome integration (passed to Claude Code)",
|
|
309
|
+
)
|
|
300
310
|
|
|
301
311
|
# Dependency checking options (for backward compatibility at top level)
|
|
302
312
|
dep_group_top = parser.add_argument_group(
|
|
@@ -492,6 +502,13 @@ def create_parser(
|
|
|
492
502
|
except ImportError:
|
|
493
503
|
pass
|
|
494
504
|
|
|
505
|
+
try:
|
|
506
|
+
from .commander_parser import add_commander_subparser
|
|
507
|
+
|
|
508
|
+
add_commander_subparser(subparsers)
|
|
509
|
+
except ImportError:
|
|
510
|
+
pass
|
|
511
|
+
|
|
495
512
|
# Add uninstall command parser
|
|
496
513
|
try:
|
|
497
514
|
from ..commands.uninstall import add_uninstall_parser
|
|
@@ -607,6 +624,59 @@ def create_parser(
|
|
|
607
624
|
help="Skip confirmation prompts",
|
|
608
625
|
)
|
|
609
626
|
|
|
627
|
+
# Add autotodos command for auto-generating todos from hook errors
|
|
628
|
+
autotodos_parser = subparsers.add_parser(
|
|
629
|
+
"autotodos",
|
|
630
|
+
help="Auto-generate todos from hook errors and delegation patterns",
|
|
631
|
+
)
|
|
632
|
+
autotodos_parser.add_argument(
|
|
633
|
+
"autotodos_command",
|
|
634
|
+
nargs="?",
|
|
635
|
+
choices=["list", "inject", "clear", "status", "scan", "violations"],
|
|
636
|
+
help="AutoTodos subcommand",
|
|
637
|
+
)
|
|
638
|
+
autotodos_parser.add_argument(
|
|
639
|
+
"text",
|
|
640
|
+
nargs="?",
|
|
641
|
+
help="Text to scan for delegation patterns (scan command only)",
|
|
642
|
+
)
|
|
643
|
+
autotodos_parser.add_argument(
|
|
644
|
+
"--format",
|
|
645
|
+
choices=["table", "json"],
|
|
646
|
+
default="table",
|
|
647
|
+
help="Output format for list/scan commands",
|
|
648
|
+
)
|
|
649
|
+
autotodos_parser.add_argument(
|
|
650
|
+
"--output",
|
|
651
|
+
help="Output file path for inject command",
|
|
652
|
+
)
|
|
653
|
+
autotodos_parser.add_argument(
|
|
654
|
+
"--error-key",
|
|
655
|
+
help="Specific error key to clear",
|
|
656
|
+
)
|
|
657
|
+
autotodos_parser.add_argument(
|
|
658
|
+
"--event-type",
|
|
659
|
+
choices=["error", "violation", "all"],
|
|
660
|
+
default="all",
|
|
661
|
+
help="Type of events to clear (clear command only)",
|
|
662
|
+
)
|
|
663
|
+
autotodos_parser.add_argument(
|
|
664
|
+
"--file",
|
|
665
|
+
"-f",
|
|
666
|
+
help="Scan text from file (scan command only)",
|
|
667
|
+
)
|
|
668
|
+
autotodos_parser.add_argument(
|
|
669
|
+
"--save",
|
|
670
|
+
action="store_true",
|
|
671
|
+
help="Save detections to event log (scan command only)",
|
|
672
|
+
)
|
|
673
|
+
autotodos_parser.add_argument(
|
|
674
|
+
"-y",
|
|
675
|
+
"--yes",
|
|
676
|
+
action="store_true",
|
|
677
|
+
help="Skip confirmation prompts",
|
|
678
|
+
)
|
|
679
|
+
|
|
610
680
|
# Add summarize command
|
|
611
681
|
from ..commands.summarize import add_summarize_parser
|
|
612
682
|
|