claude-mpm 5.6.16__py3-none-any.whl → 5.6.18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 5.6.16
1
+ 5.6.18
claude_mpm/cli/startup.py CHANGED
@@ -478,6 +478,94 @@ def _cleanup_orphaned_agents(deploy_target: Path, deployed_agents: list[str]) ->
478
478
  return removed_count
479
479
 
480
480
 
481
+ def _save_deployment_state_after_reconciliation(
482
+ agent_result, project_path: Path
483
+ ) -> None:
484
+ """Save deployment state after reconciliation to prevent duplicate deployment.
485
+
486
+ WHY: After perform_startup_reconciliation() deploys agents to .claude/agents/,
487
+ we need to save a deployment state file so that ClaudeRunner.setup_agents()
488
+ can detect agents are already deployed and skip redundant deployment.
489
+
490
+ This prevents the "✓ Deployed 31 native agents" duplicate deployment that
491
+ occurs when setup_agents() doesn't know reconciliation already ran.
492
+
493
+ Args:
494
+ agent_result: DeploymentResult from perform_startup_reconciliation()
495
+ project_path: Project root directory
496
+
497
+ DESIGN DECISION: Use same state file format as ClaudeRunner._save_deployment_state()
498
+ Located at: .claude-mpm/cache/deployment_state.json
499
+
500
+ State file format:
501
+ {
502
+ "version": "5.6.13",
503
+ "agent_count": 15,
504
+ "deployment_hash": "sha256:...",
505
+ "deployed_at": 1234567890.123
506
+ }
507
+ """
508
+ import hashlib
509
+ import json
510
+ import time
511
+
512
+ from ..core.logger import get_logger
513
+
514
+ logger = get_logger("cli")
515
+
516
+ try:
517
+ # Get version from package
518
+ from claude_mpm import __version__
519
+
520
+ # Path to state file (matches ClaudeRunner._get_deployment_state_path())
521
+ state_file = project_path / ".claude-mpm" / "cache" / "deployment_state.json"
522
+ agents_dir = project_path / ".claude" / "agents"
523
+
524
+ # Count deployed agents
525
+ if agents_dir.exists():
526
+ agent_count = len(list(agents_dir.glob("*.md")))
527
+ else:
528
+ agent_count = 0
529
+
530
+ # Calculate deployment hash (matches ClaudeRunner._calculate_deployment_hash())
531
+ # CRITICAL: Must match exact hash algorithm used in ClaudeRunner
532
+ # Hashes filename + file content (not mtime) for consistency
533
+ deployment_hash = ""
534
+ if agents_dir.exists():
535
+ agent_files = sorted(agents_dir.glob("*.md"))
536
+ hash_obj = hashlib.sha256()
537
+ for agent_file in agent_files:
538
+ # Include filename and content in hash (matches ClaudeRunner)
539
+ hash_obj.update(agent_file.name.encode())
540
+ try:
541
+ hash_obj.update(agent_file.read_bytes())
542
+ except Exception as e:
543
+ logger.debug(f"Error reading {agent_file} for hash: {e}")
544
+
545
+ deployment_hash = hash_obj.hexdigest()
546
+
547
+ # Create state data
548
+ state_data = {
549
+ "version": __version__,
550
+ "agent_count": agent_count,
551
+ "deployment_hash": deployment_hash,
552
+ "deployed_at": time.time(),
553
+ }
554
+
555
+ # Ensure directory exists
556
+ state_file.parent.mkdir(parents=True, exist_ok=True)
557
+
558
+ # Write state file
559
+ state_file.write_text(json.dumps(state_data, indent=2))
560
+ logger.debug(
561
+ f"Saved deployment state after reconciliation: {agent_count} agents"
562
+ )
563
+
564
+ except Exception as e:
565
+ # Non-critical error - log but don't fail startup
566
+ logger.debug(f"Failed to save deployment state: {e}")
567
+
568
+
481
569
  def sync_remote_agents_on_startup(force_sync: bool = False):
482
570
  """
483
571
  Synchronize agent templates from remote sources on startup.
@@ -640,6 +728,12 @@ def sync_remote_agents_on_startup(force_sync: bool = False):
640
728
  )
641
729
  print(" Run with --verbose for detailed error information.\n")
642
730
 
731
+ # Save deployment state to prevent duplicate deployment in ClaudeRunner
732
+ # This ensures setup_agents() skips deployment since we already reconciled
733
+ _save_deployment_state_after_reconciliation(
734
+ agent_result=agent_result, project_path=project_path
735
+ )
736
+
643
737
  except Exception as e:
644
738
  # Deployment failure shouldn't block startup
645
739
  from ..core.logger import get_logger
@@ -214,8 +214,12 @@ class ClaudeRunner:
214
214
  )
215
215
 
216
216
  def _get_deployment_state_path(self) -> Path:
217
- """Get path to deployment state file."""
218
- return Path.cwd() / ".claude-mpm" / "deployment-state.json"
217
+ """Get path to deployment state file.
218
+
219
+ CRITICAL: Must match path used by startup.py::_save_deployment_state_after_reconciliation()
220
+ Located at: .claude-mpm/cache/deployment_state.json
221
+ """
222
+ return Path.cwd() / ".claude-mpm" / "cache" / "deployment_state.json"
219
223
 
220
224
  def _calculate_deployment_hash(self, agents_dir: Path) -> str:
221
225
  """Calculate hash of all agent files for change detection.
@@ -332,14 +336,15 @@ class ClaudeRunner:
332
336
  """Deploy native agents to .claude/agents/."""
