claude-mpm 4.15.6__py3-none-any.whl → 4.21.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (194) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  3. claude_mpm/agents/BASE_PM.md +272 -23
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +49 -0
  5. claude_mpm/agents/agent_loader.py +4 -4
  6. claude_mpm/agents/templates/engineer.json +5 -1
  7. claude_mpm/agents/templates/php-engineer.json +10 -4
  8. claude_mpm/agents/templates/python_engineer.json +8 -3
  9. claude_mpm/agents/templates/rust_engineer.json +12 -7
  10. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  11. claude_mpm/cli/commands/__init__.py +2 -0
  12. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  13. claude_mpm/cli/commands/mpm_init/core.py +525 -0
  14. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  15. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  16. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  17. claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
  18. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  19. claude_mpm/cli/commands/mpm_init_handler.py +67 -1
  20. claude_mpm/cli/commands/skills.py +488 -0
  21. claude_mpm/cli/executor.py +2 -0
  22. claude_mpm/cli/parsers/base_parser.py +7 -0
  23. claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
  24. claude_mpm/cli/parsers/skills_parser.py +137 -0
  25. claude_mpm/cli/startup.py +57 -0
  26. claude_mpm/commands/mpm-auto-configure.md +52 -0
  27. claude_mpm/commands/mpm-help.md +3 -0
  28. claude_mpm/commands/mpm-init.md +112 -6
  29. claude_mpm/commands/mpm-version.md +113 -0
  30. claude_mpm/commands/mpm.md +1 -0
  31. claude_mpm/config/agent_config.py +2 -2
  32. claude_mpm/constants.py +12 -0
  33. claude_mpm/core/config.py +42 -0
  34. claude_mpm/core/factories.py +1 -1
  35. claude_mpm/core/interfaces.py +56 -1
  36. claude_mpm/core/optimized_agent_loader.py +3 -3
  37. claude_mpm/hooks/__init__.py +8 -0
  38. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  39. claude_mpm/hooks/session_resume_hook.py +121 -0
  40. claude_mpm/models/resume_log.py +340 -0
  41. claude_mpm/services/agents/auto_config_manager.py +1 -1
  42. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  43. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  44. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  45. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  46. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  47. claude_mpm/services/agents/local_template_manager.py +1 -1
  48. claude_mpm/services/agents/recommender.py +47 -0
  49. claude_mpm/services/cli/resume_service.py +617 -0
  50. claude_mpm/services/cli/session_manager.py +87 -0
  51. claude_mpm/services/cli/session_pause_manager.py +504 -0
  52. claude_mpm/services/cli/session_resume_helper.py +372 -0
  53. claude_mpm/services/core/interfaces.py +56 -1
  54. claude_mpm/services/core/models/agent_config.py +3 -0
  55. claude_mpm/services/core/models/process.py +4 -0
  56. claude_mpm/services/core/path_resolver.py +1 -1
  57. claude_mpm/services/diagnostics/models.py +21 -0
  58. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  59. claude_mpm/services/local_ops/__init__.py +2 -0
  60. claude_mpm/services/mcp_config_manager.py +7 -131
  61. claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
  62. claude_mpm/services/mcp_gateway/core/process_pool.py +19 -10
  63. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +26 -21
  64. claude_mpm/services/session_manager.py +205 -1
  65. claude_mpm/services/unified/deployment_strategies/local.py +1 -1
  66. claude_mpm/services/version_service.py +104 -1
  67. claude_mpm/skills/__init__.py +21 -0
  68. claude_mpm/skills/agent_skills_injector.py +324 -0
  69. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  70. claude_mpm/skills/bundled/api-documentation.md +393 -0
  71. claude_mpm/skills/bundled/async-testing.md +571 -0
  72. claude_mpm/skills/bundled/code-review.md +143 -0
  73. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  74. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  75. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  76. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  77. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  78. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  79. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  80. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  81. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  82. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  83. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  84. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  85. claude_mpm/skills/bundled/database-migration.md +199 -0
  86. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  87. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  88. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  89. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  90. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  91. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  92. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  93. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  94. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  95. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  96. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  97. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  98. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  99. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  100. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  101. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  102. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  103. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  104. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  105. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  106. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  107. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  108. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  109. claude_mpm/skills/bundled/git-workflow.md +414 -0
  110. claude_mpm/skills/bundled/imagemagick.md +204 -0
  111. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  112. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  113. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  114. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  115. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  116. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  117. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  118. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  119. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  120. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  121. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  122. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  123. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  124. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  125. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  126. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  127. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  128. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  129. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  130. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  131. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  132. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  133. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  134. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  135. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  136. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  137. claude_mpm/skills/bundled/pdf.md +141 -0
  138. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  139. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  140. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  141. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  142. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  143. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  144. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  145. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  146. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  147. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  148. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  149. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  150. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  151. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  152. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  153. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  154. claude_mpm/skills/bundled/security-scanning.md +327 -0
  155. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  156. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  157. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  158. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  159. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  160. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  161. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  162. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  163. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  164. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  165. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  166. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  167. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  168. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  169. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  170. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  171. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  172. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  173. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  174. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  175. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  176. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  177. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  178. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  179. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  180. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  181. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  182. claude_mpm/skills/bundled/xlsx.md +157 -0
  183. claude_mpm/skills/registry.py +97 -9
  184. claude_mpm/skills/skills_registry.py +348 -0
  185. claude_mpm/skills/skills_service.py +739 -0
  186. claude_mpm/utils/agent_dependency_loader.py +2 -2
  187. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/METADATA +211 -33
  188. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/RECORD +192 -60
  189. claude_mpm/agents/INSTRUCTIONS_OLD_DEPRECATED.md +0 -602
  190. claude_mpm/cli/commands/mpm_init.py +0 -2008
  191. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/WHEEL +0 -0
  192. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/entry_points.txt +0 -0
  193. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/licenses/LICENSE +0 -0
  194. {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.0.dist-info}/top_level.txt +0 -0
