claude-mpm 5.0.9__py3-none-any.whl → 5.6.23__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/__init__.py +4 -0
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +115 -0
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +479 -616
- claude_mpm/agents/WORKFLOW.md +6 -253
- claude_mpm/agents/agent_loader.py +13 -44
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +70 -2
- claude_mpm/agents/templates/circuit-breakers.md +457 -62
- claude_mpm/cli/__init__.py +5 -2
- claude_mpm/cli/__main__.py +4 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/agent_state_manager.py +18 -27
- claude_mpm/cli/commands/agents.py +177 -41
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/auto_configure.py +723 -236
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/config.py +88 -2
- claude_mpm/cli/commands/configure.py +1874 -170
- claude_mpm/cli/commands/configure_agent_display.py +27 -6
- 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 +232 -46
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/profile.py +276 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +379 -204
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +141 -19
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +115 -60
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/agents_parser.py +54 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
- claude_mpm/cli/parsers/base_parser.py +88 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/config_parser.py +153 -83
- claude_mpm/cli/parsers/profile_parser.py +147 -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 +1 -1
- claude_mpm/cli/startup.py +1017 -266
- claude_mpm/cli/startup_display.py +74 -6
- claude_mpm/cli/startup_logging.py +2 -2
- 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 +146 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +51 -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 +603 -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 +146 -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 +450 -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 +36 -0
- claude_mpm/commands/mpm-doctor.md +16 -21
- claude_mpm/commands/mpm-help.md +12 -286
- claude_mpm/commands/mpm-init.md +88 -506
- claude_mpm/commands/mpm-monitor.md +22 -401
- claude_mpm/commands/mpm-organize.md +128 -0
- claude_mpm/commands/mpm-postmortem.md +13 -107
- claude_mpm/commands/mpm-session-resume.md +20 -363
- claude_mpm/commands/mpm-status.md +13 -69
- claude_mpm/commands/mpm-ticket-view.md +60 -495
- claude_mpm/commands/mpm-version.md +13 -107
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +37 -26
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/framework/formatters/content_formatter.py +3 -13
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/framework_loader.py +4 -2
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +39 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +61 -0
- claude_mpm/core/output_style_manager.py +219 -44
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +16 -8
- claude_mpm/core/unified_agent_registry.py +134 -16
- claude_mpm/core/unified_config.py +76 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- 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/1WZnGYqX.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
- 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/C3rbW_a-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
- 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 -0
- claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
- claude_mpm/dashboard/static/svelte-build/index.html +36 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- 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/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +479 -128
- claude_mpm/hooks/claude_hooks/hook_handler.py +254 -83
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +149 -18
- claude_mpm/hooks/claude_hooks/memory_integration.py +67 -19
- claude_mpm/hooks/claude_hooks/response_tracking.py +44 -62
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.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__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +69 -30
- 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 +73 -75
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/memory_integration_hook.py +46 -1
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/init.py +276 -19
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +87 -20
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/agent_recommendation_service.py +278 -0
- claude_mpm/services/agents/agent_review_service.py +280 -0
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +7 -7
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +6 -5
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +42 -20
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +348 -29
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +570 -68
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +57 -4
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
- claude_mpm/services/agents/sources/git_source_sync_service.py +129 -11
- claude_mpm/services/agents/startup_sync.py +27 -4
- claude_mpm/services/agents/toolchain_detector.py +10 -6
- claude_mpm/services/analysis/__init__.py +11 -1
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- 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/command_deployment_service.py +81 -10
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
- 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_bus/config.py +3 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/git/git_operations_service.py +101 -16
- 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.py +9 -2
- claude_mpm/services/monitor/daemon_manager.py +54 -7
- claude_mpm/services/monitor/management/lifecycle.py +15 -3
- claude_mpm/services/monitor/server.py +796 -30
- claude_mpm/services/pm_skills_deployer.py +884 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/self_upgrade_service.py +120 -12
- claude_mpm/services/skills/__init__.py +3 -0
- claude_mpm/services/skills/git_skill_source_manager.py +303 -12
- claude_mpm/services/skills/selective_skill_deployer.py +869 -0
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
- claude_mpm/services/skills_deployer.py +294 -55
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +51 -6
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/core.py +386 -108
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- 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-bug-reporting/SKILL.md +248 -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-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -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-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -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-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +98 -3
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +115 -4
- claude_mpm/utils/agent_filters.py +17 -44
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +86 -21
- claude_mpm-5.6.23.dist-info/METADATA +393 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +508 -261
- claude_mpm-5.6.23.dist-info/entry_points.txt +5 -0
- claude_mpm-5.6.23.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.6.23.dist-info/licenses/LICENSE-FAQ.md +153 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
- claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
- claude_mpm/agents/BASE_OPS.md +0 -219
- claude_mpm/agents/BASE_PM.md +0 -480
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
- claude_mpm/agents/BASE_QA.md +0 -167
- claude_mpm/agents/BASE_RESEARCH.md +0 -53
- claude_mpm/agents/OUTPUT_STYLE.md +0 -290
- claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +0 -1322
- claude_mpm/agents/base_agent_loader.py +0 -601
- claude_mpm/cli/commands/agents_detect.py +0 -380
- claude_mpm/cli/commands/agents_recommend.py +0 -309
- claude_mpm/cli/ticket_cli.py +0 -35
- claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
- claude_mpm/commands/mpm-agents-detect.md +0 -177
- claude_mpm/commands/mpm-agents-list.md +0 -131
- claude_mpm/commands/mpm-agents-recommend.md +0 -223
- claude_mpm/commands/mpm-config-view.md +0 -150
- claude_mpm/commands/mpm-ticket-organize.md +0 -304
- claude_mpm/dashboard/analysis_runner.py +0 -455
- claude_mpm/dashboard/index.html +0 -13
- claude_mpm/dashboard/open_dashboard.py +0 -66
- claude_mpm/dashboard/static/css/activity.css +0 -1958
- claude_mpm/dashboard/static/css/connection-status.css +0 -370
- claude_mpm/dashboard/static/css/dashboard.css +0 -4701
- claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
- claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
- claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
- claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
- claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
- claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
- claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
- claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
- claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
- claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
- claude_mpm/dashboard/static/js/connection-manager.js +0 -536
- claude_mpm/dashboard/static/js/dashboard.js +0 -1914
- claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/js/socket-client.js +0 -1474
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/socket.io.min.js +0 -7
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
- claude_mpm/dashboard/templates/code_simple.html +0 -153
- claude_mpm/dashboard/templates/index.html +0 -606
- claude_mpm/dashboard/test_dashboard.html +0 -372
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/scripts/mcp_server.py +0 -75
- claude_mpm/scripts/mcp_wrapper.py +0 -39
- claude_mpm/services/mcp_gateway/__init__.py +0 -159
- claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
- claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
- claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
- claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
- claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
- claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
- claude_mpm/services/mcp_gateway/core/base.py +0 -312
- claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
- claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
- claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
- claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
- claude_mpm/services/mcp_gateway/main.py +0 -589
- claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
- claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
- claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
- claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
- claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
- claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
- claude_mpm-5.0.9.dist-info/METADATA +0 -1028
- claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
- claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
# Real-World TDD Examples
|
|
2
|
+
|
|
3
|
+
> **Part of**: [Test-Driven Development](../SKILL.md)
|
|
4
|
+
> **Category**: testing
|
|
5
|
+
> **Reading Level**: Intermediate
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
Real-world scenarios demonstrating test-driven development in action, with complete RED/GREEN/REFACTOR cycles and step-by-step walkthroughs.
|
|
10
|
+
|
|
11
|
+
## Example 1: Form Validation
|
|
12
|
+
|
|
13
|
+
### Scenario
|
|
14
|
+
Build email validation for user registration form.
|
|
15
|
+
|
|
16
|
+
### Iteration 1: Basic Email Validation
|
|
17
|
+
|
|
18
|
+
**RED - Write Failing Test:**
|
|
19
|
+
```typescript
|
|
20
|
+
describe('Email Validation', () => {
|
|
21
|
+
test('accepts valid email format', () => {
|
|
22
|
+
const result = validateEmail('user@example.com');
|
|
23
|
+
expect(result.valid).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**VERIFY RED - Run Test:**
|
|
29
|
+
```bash
|
|
30
|
+
$ npm test
|
|
31
|
+
FAIL: accepts valid email format
|
|
32
|
+
ReferenceError: validateEmail is not defined
|
|
33
|
+
```
|
|
34
|
+
✓ Fails correctly - function doesn't exist
|
|
35
|
+
|
|
36
|
+
**GREEN - Minimal Implementation:**
|
|
37
|
+
```typescript
|
|
38
|
+
interface ValidationResult {
|
|
39
|
+
valid: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function validateEmail(email: string): ValidationResult {
|
|
44
|
+
return { valid: true }; // Simplest thing that passes
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**VERIFY GREEN - Run Test:**
|
|
49
|
+
```bash
|
|
50
|
+
$ npm test
|
|
51
|
+
PASS: accepts valid email format
|
|
52
|
+
```
|
|
53
|
+
✓ Test passes
|
|
54
|
+
|
|
55
|
+
### Iteration 2: Reject Invalid Format
|
|
56
|
+
|
|
57
|
+
**RED:**
|
|
58
|
+
```typescript
|
|
59
|
+
test('rejects email without @ symbol', () => {
|
|
60
|
+
const result = validateEmail('userexample.com');
|
|
61
|
+
expect(result.valid).toBe(false);
|
|
62
|
+
expect(result.error).toBe('Invalid email format');
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**VERIFY RED:**
|
|
67
|
+
```bash
|
|
68
|
+
$ npm test
|
|
69
|
+
FAIL: rejects email without @ symbol
|
|
70
|
+
Expected valid: false, Received: true
|
|
71
|
+
```
|
|
72
|
+
✓ Fails correctly
|
|
73
|
+
|
|
74
|
+
**GREEN:**
|
|
75
|
+
```typescript
|
|
76
|
+
function validateEmail(email: string): ValidationResult {
|
|
77
|
+
if (!email.includes('@')) {
|
|
78
|
+
return { valid: false, error: 'Invalid email format' };
|
|
79
|
+
}
|
|
80
|
+
return { valid: true };
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**VERIFY GREEN:**
|
|
85
|
+
```bash
|
|
86
|
+
$ npm test
|
|
87
|
+
PASS: accepts valid email format
|
|
88
|
+
PASS: rejects email without @ symbol
|
|
89
|
+
```
|
|
90
|
+
✓ Both tests pass
|
|
91
|
+
|
|
92
|
+
### Iteration 3: Reject Multiple @ Symbols
|
|
93
|
+
|
|
94
|
+
**RED:**
|
|
95
|
+
```typescript
|
|
96
|
+
test('rejects email with multiple @ symbols', () => {
|
|
97
|
+
const result = validateEmail('user@@example.com');
|
|
98
|
+
expect(result.valid).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**GREEN:**
|
|
103
|
+
```typescript
|
|
104
|
+
function validateEmail(email: string): ValidationResult {
|
|
105
|
+
if (!email.includes('@')) {
|
|
106
|
+
return { valid: false, error: 'Invalid email format' };
|
|
107
|
+
}
|
|
108
|
+
if (email.indexOf('@') !== email.lastIndexOf('@')) {
|
|
109
|
+
return { valid: false, error: 'Invalid email format' };
|
|
110
|
+
}
|
|
111
|
+
return { valid: true };
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**REFACTOR - Clean Up:**
|
|
116
|
+
```typescript
|
|
117
|
+
function validateEmail(email: string): ValidationResult {
|
|
118
|
+
const hasAtSymbol = email.includes('@');
|
|
119
|
+
const hasSingleAtSymbol = email.indexOf('@') === email.lastIndexOf('@');
|
|
120
|
+
|
|
121
|
+
if (!hasAtSymbol || !hasSingleAtSymbol) {
|
|
122
|
+
return { valid: false, error: 'Invalid email format' };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { valid: true };
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Time:** 15 minutes, 3 tests, working validation
|
|
130
|
+
|
|
131
|
+
## Example 2: Bug Fix with TDD
|
|
132
|
+
|
|
133
|
+
### Scenario
|
|
134
|
+
Bug reported: Empty shopping cart shows "$0" instead of "Cart is empty" message.
|
|
135
|
+
|
|
136
|
+
### Step 1: Reproduce with Test
|
|
137
|
+
|
|
138
|
+
**RED - Failing Test:**
|
|
139
|
+
```typescript
|
|
140
|
+
describe('Shopping Cart Display', () => {
|
|
141
|
+
test('shows empty message when cart has no items', () => {
|
|
142
|
+
const cart = new ShoppingCart();
|
|
143
|
+
const display = cart.getDisplayMessage();
|
|
144
|
+
expect(display).toBe('Cart is empty');
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**VERIFY RED:**
|
|
150
|
+
```bash
|
|
151
|
+
$ npm test
|
|
152
|
+
FAIL: shows empty message when cart has no items
|
|
153
|
+
Expected: 'Cart is empty'
|
|
154
|
+
Received: 'Total: $0'
|
|
155
|
+
```
|
|
156
|
+
✓ Test reproduces the bug
|
|
157
|
+
|
|
158
|
+
### Step 2: Fix with Minimal Change
|
|
159
|
+
|
|
160
|
+
**GREEN:**
|
|
161
|
+
```typescript
|
|
162
|
+
class ShoppingCart {
|
|
163
|
+
private items: Item[] = [];
|
|
164
|
+
|
|
165
|
+
getDisplayMessage(): string {
|
|
166
|
+
if (this.items.length === 0) {
|
|
167
|
+
return 'Cart is empty';
|
|
168
|
+
}
|
|
169
|
+
return `Total: $${this.getTotal()}`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getTotal(): number {
|
|
173
|
+
return this.items.reduce((sum, item) => sum + item.price, 0);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**VERIFY GREEN:**
|
|
179
|
+
```bash
|
|
180
|
+
$ npm test
|
|
181
|
+
PASS: shows empty message when cart has no items
|
|
182
|
+
PASS: calculates total correctly (existing test)
|
|
183
|
+
```
|
|
184
|
+
✓ Bug fixed, no regressions
|
|
185
|
+
|
|
186
|
+
### Step 3: Prevent Regression
|
|
187
|
+
|
|
188
|
+
Test stays in suite permanently - bug can never return without test failing.
|
|
189
|
+
|
|
190
|
+
**Time:** 10 minutes, bug fixed with regression protection
|
|
191
|
+
|
|
192
|
+
## Example 3: API Client Development
|
|
193
|
+
|
|
194
|
+
### Scenario
|
|
195
|
+
Build HTTP client with retry logic for failed requests.
|
|
196
|
+
|
|
197
|
+
### Iteration 1: Basic Request
|
|
198
|
+
|
|
199
|
+
**RED:**
|
|
200
|
+
```typescript
|
|
201
|
+
describe('HTTP Client', () => {
|
|
202
|
+
test('makes GET request successfully', async () => {
|
|
203
|
+
const client = new HttpClient('https://api.example.com');
|
|
204
|
+
const response = await client.get('/users/1');
|
|
205
|
+
expect(response.status).toBe(200);
|
|
206
|
+
expect(response.data).toBeDefined();
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**GREEN:**
|
|
212
|
+
```typescript
|
|
213
|
+
class HttpClient {
|
|
214
|
+
constructor(private baseUrl: string) {}
|
|
215
|
+
|
|
216
|
+
async get(path: string): Promise<Response> {
|
|
217
|
+
const res = await fetch(`${this.baseUrl}${path}`);
|
|
218
|
+
return {
|
|
219
|
+
status: res.status,
|
|
220
|
+
data: await res.json()
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Iteration 2: Handle Network Errors
|
|
227
|
+
|
|
228
|
+
**RED:**
|
|
229
|
+
```typescript
|
|
230
|
+
test('retries on network error', async () => {
|
|
231
|
+
const client = new HttpClient('https://api.example.com');
|
|
232
|
+
|
|
233
|
+
// Mock fetch to fail once then succeed
|
|
234
|
+
let attempts = 0;
|
|
235
|
+
global.fetch = jest.fn().mockImplementation(() => {
|
|
236
|
+
attempts++;
|
|
237
|
+
if (attempts === 1) {
|
|
238
|
+
throw new Error('Network error');
|
|
239
|
+
}
|
|
240
|
+
return Promise.resolve({
|
|
241
|
+
status: 200,
|
|
242
|
+
json: () => Promise.resolve({ id: 1 })
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const response = await client.get('/users/1');
|
|
247
|
+
|
|
248
|
+
expect(response.status).toBe(200);
|
|
249
|
+
expect(attempts).toBe(2);
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**GREEN:**
|
|
254
|
+
```typescript
|
|
255
|
+
class HttpClient {
|
|
256
|
+
constructor(private baseUrl: string) {}
|
|
257
|
+
|
|
258
|
+
async get(path: string): Promise<Response> {
|
|
259
|
+
try {
|
|
260
|
+
return await this.makeRequest(path);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
// Retry once
|
|
263
|
+
return await this.makeRequest(path);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private async makeRequest(path: string): Promise<Response> {
|
|
268
|
+
const res = await fetch(`${this.baseUrl}${path}`);
|
|
269
|
+
return {
|
|
270
|
+
status: res.status,
|
|
271
|
+
data: await res.json()
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Iteration 3: Configurable Retries
|
|
278
|
+
|
|
279
|
+
**RED:**
|
|
280
|
+
```typescript
|
|
281
|
+
test('retries up to max attempts', async () => {
|
|
282
|
+
const client = new HttpClient('https://api.example.com', {
|
|
283
|
+
maxRetries: 3
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
let attempts = 0;
|
|
287
|
+
global.fetch = jest.fn().mockImplementation(() => {
|
|
288
|
+
attempts++;
|
|
289
|
+
if (attempts < 3) {
|
|
290
|
+
throw new Error('Network error');
|
|
291
|
+
}
|
|
292
|
+
return Promise.resolve({
|
|
293
|
+
status: 200,
|
|
294
|
+
json: () => Promise.resolve({ id: 1 })
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const response = await client.get('/users/1');
|
|
299
|
+
|
|
300
|
+
expect(response.status).toBe(200);
|
|
301
|
+
expect(attempts).toBe(3);
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**GREEN:**
|
|
306
|
+
```typescript
|
|
307
|
+
interface HttpClientOptions {
|
|
308
|
+
maxRetries?: number;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
class HttpClient {
|
|
312
|
+
private maxRetries: number;
|
|
313
|
+
|
|
314
|
+
constructor(
|
|
315
|
+
private baseUrl: string,
|
|
316
|
+
options: HttpClientOptions = {}
|
|
317
|
+
) {
|
|
318
|
+
this.maxRetries = options.maxRetries ?? 1;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async get(path: string): Promise<Response> {
|
|
322
|
+
let lastError: Error;
|
|
323
|
+
|
|
324
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
325
|
+
try {
|
|
326
|
+
return await this.makeRequest(path);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
lastError = error as Error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
throw lastError!;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private async makeRequest(path: string): Promise<Response> {
|
|
336
|
+
const res = await fetch(`${this.baseUrl}${path}`);
|
|
337
|
+
return {
|
|
338
|
+
status: res.status,
|
|
339
|
+
data: await res.json()
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**REFACTOR:**
|
|
346
|
+
```typescript
|
|
347
|
+
// Extract retry logic to utility
|
|
348
|
+
async function withRetry<T>(
|
|
349
|
+
fn: () => Promise<T>,
|
|
350
|
+
maxRetries: number
|
|
351
|
+
): Promise<T> {
|
|
352
|
+
let lastError: Error;
|
|
353
|
+
|
|
354
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
355
|
+
try {
|
|
356
|
+
return await fn();
|
|
357
|
+
} catch (error) {
|
|
358
|
+
lastError = error as Error;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
throw lastError!;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
class HttpClient {
|
|
366
|
+
constructor(
|
|
367
|
+
private baseUrl: string,
|
|
368
|
+
private options: HttpClientOptions = {}
|
|
369
|
+
) {}
|
|
370
|
+
|
|
371
|
+
async get(path: string): Promise<Response> {
|
|
372
|
+
return withRetry(
|
|
373
|
+
() => this.makeRequest(path),
|
|
374
|
+
this.options.maxRetries ?? 1
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private async makeRequest(path: string): Promise<Response> {
|
|
379
|
+
const res = await fetch(`${this.baseUrl}${path}`);
|
|
380
|
+
return {
|
|
381
|
+
status: res.status,
|
|
382
|
+
data: await res.json()
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Time:** 30 minutes, robust HTTP client with retry logic
|
|
389
|
+
|
|
390
|
+
## Example 4: Refactoring with Test Protection
|
|
391
|
+
|
|
392
|
+
### Scenario
|
|
393
|
+
Legacy code needs refactoring - extract business logic from controller.
|
|
394
|
+
|
|
395
|
+
### Step 1: Write Tests for Current Behavior
|
|
396
|
+
|
|
397
|
+
**RED (characterization tests):**
|
|
398
|
+
```typescript
|
|
399
|
+
describe('User Registration', () => {
|
|
400
|
+
test('registers new user with valid data', async () => {
|
|
401
|
+
const controller = new UserController();
|
|
402
|
+
const result = await controller.register({
|
|
403
|
+
email: 'user@example.com',
|
|
404
|
+
password: 'SecurePass123',
|
|
405
|
+
name: 'Test User'
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
expect(result.success).toBe(true);
|
|
409
|
+
expect(result.userId).toBeDefined();
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test('rejects duplicate email', async () => {
|
|
413
|
+
const controller = new UserController();
|
|
414
|
+
await controller.register({
|
|
415
|
+
email: 'existing@example.com',
|
|
416
|
+
password: 'Pass123',
|
|
417
|
+
name: 'First User'
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const result = await controller.register({
|
|
421
|
+
email: 'existing@example.com',
|
|
422
|
+
password: 'Pass456',
|
|
423
|
+
name: 'Second User'
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
expect(result.success).toBe(false);
|
|
427
|
+
expect(result.error).toBe('Email already exists');
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**GREEN - Tests pass on legacy code:**
|
|
433
|
+
```bash
|
|
434
|
+
$ npm test
|
|
435
|
+
PASS: registers new user with valid data
|
|
436
|
+
PASS: rejects duplicate email
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Step 2: Refactor with Test Protection
|
|
440
|
+
|
|
441
|
+
**Before (everything in controller):**
|
|
442
|
+
```typescript
|
|
443
|
+
class UserController {
|
|
444
|
+
async register(data: UserData) {
|
|
445
|
+
// Validation
|
|
446
|
+
if (!data.email.includes('@')) {
|
|
447
|
+
return { success: false, error: 'Invalid email' };
|
|
448
|
+
}
|
|
449
|
+
if (data.password.length < 8) {
|
|
450
|
+
return { success: false, error: 'Password too short' };
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Check duplicate
|
|
454
|
+
const existing = await db.users.findByEmail(data.email);
|
|
455
|
+
if (existing) {
|
|
456
|
+
return { success: false, error: 'Email already exists' };
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Create user
|
|
460
|
+
const user = await db.users.create({
|
|
461
|
+
email: data.email,
|
|
462
|
+
password: hashPassword(data.password),
|
|
463
|
+
name: data.name
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
return { success: true, userId: user.id };
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**After (extracted service):**
|
|
472
|
+
```typescript
|
|
473
|
+
// Extract service
|
|
474
|
+
class UserService {
|
|
475
|
+
async registerUser(data: UserData): Promise<User> {
|
|
476
|
+
this.validateUserData(data);
|
|
477
|
+
await this.checkDuplicateEmail(data.email);
|
|
478
|
+
return this.createUser(data);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
private validateUserData(data: UserData): void {
|
|
482
|
+
if (!data.email.includes('@')) {
|
|
483
|
+
throw new Error('Invalid email');
|
|
484
|
+
}
|
|
485
|
+
if (data.password.length < 8) {
|
|
486
|
+
throw new Error('Password too short');
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private async checkDuplicateEmail(email: string): Promise<void> {
|
|
491
|
+
const existing = await db.users.findByEmail(email);
|
|
492
|
+
if (existing) {
|
|
493
|
+
throw new Error('Email already exists');
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
private async createUser(data: UserData): Promise<User> {
|
|
498
|
+
return db.users.create({
|
|
499
|
+
email: data.email,
|
|
500
|
+
password: hashPassword(data.password),
|
|
501
|
+
name: data.name
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Simplified controller
|
|
507
|
+
class UserController {
|
|
508
|
+
private userService = new UserService();
|
|
509
|
+
|
|
510
|
+
async register(data: UserData) {
|
|
511
|
+
try {
|
|
512
|
+
const user = await this.userService.registerUser(data);
|
|
513
|
+
return { success: true, userId: user.id };
|
|
514
|
+
} catch (error) {
|
|
515
|
+
return { success: false, error: error.message };
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**Verify refactoring:**
|
|
522
|
+
```bash
|
|
523
|
+
$ npm test
|
|
524
|
+
PASS: registers new user with valid data
|
|
525
|
+
PASS: rejects duplicate email
|
|
526
|
+
```
|
|
527
|
+
✓ Behavior unchanged, structure improved
|
|
528
|
+
|
|
529
|
+
### Step 3: Add Tests for New Service
|
|
530
|
+
|
|
531
|
+
**Now test service directly:**
|
|
532
|
+
```typescript
|
|
533
|
+
describe('UserService', () => {
|
|
534
|
+
test('validates email format', async () => {
|
|
535
|
+
const service = new UserService();
|
|
536
|
+
await expect(
|
|
537
|
+
service.registerUser({
|
|
538
|
+
email: 'invalid',
|
|
539
|
+
password: 'Pass123456',
|
|
540
|
+
name: 'Test'
|
|
541
|
+
})
|
|
542
|
+
).rejects.toThrow('Invalid email');
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
test('validates password length', async () => {
|
|
546
|
+
const service = new UserService();
|
|
547
|
+
await expect(
|
|
548
|
+
service.registerUser({
|
|
549
|
+
email: 'test@example.com',
|
|
550
|
+
password: 'short',
|
|
551
|
+
name: 'Test'
|
|
552
|
+
})
|
|
553
|
+
).rejects.toThrow('Password too short');
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Time:** 45 minutes, safe refactoring with test protection
|
|
559
|
+
|
|
560
|
+
## Example 5: Building a Feature from Scratch
|
|
561
|
+
|
|
562
|
+
### Scenario
|
|
563
|
+
Implement shopping cart with add/remove/total functionality.
|
|
564
|
+
|
|
565
|
+
### Complete TDD Session
|
|
566
|
+
|
|
567
|
+
**Iteration 1 - Add Item:**
|
|
568
|
+
```typescript
|
|
569
|
+
// RED
|
|
570
|
+
test('adds item to cart', () => {
|
|
571
|
+
const cart = new ShoppingCart();
|
|
572
|
+
cart.addItem({ id: 1, name: 'Book', price: 10 });
|
|
573
|
+
expect(cart.getItemCount()).toBe(1);
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
// GREEN
|
|
577
|
+
class ShoppingCart {
|
|
578
|
+
private items: Item[] = [];
|
|
579
|
+
|
|
580
|
+
addItem(item: Item) {
|
|
581
|
+
this.items.push(item);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
getItemCount(): number {
|
|
585
|
+
return this.items.length;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
**Iteration 2 - Calculate Total:**
|
|
591
|
+
```typescript
|
|
592
|
+
// RED
|
|
593
|
+
test('calculates total price', () => {
|
|
594
|
+
const cart = new ShoppingCart();
|
|
595
|
+
cart.addItem({ id: 1, name: 'Book', price: 10 });
|
|
596
|
+
cart.addItem({ id: 2, name: 'Pen', price: 5 });
|
|
597
|
+
expect(cart.getTotal()).toBe(15);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
// GREEN
|
|
601
|
+
class ShoppingCart {
|
|
602
|
+
private items: Item[] = [];
|
|
603
|
+
|
|
604
|
+
addItem(item: Item) {
|
|
605
|
+
this.items.push(item);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
getItemCount(): number {
|
|
609
|
+
return this.items.length;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
getTotal(): number {
|
|
613
|
+
return this.items.reduce((sum, item) => sum + item.price, 0);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
**Iteration 3 - Remove Item:**
|
|
619
|
+
```typescript
|
|
620
|
+
// RED
|
|
621
|
+
test('removes item from cart', () => {
|
|
622
|
+
const cart = new ShoppingCart();
|
|
623
|
+
cart.addItem({ id: 1, name: 'Book', price: 10 });
|
|
624
|
+
cart.addItem({ id: 2, name: 'Pen', price: 5 });
|
|
625
|
+
cart.removeItem(1);
|
|
626
|
+
expect(cart.getItemCount()).toBe(1);
|
|
627
|
+
expect(cart.getTotal()).toBe(5);
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
// GREEN
|
|
631
|
+
class ShoppingCart {
|
|
632
|
+
private items: Item[] = [];
|
|
633
|
+
|
|
634
|
+
addItem(item: Item) {
|
|
635
|
+
this.items.push(item);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
removeItem(itemId: number) {
|
|
639
|
+
this.items = this.items.filter(item => item.id !== itemId);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
getItemCount(): number {
|
|
643
|
+
return this.items.length;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
getTotal(): number {
|
|
647
|
+
return this.items.reduce((sum, item) => sum + item.price, 0);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Iteration 4 - Handle Empty Cart:**
|
|
653
|
+
```typescript
|
|
654
|
+
// RED
|
|
655
|
+
test('returns zero for empty cart', () => {
|
|
656
|
+
const cart = new ShoppingCart();
|
|
657
|
+
expect(cart.getTotal()).toBe(0);
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
// GREEN - Already passes!
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
**Iteration 5 - Quantity Support:**
|
|
664
|
+
```typescript
|
|
665
|
+
// RED
|
|
666
|
+
test('handles item quantity', () => {
|
|
667
|
+
const cart = new ShoppingCart();
|
|
668
|
+
cart.addItem({ id: 1, name: 'Book', price: 10 }, 3);
|
|
669
|
+
expect(cart.getTotal()).toBe(30);
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
// GREEN
|
|
673
|
+
interface CartItem extends Item {
|
|
674
|
+
quantity: number;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
class ShoppingCart {
|
|
678
|
+
private items: CartItem[] = [];
|
|
679
|
+
|
|
680
|
+
addItem(item: Item, quantity: number = 1) {
|
|
681
|
+
this.items.push({ ...item, quantity });
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
removeItem(itemId: number) {
|
|
685
|
+
this.items = this.items.filter(item => item.id !== itemId);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
getItemCount(): number {
|
|
689
|
+
return this.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
getTotal(): number {
|
|
693
|
+
return this.items.reduce(
|
|
694
|
+
(sum, item) => sum + (item.price * item.quantity),
|
|
695
|
+
0
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
**Time:** 25 minutes, complete shopping cart with 5 tests
|
|
702
|
+
|
|
703
|
+
## Key Patterns Demonstrated
|
|
704
|
+
|
|
705
|
+
### Incremental Development
|
|
706
|
+
- Each test adds one small behavior
|
|
707
|
+
- Build complexity gradually
|
|
708
|
+
- Each step verified before next
|
|
709
|
+
|
|
710
|
+
### Test Protection
|
|
711
|
+
- Refactoring safe with tests
|
|
712
|
+
- Regressions caught immediately
|
|
713
|
+
- Behavior preserved across changes
|
|
714
|
+
|
|
715
|
+
### Test-First Benefits
|
|
716
|
+
- Clear requirements from tests
|
|
717
|
+
- No over-engineering
|
|
718
|
+
- 100% relevant test coverage
|
|
719
|
+
|
|
720
|
+
### Time Investment
|
|
721
|
+
- Small features: 10-25 minutes
|
|
722
|
+
- Medium features: 25-45 minutes
|
|
723
|
+
- Includes tests, implementation, refactoring
|
|
724
|
+
- Compare to: 15 min coding + 60-120 min debugging
|
|
725
|
+
|
|
726
|
+
## Summary
|
|
727
|
+
|
|
728
|
+
TDD in practice:
|
|
729
|
+
- Start with failing test
|
|
730
|
+
- Implement minimally
|
|
731
|
+
- Refactor safely
|
|
732
|
+
- Build incrementally
|
|
733
|
+
- Fast feedback loop
|
|
734
|
+
- High confidence
|
|
735
|
+
|
|
736
|
+
## Related References
|
|
737
|
+
|
|
738
|
+
- [Workflow](workflow.md): Complete RED/GREEN/REFACTOR process
|
|
739
|
+
- [Philosophy](philosophy.md): Why TDD works
|
|
740
|
+
- [Anti-patterns](anti-patterns.md): Common mistakes
|
|
741
|
+
- [Integration](integration.md): TDD with other skills
|