333
337
  try:
334
338
  # Check if agents are already deployed and up-to-date
339
+ # This detects if reconciliation already ran during startup
335
340
  if self._check_deployment_state():
336
341
  agents_dir = Path.cwd() / ".claude" / "agents"
337
342
  agent_count = len(list(agents_dir.glob("*.md")))
338
- print(f"✓ Agents: {agent_count} cached")
343
+ # Silent return - reconciliation already logged deployment
339
344
  if self.project_logger:
340
345
  self.project_logger.log_system(
341
- f"Agents already deployed: {agent_count} cached",
342
- level="INFO",
346
+ f"Agents already deployed via reconciliation: {agent_count} agents",
347
+ level="DEBUG",
343
348
  component="deployment",
344
349
  )
345
350
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 5.6.16
3
+ Version: 5.6.18
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
2
- claude_mpm/VERSION,sha256=skzn24lo2CR2l5t6pUqVy6HhEUWd0Zzrlmq5Zmoh53w,7
2
+ claude_mpm/VERSION,sha256=PpRjpQ0ZyEXfEuMQSDx-5ZFFR07Dgt649GTI-_b7Xyk,7
3
3
  claude_mpm/__init__.py,sha256=AGfh00BHKvLYD-UVFw7qbKtl7NMRIzRXOWw7vEuZ-h4,2214
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=pz3lTrZZR5HhV3eZzYtIbtBwWo7iM6pkBHP_ixxmI6Y,6827
@@ -42,7 +42,7 @@ claude_mpm/cli/chrome_devtools_installer.py,sha256=efA_ZX1iR3oaJi3222079BQw6DEG8
42
42
  claude_mpm/cli/executor.py,sha256=eerqDVszBfTm8N2FgreLr-132Jb9BVZGNrrukvb_b-I,15106
43
43
  claude_mpm/cli/helpers.py,sha256=CypEhw0tbNH6_GzVTaQdi4w7ThCWO43Ep92YbJzPR4I,3638
44
44
  claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
45
- claude_mpm/cli/startup.py,sha256=q0q4ixGbboysdils2ptnEUll4f0iMooX0g2briB77P0,63711
45
+ claude_mpm/cli/startup.py,sha256=NtfKcGY3F7JnPqg19xMstV6h8i6gKLWTT2JteAx50E4,67175
46
46
  claude_mpm/cli/startup_display.py,sha256=KI4GZ0uVoK7FXeK5jsS4JAyaKaKf5rCkY3h5tNeEY7M,17209
47
47
  claude_mpm/cli/startup_logging.py,sha256=wHokzcCA0AJPxAqFrpY5PMOBh1iOhdhgP1gY1OvD0gY,29392
48
48
  claude_mpm/cli/utils.py,sha256=5e3v-ow1gd-5nlad9OWCsL-3SRJcPjBJ9HS3zygwkiQ,8988
@@ -271,7 +271,7 @@ claude_mpm/core/agent_session_manager.py,sha256=F10LS-nyTQxzMP3fkhbI94klsJy5xpSA
271
271
  claude_mpm/core/api_validator.py,sha256=zxeUykC2asy1KwHBDu5w3Eoo64E51PJyNe4PT7CTJf0,12282
272
272
  claude_mpm/core/base_service.py,sha256=4Zrt-vQ6g_KVk4hEfvd4QccuItYoOf7wUHCimIW6zJQ,29953
273
273
  claude_mpm/core/cache.py,sha256=orh8B40oYnRRGmXdANR4P4f-KVMIHV0vg7vrsemk0no,17232
274
- claude_mpm/core/claude_runner.py,sha256=Mxly26VD9XVOj_gAGbOb_1ZMdsMebakx3S9tv4kN6Gk,39361
274
+ claude_mpm/core/claude_runner.py,sha256=41qTAA9rrtS33Ta_FHsyjcn7TSh0Zs7i_8oBMHWxQuI,39649
275
275
  claude_mpm/core/config.py,sha256=0R1ZLdwxTM2N3-uIBgcbr37jDiEe-G7h7x4YmYIVit0,43385
276
276
  claude_mpm/core/config_aliases.py,sha256=QpNNECkTY4TYYAhVlFZvB-msPnZrui90g19u0-v0HDE,9703
277
277
  claude_mpm/core/config_constants.py,sha256=MEF35Y2Lj5FMzRdhgSgZrZeTzHfCzistPGZVY8INta4,10073
@@ -1128,10 +1128,10 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
1128
1128
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
1129
1129
  claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
1130
1130
  claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
1131
- claude_mpm-5.6.16.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
1132
- claude_mpm-5.6.16.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
1133
- claude_mpm-5.6.16.dist-info/METADATA,sha256=jWxRHG_53geY6q4TUr7ZOdSEY3bYBJGVPmlc_vgDQcc,15245
1134
- claude_mpm-5.6.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1135
- claude_mpm-5.6.16.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
1136
- claude_mpm-5.6.16.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
1137
- claude_mpm-5.6.16.dist-info/RECORD,,
1131
+ claude_mpm-5.6.18.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
1132
+ claude_mpm-5.6.18.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
1133
+ claude_mpm-5.6.18.dist-info/METADATA,sha256=iY6Kyv52jHootEtQ0iciyiF4_ji9kWh1MGrPxFNtdhM,15245
1134
+ claude_mpm-5.6.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1135
+ claude_mpm-5.6.18.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
1136
+ claude_mpm-5.6.18.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
1137
+ claude_mpm-5.6.18.dist-info/RECORD,,