@@ -163,17 +163,21 @@ class MCPAutoConfigurator:
163
163
  Returns:
164
164
  True if user agrees, False if declines, None if timeout
165
165
  """
166
- print("\n" + "=" * 60)
167
- print("🔧 MCP Gateway Configuration")
168
- print("=" * 60)
169
- print("\nClaude MPM can automatically configure MCP Gateway for")
170
- print("Claude Code integration. This enables advanced features:")
171
- print(" • File analysis and summarization")
172
- print(" • System diagnostics")
173
- print(" Ticket management")
174
- print(" • And more...")
175
- print("\nWould you like to configure it now? (y/n)")
176
- print(f"(Auto-declining in {timeout} seconds)")
166
+ print("\n" + "=" * 60, file=sys.stderr)
167
+ print("🔧 MCP Gateway Configuration", file=sys.stderr)
168
+ print("=" * 60, file=sys.stderr)
169
+ print(
170
+ "\nClaude MPM can automatically configure MCP Gateway for", file=sys.stderr
171
+ )
172
+ print(
173
+ "Claude Code integration. This enables advanced features:", file=sys.stderr
174
+ )
175
+ print(" File analysis and summarization", file=sys.stderr)
176
+ print(" System diagnostics", file=sys.stderr)
177
+ print(" • Ticket management", file=sys.stderr)
178
+ print(" • And more...", file=sys.stderr)
179
+ print("\nWould you like to configure it now? (y/n)", file=sys.stderr)
180
+ print(f"(Auto-declining in {timeout} seconds)", file=sys.stderr)
177
181
 
178
182
  # Use threading for cross-platform timeout support
179
183
  # Python 3.7+ has queue built-in - no need to check, we require 3.10+
@@ -203,7 +207,7 @@ class MCPAutoConfigurator:
203
207
 
204
208
  if input_thread.is_alive():
205
209
  # Timed out
206
- print("\n(Timed out - declining)")
210
+ print("\n(Timed out - declining)", file=sys.stderr)
207
211
  return None
208
212
  # Got input
209
213
  return user_input in ["y", "yes"]
@@ -220,7 +224,7 @@ class MCPAutoConfigurator:
220
224
  if self.claude_config_path.exists():
221
225
  backup_path = self._create_backup()
222
226
  if backup_path:
223
- print(f"✅ Backup created: {backup_path}")
227
+ print(f"✅ Backup created: {backup_path}", file=sys.stderr)
224
228
 
225
229
  # Load or create configuration
226
230
  config = self._load_or_create_config()
@@ -232,7 +236,7 @@ class MCPAutoConfigurator:
232
236
  # Find claude-mpm executable
233
237
  executable = self._find_claude_mpm_executable()
234
238
  if not executable:
235
- print("❌ Could not find claude-mpm executable")
239
+ print("❌ Could not find claude-mpm executable", file=sys.stderr)
236
240
  return False
237
241
 
238
242
  # Configure MCP server
@@ -246,20 +250,22 @@ class MCPAutoConfigurator:
246
250
  with self.claude_config_path.open("w") as f:
247
251
  json.dump(config, f, indent=2)
248
252
 
249
- print(f"✅ Configuration saved to: {self.claude_config_path}")
250
- print("\n🎉 MCP Gateway configured successfully!")
251
- print("\nNext steps:")
252
- print("1. Restart Claude Code (if running)")
253
- print("2. Look for the MCP icon in the interface")
254
- print("3. Try @claude-mpm-gateway in a conversation")
253
+ print(
254
+ f" Configuration saved to: {self.claude_config_path}", file=sys.stderr
255
+ )
256
+ print("\n🎉 MCP Gateway configured successfully!", file=sys.stderr)
257
+ print("\nNext steps:", file=sys.stderr)
258
+ print("1. Restart Claude Code (if running)", file=sys.stderr)
259
+ print("2. Look for the MCP icon in the interface", file=sys.stderr)
260
+ print("3. Try @claude-mpm-gateway in a conversation", file=sys.stderr)
255
261
 
256
262
  return True
257
263
 
258
264
  except Exception as e:
259
265
  self.logger.error(f"Auto-configuration failed: {e}")
260
- print(f"❌ Configuration failed: {e}")
261
- print("\nYou can configure manually with:")
262
- print(" claude-mpm mcp install")
266
+ print(f"❌ Configuration failed: {e}", file=sys.stderr)
267
+ print("\nYou can configure manually with:", file=sys.stderr)
268
+ print(" claude-mpm mcp install", file=sys.stderr)
263
269
  return False
264
270
 
265
271
  def _create_backup(self) -> Optional[Path]:
@@ -344,8 +350,8 @@ class MCPAutoConfigurator:
344
350
  if user_choice:
345
351
  return self.auto_configure()
346
352
  if user_choice is False: # User explicitly said no
347
- print("\n📝 You can configure MCP later with:")
348
- print(" claude-mpm mcp install")
353
+ print("\n📝 You can configure MCP later with:", file=sys.stderr)
354
+ print(" claude-mpm mcp install", file=sys.stderr)
349
355
  # If timeout (None), don't show additional message
350
356
  return False
351
357
 
@@ -864,7 +864,7 @@ def _prompt_kuzu_update(current: str, latest: str) -> None:
864
864
  # Check if running in a non-interactive context
865
865
  try:
866
866
  if confirm_operation(message):
867
- print("🚀 Updating kuzu-memory...")
867
+ print("🚀 Updating kuzu-memory...", file=sys.stderr)
868
868
  try:
869
869
  result = subprocess.run(
870
870
  ["pipx", "upgrade", "kuzu-memory"],
@@ -874,28 +874,37 @@ def _prompt_kuzu_update(current: str, latest: str) -> None:
874
874
  check=False,
875
875
  )
876
876
  if result.returncode == 0:
877
- print("✅ Successfully updated kuzu-memory!")
877
+ print("✅ Successfully updated kuzu-memory!", file=sys.stderr)
878
878
  logger.info(f"Updated kuzu-memory from {current} to {latest}")
879
879
  else:
880
- print(f"⚠️ Update failed: {result.stderr}")
880
+ print(f"⚠️ Update failed: {result.stderr}", file=sys.stderr)
881
881
  logger.warning(f"kuzu-memory update failed: {result.stderr}")
882
882
  except subprocess.TimeoutExpired:
883
- print("⚠️ Update timed out. Please try again later.")
883
+ print("⚠️ Update timed out. Please try again later.", file=sys.stderr)
884
884
  logger.warning("kuzu-memory update timed out")
885
885
  except Exception as e:
886
- print(f"⚠️ Update failed: {e}")
886
+ print(f"⚠️ Update failed: {e}", file=sys.stderr)
887
887
  logger.warning(f"kuzu-memory update error: {e}")
888
888
  else:
889
889
  # User declined update
890
- print("\n To skip this version permanently, run:")
891
- print(f" claude-mpm config set-skip-version kuzu-memory {latest}")
892
- print(" To disable update checks for kuzu-memory:")
893
- print(" claude-mpm config disable-update-checks kuzu-memory")
890
+ print("\n To skip this version permanently, run:", file=sys.stderr)
891
+ print(
892
+ f" claude-mpm config set-skip-version kuzu-memory {latest}",
893
+ file=sys.stderr,
894
+ )
895
+ print(" To disable update checks for kuzu-memory:", file=sys.stderr)
896
+ print(
897
+ " claude-mpm config disable-update-checks kuzu-memory",
898
+ file=sys.stderr,
899
+ )
894
900
 
895
901
  # Ask if user wants to skip this version
896
902
  if confirm_operation("\n Skip this version in future checks?"):
897
903
  UpdatePreferences.set_skip_version("kuzu-memory", latest)
898
- print(f" Version {latest} will be skipped in future checks.")
904
+ print(
905
+ f" Version {latest} will be skipped in future checks.",
906
+ file=sys.stderr,
907
+ )
899
908
  except (KeyboardInterrupt, EOFError):
900
909
  # User interrupted or input not available
901
910
  pass
@@ -161,12 +161,17 @@ class ExternalMCPService(BaseToolAdapter):
161
161
 
162
162
  if interactive:
163
163
  # Show user-friendly installation prompt
164
- print(f"\n⚠️ {self.package_name} not found")
165
- print("This package enables enhanced functionality (optional).")
166
- print("\nInstallation options:")
167
- print("1. Install via pip (recommended for this project)")
168
- print("2. Install via pipx (isolated, system-wide)")
169
- print("3. Skip (continue without this package)")
164
+ print(f"\n⚠️ {self.package_name} not found", file=sys.stderr)
165
+ print(
166
+ "This package enables enhanced functionality (optional).",
167
+ file=sys.stderr,
168
+ )
169
+ print("\nInstallation options:", file=sys.stderr)
170
+ print(
171
+ "1. Install via pip (recommended for this project)", file=sys.stderr
172
+ )
173
+ print("2. Install via pipx (isolated, system-wide)", file=sys.stderr)
174
+ print("3. Skip (continue without this package)", file=sys.stderr)
170
175
 
171
176
  try:
172
177
  choice = input("\nChoose option (1/2/3) [1]: ").strip() or "1"
@@ -180,7 +185,7 @@ class ExternalMCPService(BaseToolAdapter):
180
185
  )
181
186
  return False
182
187
  except (EOFError, KeyboardInterrupt):
183
- print("\nInstallation cancelled")
188
+ print("\nInstallation cancelled", file=sys.stderr)
184
189
  return False
185
190
  else:
186
191
  # Non-interactive: default to pip
@@ -201,7 +206,7 @@ class ExternalMCPService(BaseToolAdapter):
201
206
  async def _install_via_pip(self) -> bool:
202
207
  """Install package via pip."""
203
208
  try:
204
- print(f"\n📦 Installing {self.package_name} via pip...")
209
+ print(f"\n📦 Installing {self.package_name} via pip...", file=sys.stderr)
205
210
  result = subprocess.run(
206
211
  [sys.executable, "-m", "pip", "install", self.package_name],
207
212
  capture_output=True,
@@ -211,21 +216,21 @@ class ExternalMCPService(BaseToolAdapter):
211
216
  )
212
217
 
213
218
  if result.returncode == 0:
214
- print(f"✓ Successfully installed {self.package_name}")
219
+ print(f"✓ Successfully installed {self.package_name}", file=sys.stderr)
215
220
  self.logger.info(f"Successfully installed {self.package_name} via pip")
216
221
  return True
217
222
 
218
223
  error_msg = result.stderr.strip() if result.stderr else "Unknown error"
219
- print(f"✗ Installation failed: {error_msg}")
224
+ print(f"✗ Installation failed: {error_msg}", file=sys.stderr)
220
225
  self.logger.error(f"Failed to install {self.package_name}: {error_msg}")
221
226
  return False
222
227
 
223
228
  except subprocess.TimeoutExpired:
224
- print("✗ Installation timed out")
229
+ print("✗ Installation timed out", file=sys.stderr)
225
230
  self.logger.error(f"Installation of {self.package_name} timed out")
226
231
  return False
227
232
  except Exception as e:
228
- print(f"✗ Installation error: {e}")
233
+ print(f"✗ Installation error: {e}", file=sys.stderr)
229
234
  self.logger.error(f"Error installing {self.package_name}: {e}")
230
235
  return False
231
236
 
@@ -242,12 +247,12 @@ class ExternalMCPService(BaseToolAdapter):
242
247
  )
243
248
 
244
249
  if pipx_check.returncode != 0:
245
- print("✗ pipx is not installed")
246
- print("Install pipx first: python -m pip install pipx")
250
+ print("✗ pipx is not installed", file=sys.stderr)
251
+ print("Install pipx first: python -m pip install pipx", file=sys.stderr)
247
252
  self.logger.error("pipx not available for installation")
248
253
  return False
249
254
 
250
- print(f"\n📦 Installing {self.package_name} via pipx...")
255
+ print(f"\n📦 Installing {self.package_name} via pipx...", file=sys.stderr)
251
256
  result = subprocess.run(
252
257
  ["pipx", "install", self.package_name],
253
258
  capture_output=True,
@@ -257,26 +262,26 @@ class ExternalMCPService(BaseToolAdapter):
257
262
  )
258
263
 
259
264
  if result.returncode == 0:
260
- print(f"✓ Successfully installed {self.package_name}")
265
+ print(f"✓ Successfully installed {self.package_name}", file=sys.stderr)
261
266
  self.logger.info(f"Successfully installed {self.package_name} via pipx")
262
267
  return True
263
268
 
264
269
  error_msg = result.stderr.strip() if result.stderr else "Unknown error"
265
- print(f"✗ Installation failed: {error_msg}")
270
+ print(f"✗ Installation failed: {error_msg}", file=sys.stderr)
266
271
  self.logger.error(f"Failed to install {self.package_name}: {error_msg}")
267
272
  return False
268
273
 
269
274
  except FileNotFoundError:
270
- print("✗ pipx command not found")
271
- print("Install pipx first: python -m pip install pipx")
275
+ print("✗ pipx command not found", file=sys.stderr)
276
+ print("Install pipx first: python -m pip install pipx", file=sys.stderr)
272
277
  self.logger.error("pipx command not found")
273
278
  return False
274
279
  except subprocess.TimeoutExpired:
275
- print("✗ Installation timed out")
280
+ print("✗ Installation timed out", file=sys.stderr)
276
281
  self.logger.error(f"Installation of {self.package_name} timed out")
277
282
  return False
278
283
  except Exception as e:
279
- print(f"✗ Installation error: {e}")
284
+ print(f"✗ Installation error: {e}", file=sys.stderr)
280
285
  self.logger.error(f"Error installing {self.package_name}: {e}")
281
286
  return False
282
287
 
@@ -6,12 +6,19 @@ Ensures a single session ID is generated and used across all components.
6
6
 
7
7
  This service addresses race conditions and duplicate session ID generation
8
8
  by providing a single source of truth for session identifiers.
9
+
10
+ Extended with:
11
+ - Token usage tracking and monitoring
12
+ - Resume log generation on session end
13
+ - Context metrics persistence
14
+ - Automatic resume log injection on session startup
9
15
  """
10
16
 
11
17
  import os
12
18
  from datetime import datetime, timezone
19
+ from pathlib import Path
13
20
  from threading import Lock
14
- from typing import Optional
21
+ from typing import Any, Dict, Optional
15
22
 
16
23
  from claude_mpm.core.logging_utils import get_logger
17
24
 
@@ -64,6 +71,24 @@ class SessionManager:
64
71
  self._session_id = self._generate_session_id()
65
72
  self._session_start_time = datetime.now(timezone.utc)
66
73
 
74
+ # Token usage tracking
75
+ self._cumulative_tokens = 0
76
+ self._total_budget = 200000 # Default Claude Code budget
77
+ self._last_stop_reason: Optional[str] = None
78
+
79
+ # Context metrics storage
80
+ self._context_metrics: Dict[str, Any] = {
81
+ "total_budget": self._total_budget,
82
+ "used_tokens": 0,
83
+ "remaining_tokens": self._total_budget,
84
+ "percentage_used": 0.0,
85
+ "stop_reason": None,
86
+ "model": "claude-sonnet-4.5",
87
+ }
88
+
89
+ # Resume log reference (loaded on startup if exists)
90
+ self._resume_log_content: Optional[str] = None
91
+
67
92
  # Mark as initialized
68
93
  self.__class__._initialized = True
69
94
 
@@ -71,6 +96,9 @@ class SessionManager:
71
96
  f"SessionManager initialized with session ID: {self._session_id}"
72
97
  )
73
98
 
99
+ # Check for resume log from previous session
100
+ self._load_resume_log()
101
+
74
102
  def _generate_session_id(self) -> str:
75
103
  """
76
104
  Generate or retrieve a session ID.
@@ -134,6 +162,182 @@ class SessionManager:
134
162
  f"Session ID already set to {session_id}, no change needed"
135
163
  )
136
164
 
165
+ def update_token_usage(
166
+ self,
167
+ input_tokens: int = 0,
168
+ output_tokens: int = 0,
169
+ stop_reason: Optional[str] = None,
170
+ ) -> Dict[str, Any]:
171
+ """
172
+ Update cumulative token usage for the session.
173
+
174
+ Args:
175
+ input_tokens: Input tokens from latest API call
176
+ output_tokens: Output tokens from latest API call
177
+ stop_reason: Stop reason from Claude API
178
+
179
+ Returns:
180
+ Updated context metrics
181
+ """
182
+ with self.__class__._lock:
183
+ # Update cumulative usage
184
+ tokens_used = input_tokens + output_tokens
185
+ self._cumulative_tokens += tokens_used
186
+
187
+ # Update stop reason if provided
188
+ if stop_reason:
189
+ self._last_stop_reason = stop_reason
190
+
191
+ # Calculate metrics
192
+ remaining = max(0, self._total_budget - self._cumulative_tokens)
193
+ percentage = (self._cumulative_tokens / self._total_budget) * 100
194
+
195
+ # Update context metrics
196
+ self._context_metrics = {
197
+ "total_budget": self._total_budget,
198
+ "used_tokens": self._cumulative_tokens,
199
+ "remaining_tokens": remaining,
200
+ "percentage_used": percentage,
201
+ "stop_reason": self._last_stop_reason,
202
+ "model": "claude-sonnet-4.5",
203
+ }
204
+
205
+ logger.debug(
206
+ f"Token usage updated: {self._cumulative_tokens}/{self._total_budget} "
207
+ f"({percentage:.1f}%) - Stop reason: {stop_reason}"
208
+ )
209
+
210
+ return self._context_metrics.copy()
211
+
212
+ def get_context_metrics(self) -> Dict[str, Any]:
213
+ """
214
+ Get current context metrics.
215
+
216
+ Returns:
217
+ Dictionary containing token usage and context metrics
218
+ """
219
+ with self.__class__._lock:
220
+ return self._context_metrics.copy()
221
+
222
+ def get_token_usage_percentage(self) -> float:
223
+ """
224
+ Get current token usage as a percentage (0.0 to 1.0).
225
+
226
+ Returns:
227
+ Token usage percentage
228
+ """
229
+ with self.__class__._lock:
230
+ return self._context_metrics["percentage_used"] / 100.0
231
+
232
+ def should_warn_context_limit(self, threshold: float = 0.70) -> bool:
233
+ """
234
+ Check if context usage has reached warning threshold.
235
+
236
+ Args:
237
+ threshold: Warning threshold (0.0 to 1.0)
238
+
239
+ Returns:
240
+ True if threshold reached
241
+ """
242
+ return self.get_token_usage_percentage() >= threshold
243
+
244
+ def _load_resume_log(self) -> None:
245
+ """
246
+ Load resume log from previous session if it exists.
247
+
248
+ This is called during initialization to check for session continuity.
249
+ """
250
+ try:
251
+ # Lazy import to avoid circular dependencies
252
+ from claude_mpm.services.infrastructure.resume_log_generator import (
253
+ ResumeLogGenerator,
254
+ )
255
+
256
+ generator = ResumeLogGenerator()
257
+
258
+ # Check if there's a resume log for this session
259
+ # (Could be from a previous interrupted session with same ID)
260
+ resume_content = generator.load_resume_log(self._session_id)
261
+
262
+ if resume_content:
263
+ self._resume_log_content = resume_content
264
+ logger.info(f"Loaded resume log for session {self._session_id}")
265
+ else:
266
+ logger.debug("No resume log found for current session")
267
+
268
+ except Exception as e:
269
+ logger.warning(f"Failed to load resume log: {e}")
270
+ # Non-critical error, continue without resume log
271
+
272
+ def get_resume_log_content(self) -> Optional[str]:
273
+ """
274
+ Get resume log content if loaded.
275
+
276
+ Returns:
277
+ Resume log markdown content or None
278
+ """
279
+ with self.__class__._lock:
280
+ return self._resume_log_content
281
+
282
+ def generate_resume_log(
283
+ self,
284
+ session_state: Optional[Dict[str, Any]] = None,
285
+ ) -> Optional[Path]:
286
+ """
287
+ Generate and save resume log for current session.
288
+
289
+ Args:
290
+ session_state: Optional session state data to include
291
+
292
+ Returns:
293
+ Path to saved resume log or None if generation failed
294
+ """
295
+ try:
296
+ # Lazy import to avoid circular dependencies
297
+ from claude_mpm.models.resume_log import ContextMetrics, ResumeLog
298
+ from claude_mpm.services.infrastructure.resume_log_generator import (
299
+ ResumeLogGenerator,
300
+ )
301
+
302
+ generator = ResumeLogGenerator()
303
+
304
+ # Create context metrics from current state
305
+ context_metrics = ContextMetrics(
306
+ total_budget=self._total_budget,
307
+ used_tokens=self._cumulative_tokens,
308
+ remaining_tokens=self._context_metrics["remaining_tokens"],
309
+ percentage_used=self._context_metrics["percentage_used"],
310
+ stop_reason=self._last_stop_reason,
311
+ model=self._context_metrics["model"],
312
+ session_id=self._session_id,
313
+ )
314
+
315
+ if session_state:
316
+ # Generate from provided session state
317
+ resume_log = generator.generate_from_session_state(
318
+ session_id=self._session_id,
319
+ session_state=session_state,
320
+ stop_reason=self._last_stop_reason,
321
+ )
322
+ else:
323
+ # Create minimal resume log
324
+ resume_log = ResumeLog(
325
+ session_id=self._session_id,
326
+ context_metrics=context_metrics,
327
+ mission_summary="Session ended - resume log auto-generated.",
328
+ )
329
+
330
+ if resume_log:
331
+ file_path = generator.save_resume_log(resume_log)
332
+ logger.info(f"Resume log generated and saved: {file_path}")
333
+ return file_path
334
+ logger.warning("Resume log generation returned None")
335
+ return None
336
+
337
+ except Exception as e:
338
+ logger.error(f"Failed to generate resume log: {e}", exc_info=True)
339
+ return None
340
+
137
341
  @classmethod
138
342
  def reset(cls) -> None:
139
343
  """
@@ -395,7 +395,7 @@ class LocalDeploymentStrategy(DeploymentStrategy):
395
395
  shutil.copy2(artifact, dest)
396
396
  deployed.append(dest)
397
397
 
398
- self._logger.info(f"Deployed agent: {dest}")
398
+ self._logger.debug(f"Deployed agent: {dest}")
399
399
 
400
400
  return deployed
401
401
 
@@ -9,7 +9,7 @@ Extracted from ClaudeRunner to follow Single Responsibility Principle.
9
9
  """
10
10
 
11
11
  from pathlib import Path
12
- from typing import Any, Dict, Optional
12
+ from typing import Any, Dict, List, Optional
13
13
 
14
14
  from claude_mpm.config.paths import paths
15
15
  from claude_mpm.core.base_service import BaseService
@@ -274,3 +274,106 @@ class VersionService(BaseService, VersionServiceInterface):
274
274
  "message": "Update checking not implemented",
275
275
  "checked_at": None,
276
276
  }
277
+
278
+ def get_agents_versions(self) -> Dict[str, List[Dict[str, str]]]:
279
+ """Get all agents grouped by tier with versions.
280
+
281
+ Returns:
282
+ Dict with keys: system, user, project
283
+ Each value is list of agent dicts with: name, version, id
284
+ """
285
+ from claude_mpm.core.unified_agent_registry import get_agent_registry
286
+
287
+ agents_by_tier = {"system": [], "user": [], "project": []}
288
+
289
+ try:
290
+ registry = get_agent_registry()
291
+ all_agents = registry.list_agents()
292
+
293
+ for agent in all_agents:
294
+ agent_info = {
295
+ "name": agent.name,
296
+ "version": agent.version,
297
+ "id": agent.name, # Use name as ID since agent_id doesn't exist
298
+ }
299
+ tier = (
300
+ agent.tier.value
301
+ if hasattr(agent.tier, "value")
302
+ else str(agent.tier)
303
+ )
304
+ if tier in agents_by_tier:
305
+ agents_by_tier[tier].append(agent_info)
306
+ else:
307
+ agents_by_tier["system"].append(agent_info)
308
+
309
+ # Sort each tier alphabetically by name
310
+ for tier, agents in agents_by_tier.items():
311
+ agents.sort(key=lambda x: x["name"])
312
+
313
+ except Exception as e:
314
+ self.logger.error(f"Failed to get agent versions: {e}")
315
+
316
+ return agents_by_tier
317
+
318
+ def get_skills_versions(self) -> Dict[str, List[Dict[str, str]]]:
319
+ """Get all skills grouped by source with versions.
320
+
321
+ Returns:
322
+ Dict with keys: bundled, user, project
323
+ Each value is list of skill dicts with: name, version, description
324
+ """
325
+ from claude_mpm.skills.registry import get_registry
326
+
327
+ skills_by_source = {"bundled": [], "user": [], "project": []}
328
+
329
+ try:
330
+ registry = get_registry()
331
+
332
+ for skill in registry.list_skills():
333
+ skill_info = {
334
+ "name": skill.name,
335
+ "version": skill.version,
336
+ "description": (
337
+ skill.description[:60] + "..."
338
+ if len(skill.description) > 60
339
+ else skill.description
340
+ ),
341
+ }
342
+ source = skill.source if skill.source in skills_by_source else "bundled"
343
+ skills_by_source[source].append(skill_info)
344
+
345
+ # Sort each source alphabetically by name
346
+ for source, skills in skills_by_source.items():
347
+ skills.sort(key=lambda x: x["name"])
348
+
349
+ except Exception as e:
350
+ self.logger.error(f"Failed to get skill versions: {e}")
351
+
352
+ return skills_by_source
353
+
354
+ def get_version_summary(self) -> Dict:
355
+ """Get complete version summary.
356
+
357
+ Returns:
358
+ Dict with project_version, build, agents, skills, and counts
359
+ """
360
+ agents = self.get_agents_versions()
361
+ skills = self.get_skills_versions()
362
+ build = self.get_build_number()
363
+
364
+ return {
365
+ "project_version": self.get_base_version(),
366
+ "build": build,
367
+ "agents": agents,
368
+ "skills": skills,
369
+ "counts": {
370
+ "agents_total": sum(len(v) for v in agents.values()),
371
+ "agents_system": len(agents.get("system", [])),
372
+ "agents_user": len(agents.get("user", [])),
373
+ "agents_project": len(agents.get("project", [])),
374
+ "skills_total": sum(len(v) for v in skills.values()),
375
+ "skills_bundled": len(skills.get("bundled", [])),
376
+ "skills_user": len(skills.get("user", [])),
377
+ "skills_project": len(skills.get("project", [])),
378
+ },
379
+ }
@@ -8,14 +8,35 @@ Skills can be:
8
8
  - Bundled with MPM (in skills/bundled/)
9
9
  - User-installed (in ~/.claude/skills/)
10
10
  - Project-specific (in .claude/skills/)
11
+
12
+ New Skills Integration System:
13
+ - SkillsService: Core service for skill management
14
+ - AgentSkillsInjector: Dynamic skill injection into agent templates
15
+ - SkillsRegistry: Helper class for registry operations
16
+
17
+ Legacy System (maintained for compatibility):
18
+ - Skill: Dataclass for skill representation
19
+ - SkillManager: Legacy skill manager
20
+ - get_registry: Legacy registry access
11
21
  """
12
22
 
23
+ # New Skills Integration System
24
+ from .agent_skills_injector import AgentSkillsInjector
25
+
26
+ # Legacy System (maintained for compatibility)
13
27
  from .registry import Skill, SkillsRegistry, get_registry
14
28
  from .skill_manager import SkillManager
29
+ from .skills_registry import SkillsRegistry as SkillsRegistryHelper
30
+ from .skills_service import SkillsService
15
31
 
16
32
  __all__ = [
33
+ "AgentSkillsInjector",
34
+ # Legacy System
17
35
  "Skill",
18
36
  "SkillManager",
19
37
  "SkillsRegistry",
38
+ "SkillsRegistryHelper",
39
+ # New Skills Integration System
40
+ "SkillsService",
20
41
  "get_registry",
21
42
  ]