claude-mpm 5.0.2__py3-none-any.whl → 5.1.9__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 (76) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  3. claude_mpm/agents/PM_INSTRUCTIONS.md +1176 -909
  4. claude_mpm/agents/base_agent_loader.py +10 -35
  5. claude_mpm/agents/frontmatter_validator.py +68 -0
  6. claude_mpm/agents/templates/circuit-breakers.md +293 -44
  7. claude_mpm/cli/__init__.py +0 -1
  8. claude_mpm/cli/commands/__init__.py +2 -0
  9. claude_mpm/cli/commands/agent_state_manager.py +64 -11
  10. claude_mpm/cli/commands/agents.py +446 -25
  11. claude_mpm/cli/commands/auto_configure.py +535 -233
  12. claude_mpm/cli/commands/configure.py +545 -89
  13. claude_mpm/cli/commands/postmortem.py +401 -0
  14. claude_mpm/cli/commands/run.py +1 -39
  15. claude_mpm/cli/commands/skills.py +322 -19
  16. claude_mpm/cli/interactive/agent_wizard.py +302 -195
  17. claude_mpm/cli/parsers/agents_parser.py +137 -0
  18. claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
  19. claude_mpm/cli/parsers/base_parser.py +4 -0
  20. claude_mpm/cli/parsers/skills_parser.py +7 -0
  21. claude_mpm/cli/startup.py +73 -32
  22. claude_mpm/commands/mpm-agents-auto-configure.md +2 -2
  23. claude_mpm/commands/mpm-agents-list.md +2 -2
  24. claude_mpm/commands/mpm-config-view.md +2 -2
  25. claude_mpm/commands/mpm-help.md +3 -0
  26. claude_mpm/commands/mpm-postmortem.md +123 -0
  27. claude_mpm/commands/mpm-session-resume.md +2 -2
  28. claude_mpm/commands/mpm-ticket-organize.md +2 -2
  29. claude_mpm/commands/mpm-ticket-view.md +2 -2
  30. claude_mpm/config/agent_presets.py +312 -82
  31. claude_mpm/config/skill_presets.py +392 -0
  32. claude_mpm/constants.py +1 -0
  33. claude_mpm/core/claude_runner.py +2 -25
  34. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  35. claude_mpm/core/interactive_session.py +19 -5
  36. claude_mpm/core/oneshot_session.py +16 -4
  37. claude_mpm/core/output_style_manager.py +173 -43
  38. claude_mpm/core/protocols/__init__.py +23 -0
  39. claude_mpm/core/protocols/runner_protocol.py +103 -0
  40. claude_mpm/core/protocols/session_protocol.py +131 -0
  41. claude_mpm/core/shared/singleton_manager.py +11 -4
  42. claude_mpm/core/system_context.py +38 -0
  43. claude_mpm/core/unified_agent_registry.py +129 -1
  44. claude_mpm/core/unified_config.py +22 -0
  45. claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
  46. claude_mpm/models/agent_definition.py +7 -0
  47. claude_mpm/services/agents/cache_git_manager.py +621 -0
  48. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +110 -3
  49. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +195 -1
  50. claude_mpm/services/agents/sources/git_source_sync_service.py +37 -5
  51. claude_mpm/services/analysis/__init__.py +25 -0
  52. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  53. claude_mpm/services/analysis/postmortem_service.py +765 -0
  54. claude_mpm/services/command_deployment_service.py +108 -5
  55. claude_mpm/services/core/base.py +7 -2
  56. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  57. claude_mpm/services/git/git_operations_service.py +8 -8
  58. claude_mpm/services/mcp_config_manager.py +75 -145
  59. claude_mpm/services/mcp_gateway/core/process_pool.py +22 -16
  60. claude_mpm/services/mcp_service_verifier.py +6 -3
  61. claude_mpm/services/monitor/daemon.py +28 -8
  62. claude_mpm/services/monitor/daemon_manager.py +96 -19
  63. claude_mpm/services/project/project_organizer.py +4 -0
  64. claude_mpm/services/runner_configuration_service.py +16 -3
  65. claude_mpm/services/session_management_service.py +16 -4
  66. claude_mpm/utils/agent_filters.py +288 -0
  67. claude_mpm/utils/gitignore.py +3 -0
  68. claude_mpm/utils/migration.py +372 -0
  69. claude_mpm/utils/progress.py +5 -1
  70. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/METADATA +69 -8
  71. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/RECORD +76 -62
  72. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  73. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/WHEEL +0 -0
  74. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/entry_points.txt +0 -0
  75. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/licenses/LICENSE +0 -0
  76. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/top_level.txt +0 -0
@@ -167,6 +167,16 @@ class AgentsCommand(AgentCommand):
167
167
  "available": self._list_available_from_sources,
168
168
  # Agent discovery with rich filtering (Phase 1: Discovery & Browsing)
169
169
  "discover": self._discover_agents,
170
+ # NEW: Collection-based agent management
171
+ "list-collections": self._list_collections,
172
+ "deploy-collection": self._deploy_collection,
173
+ "list-by-collection": self._list_by_collection,
174
+ # Cache git management commands
175
+ "cache-status": self._cache_status,
176
+ "cache-pull": self._cache_pull,
177
+ "cache-push": self._cache_push,
178
+ "cache-sync": self._cache_sync,
179
+ "cache-commit": self._cache_commit,
170
180
  }
171
181
 
172
182
  if args.agents_command in command_map:
@@ -551,34 +561,63 @@ class AgentsCommand(AgentCommand):
551
561
  return CommandResult.error_result(f"Error discovering agents: {e}")
552
562
 
553
563
  def _deploy_agents(self, args, force=False) -> CommandResult:
554
- """Deploy both system and project agents, or deploy by preset."""
564
+ """Deploy agents using two-phase sync: cache deploy.
565
+
566
+ Phase 3 Integration (1M-486): Uses Git sync service for deployment.
567
+ - Phase 1: Sync agents to ~/.claude-mpm/cache/remote-agents/ (if needed)
568
+ - Phase 2: Deploy from cache to project .claude-mpm/agents/
569
+
570
+ This replaces the old single-tier deployment with a multi-project
571
+ architecture where one cache serves multiple project deployments.
572
+ """
555
573
  try:
556
- # Handle preset deployment
574
+ # Handle preset deployment (uses different path)
557
575
  if hasattr(args, "preset") and args.preset:
558
576
  return self._deploy_preset(args)
559
577
 
560
- # Deploy system agents
561
- system_result = self.deployment_service.deploy_system_agents(force=force)
578
+ from ...services.agents.sources.git_source_sync_service import (
579
+ GitSourceSyncService,
580
+ )
581
+
582
+ # Initialize git sync service
583
+ git_sync = GitSourceSyncService()
584
+ project_dir = Path.cwd()
585
+
586
+ self.logger.info("Phase 1: Syncing agents to cache...")
587
+
588
+ # Sync to cache (downloads from GitHub if needed)
589
+ sync_result = git_sync.sync_repository(force=force)
590
+
591
+ if not sync_result.get("synced"):
592
+ error_msg = sync_result.get("error", "Unknown sync error")
593
+ self.logger.error(f"Sync failed: {error_msg}")
594
+ return CommandResult.error_result(f"Sync failed: {error_msg}")
595
+
596
+ self.logger.info(
597
+ f"Phase 1 complete: {sync_result.get('agent_count', 0)} agents in cache"
598
+ )
599
+ self.logger.info(f"Phase 2: Deploying agents to {project_dir}...")
562
600
 
563
- # Deploy project agents if they exist
564
- project_result = self.deployment_service.deploy_project_agents(force=force)
601
+ # Deploy from cache to project directory
602
+ deploy_result = git_sync.deploy_agents_to_project(
603
+ project_dir=project_dir,
604
+ agent_list=None, # Deploy all cached agents
605
+ force=force,
606
+ )
565
607
 
566
- # Combine results
608
+ # Format combined results for output
567
609
  combined_result = {
568
- "deployed_count": system_result.get("deployed_count", 0)
569
- + project_result.get("deployed_count", 0),
570
- "deployed": system_result.get("deployed", [])
571
- + project_result.get("deployed", []),
572
- "updated_count": system_result.get("updated_count", 0)
573
- + project_result.get("updated_count", 0),
574
- "updated": system_result.get("updated", [])
575
- + project_result.get("updated", []),
576
- "skipped": system_result.get("skipped", [])
577
- + project_result.get("skipped", []),
578
- "errors": system_result.get("errors", [])
579
- + project_result.get("errors", []),
580
- "target_dir": system_result.get("target_dir")
581
- or project_result.get("target_dir"),
610
+ "deployed_count": len(deploy_result.get("deployed", []))
611
+ + len(deploy_result.get("updated", [])),
612
+ "deployed": deploy_result.get("deployed", []),
613
+ "updated": deploy_result.get("updated", []),
614
+ "skipped": deploy_result.get("skipped", []),
615
+ "errors": deploy_result.get("failed", []),
616
+ "target_dir": deploy_result.get("deployment_dir", ""),
617
+ "sync_info": {
618
+ "cached_agents": sync_result.get("agent_count", 0),
619
+ "cache_dir": sync_result.get("cache_dir", ""),
620
+ },
582
621
  }
583
622
 
584
623
  output_format = self._get_output_format(args)
@@ -589,12 +628,15 @@ class AgentsCommand(AgentCommand):
589
628
  )
590
629
  print(formatted)
591
630
 
631
+ success_count = len(deploy_result["deployed"]) + len(
632
+ deploy_result["updated"]
633
+ )
592
634
  return CommandResult.success_result(
593
- f"Deployed {combined_result['deployed_count']} agents",
635
+ f"Deployed {success_count} agents from cache",
594
636
  data={
595
- "system_agents": system_result,
596
- "project_agents": project_result,
597
- "total_deployed": combined_result["deployed_count"],
637
+ "sync_result": sync_result,
638
+ "deploy_result": deploy_result,
639
+ "total_deployed": success_count,
598
640
  },
599
641
  )
600
642
 
@@ -2119,6 +2161,385 @@ class AgentsCommand(AgentCommand):
2119
2161
  self.logger.error(f"Error in auto-configure: {e}", exc_info=True)
2120
2162
  return CommandResult.error_result(f"Error in auto-configure: {e}")
2121
2163
 
2164
+ def _list_collections(self, args) -> CommandResult:
2165
+ """List all available agent collections.
2166
+
2167
+ NEW: Shows all collections with agent counts and metadata.
2168
+ Enables discovery of available agent collections before deployment.
2169
+ """
2170
+ try:
2171
+ from pathlib import Path
2172
+
2173
+ from ...services.agents.deployment.remote_agent_discovery_service import (
2174
+ RemoteAgentDiscoveryService,
2175
+ )
2176
+
2177
+ # Get remote agents cache directory
2178
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2179
+
2180
+ if not cache_dir.exists():
2181
+ return CommandResult.error_result(
2182
+ "No remote agent collections found. Run 'claude-mpm agents deploy' first."
2183
+ )
2184
+
2185
+ # Use RemoteAgentDiscoveryService to list collections
2186
+ remote_service = RemoteAgentDiscoveryService(cache_dir)
2187
+ collections = remote_service.list_collections()
2188
+
2189
+ if not collections:
2190
+ return CommandResult.success_result(
2191
+ "No agent collections found in cache.", data={"collections": []}
2192
+ )
2193
+
2194
+ # Format output
2195
+ output_lines = ["Available Agent Collections:\n"]
2196
+ for collection in collections:
2197
+ output_lines.append(
2198
+ f" • {collection['collection_id']} ({collection['agent_count']} agents)"
2199
+ )
2200
+
2201
+ return CommandResult.success_result(
2202
+ "\n".join(output_lines), data={"collections": collections}
2203
+ )
2204
+
2205
+ except Exception as e:
2206
+ self.logger.error(f"Error listing collections: {e}", exc_info=True)
2207
+ return CommandResult.error_result(f"Error listing collections: {e}")
2208
+
2209
+ def _deploy_collection(self, args) -> CommandResult:
2210
+ """Deploy all agents from a specific collection.
2211
+
2212
+ NEW: Enables bulk deployment of all agents from a named collection.
2213
+ Useful for deploying entire agent sets at once.
2214
+ """
2215
+ try:
2216
+ from pathlib import Path
2217
+
2218
+ from ...services.agents.deployment.multi_source_deployment_service import (
2219
+ MultiSourceAgentDeploymentService,
2220
+ )
2221
+
2222
+ collection_id = args.collection_id
2223
+
2224
+ # Get agents from collection
2225
+ service = MultiSourceAgentDeploymentService()
2226
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2227
+ agents = service.get_agents_by_collection(collection_id, cache_dir)
2228
+
2229
+ if not agents:
2230
+ return CommandResult.error_result(
2231
+ f"No agents found in collection '{collection_id}'"
2232
+ )
2233
+
2234
+ # Dry run mode
2235
+ if getattr(args, "dry_run", False):
2236
+ agent_names = [
2237
+ agent.get("metadata", {}).get("name", "Unknown") for agent in agents
2238
+ ]
2239
+ output = f"Would deploy {len(agents)} agents from collection '{collection_id}':\n"
2240
+ for name in agent_names:
2241
+ output += f" • {name}\n"
2242
+ return CommandResult.success_result(
2243
+ output,
2244
+ data={"collection_id": collection_id, "agent_count": len(agents)},
2245
+ )
2246
+
2247
+ # Deploy agents
2248
+ # TODO: Implement actual deployment logic using deployment service
2249
+ # For now, show what would be deployed
2250
+ return CommandResult.success_result(
2251
+ f"Deployment of collection '{collection_id}' would deploy {len(agents)} agents.\n"
2252
+ f"(Full deployment implementation pending)",
2253
+ data={
2254
+ "collection_id": collection_id,
2255
+ "agent_count": len(agents),
2256
+ "status": "pending_implementation",
2257
+ },
2258
+ )
2259
+
2260
+ except Exception as e:
2261
+ self.logger.error(f"Error deploying collection: {e}", exc_info=True)
2262
+ return CommandResult.error_result(f"Error deploying collection: {e}")
2263
+
2264
+ def _list_by_collection(self, args) -> CommandResult:
2265
+ """List agents from a specific collection.
2266
+
2267
+ NEW: Shows detailed information about agents in a collection.
2268
+ Supports multiple output formats (table, json, yaml).
2269
+ """
2270
+ try:
2271
+ import json as json_lib
2272
+ from pathlib import Path
2273
+
2274
+ from ...services.agents.deployment.multi_source_deployment_service import (
2275
+ MultiSourceAgentDeploymentService,
2276
+ )
2277
+
2278
+ collection_id = args.collection_id
2279
+ output_format = getattr(args, "format", "table")
2280
+
2281
+ # Get agents from collection
2282
+ service = MultiSourceAgentDeploymentService()
2283
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2284
+ agents = service.get_agents_by_collection(collection_id, cache_dir)
2285
+
2286
+ if not agents:
2287
+ return CommandResult.error_result(
2288
+ f"No agents found in collection '{collection_id}'"
2289
+ )
2290
+
2291
+ # Format output based on requested format
2292
+ if output_format == "json":
2293
+ return CommandResult.success_result(
2294
+ json_lib.dumps(agents, indent=2),
2295
+ data={"collection_id": collection_id, "agents": agents},
2296
+ )
2297
+ if output_format == "yaml":
2298
+ try:
2299
+ import yaml
2300
+
2301
+ return CommandResult.success_result(
2302
+ yaml.dump(agents, default_flow_style=False),
2303
+ data={"collection_id": collection_id, "agents": agents},
2304
+ )
2305
+ except ImportError:
2306
+ return CommandResult.error_result(
2307
+ "YAML support not available (install PyYAML)"
2308
+ )
2309
+
2310
+ # Table format (default)
2311
+ output_lines = [f"Agents in collection '{collection_id}':\n"]
2312
+ for agent in agents:
2313
+ metadata = agent.get("metadata", {})
2314
+ name = metadata.get("name", "Unknown")
2315
+ description = metadata.get("description", "No description")
2316
+ version = agent.get("version", "unknown")
2317
+ output_lines.append(f" • {name} (v{version})")
2318
+ output_lines.append(f" {description}\n")
2319
+
2320
+ return CommandResult.success_result(
2321
+ "\n".join(output_lines),
2322
+ data={"collection_id": collection_id, "agent_count": len(agents)},
2323
+ )
2324
+
2325
+ except Exception as e:
2326
+ self.logger.error(f"Error listing collection agents: {e}", exc_info=True)
2327
+ return CommandResult.error_result(f"Error listing collection agents: {e}")
2328
+
2329
+ def _cache_status(self, args) -> CommandResult:
2330
+ """Show git status of agent cache.
2331
+
2332
+ Displays current branch, uncommitted changes, unpushed commits, and
2333
+ remote URL for the agent cache repository.
2334
+ """
2335
+ try:
2336
+ from ...services.agents.cache_git_manager import CacheGitManager
2337
+
2338
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2339
+ manager = CacheGitManager(cache_dir)
2340
+
2341
+ if not manager.is_git_repo():
2342
+ print("❌ Cache is not a git repository")
2343
+ print(f"\nCache location: {cache_dir}")
2344
+ print(
2345
+ "\n💡 This is expected if you haven't cloned the agents repository."
2346
+ )
2347
+ print(" The cache will be managed via HTTP sync instead.")
2348
+ return CommandResult.error_result("Cache is not a git repository")
2349
+
2350
+ status = manager.get_status()
2351
+ output_format = self._get_output_format(args)
2352
+
2353
+ if self._is_structured_format(output_format):
2354
+ formatted = (
2355
+ self._formatter.format_as_json(status)
2356
+ if str(output_format).lower() == OutputFormat.JSON
2357
+ else self._formatter.format_as_yaml(status)
2358
+ )
2359
+ print(formatted)
2360
+ return CommandResult.success_result(
2361
+ "Cache status retrieved", data=status
2362
+ )
2363
+
2364
+ # Text output
2365
+ print(f"\n📁 Cache: {manager.repo_path}")
2366
+ print(f"🌿 Branch: {status.get('branch', 'unknown')}")
2367
+
2368
+ if status.get("remote_url"):
2369
+ print(f"🔗 Remote: {status['remote_url']}")
2370
+
2371
+ # Show sync status
2372
+ ahead = status.get("ahead", 0)
2373
+ behind = status.get("behind", 0)
2374
+
2375
+ if ahead > 0:
2376
+ print(f"📤 Ahead of remote: {ahead} commit(s)")
2377
+ if behind > 0:
2378
+ print(f"📥 Behind remote: {behind} commit(s)")
2379
+
2380
+ if ahead == 0 and behind == 0:
2381
+ print("✅ In sync with remote")
2382
+
2383
+ # Show uncommitted changes
2384
+ uncommitted = status.get("uncommitted", [])
2385
+ if uncommitted:
2386
+ print(f"\n⚠️ Uncommitted changes: {len(uncommitted)}")
2387
+ for file in uncommitted[:10]: # Show max 10 files
2388
+ print(f" - {file}")
2389
+ if len(uncommitted) > 10:
2390
+ print(f" ... and {len(uncommitted) - 10} more")
2391
+ else:
2392
+ print("\n✅ No uncommitted changes")
2393
+
2394
+ # Overall status
2395
+ if status.get("is_clean"):
2396
+ print("\n✨ Cache is clean and up-to-date")
2397
+ else:
2398
+ print("\n💡 Run 'claude-mpm agents cache-sync' to sync with remote")
2399
+
2400
+ return CommandResult.success_result("Cache status displayed", data=status)
2401
+
2402
+ except Exception as e:
2403
+ self.logger.error(f"Error getting cache status: {e}", exc_info=True)
2404
+ return CommandResult.error_result(f"Error getting cache status: {e}")
2405
+
2406
+ def _cache_pull(self, args) -> CommandResult:
2407
+ """Pull latest agents from remote repository."""
2408
+ try:
2409
+ from ...services.agents.cache_git_manager import CacheGitManager
2410
+
2411
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2412
+ manager = CacheGitManager(cache_dir)
2413
+
2414
+ if not manager.is_git_repo():
2415
+ print("❌ Cache is not a git repository")
2416
+ return CommandResult.error_result("Cache is not a git repository")
2417
+
2418
+ branch = getattr(args, "branch", "main")
2419
+ print(f"🔄 Pulling latest changes from {branch}...")
2420
+
2421
+ success, msg = manager.pull_latest(branch)
2422
+
2423
+ if success:
2424
+ print(f"✅ {msg}")
2425
+ return CommandResult.success_result(msg)
2426
+ print(f"❌ {msg}")
2427
+ return CommandResult.error_result(msg)
2428
+
2429
+ except Exception as e:
2430
+ self.logger.error(f"Error pulling cache: {e}", exc_info=True)
2431
+ return CommandResult.error_result(f"Error pulling cache: {e}")
2432
+
2433
+ def _cache_commit(self, args) -> CommandResult:
2434
+ """Commit changes to cache repository."""
2435
+ try:
2436
+ from ...services.agents.cache_git_manager import CacheGitManager
2437
+
2438
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2439
+ manager = CacheGitManager(cache_dir)
2440
+
2441
+ if not manager.is_git_repo():
2442
+ print("❌ Cache is not a git repository")
2443
+ return CommandResult.error_result("Cache is not a git repository")
2444
+
2445
+ # Get commit message from args
2446
+ message = getattr(args, "message", None)
2447
+ if not message:
2448
+ # Default message
2449
+ message = "feat: update agents from local development"
2450
+
2451
+ print("💾 Committing changes...")
2452
+ success, msg = manager.commit_changes(message)
2453
+
2454
+ if success:
2455
+ print(f"✅ {msg}")
2456
+ print(f"\n💡 Commit message: {message}")
2457
+ return CommandResult.success_result(msg)
2458
+ print(f"❌ {msg}")
2459
+ return CommandResult.error_result(msg)
2460
+
2461
+ except Exception as e:
2462
+ self.logger.error(f"Error committing cache changes: {e}", exc_info=True)
2463
+ return CommandResult.error_result(f"Error committing cache changes: {e}")
2464
+
2465
+ def _cache_push(self, args) -> CommandResult:
2466
+ """Push local agent changes to remote."""
2467
+ try:
2468
+ from ...services.agents.cache_git_manager import CacheGitManager
2469
+
2470
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2471
+ manager = CacheGitManager(cache_dir)
2472
+
2473
+ if not manager.is_git_repo():
2474
+ print("❌ Cache is not a git repository")
2475
+ return CommandResult.error_result("Cache is not a git repository")
2476
+
2477
+ # Check for uncommitted changes
2478
+ if manager.has_uncommitted_changes():
2479
+ print("⚠️ You have uncommitted changes.")
2480
+ print("\n💡 Commit changes first with:")
2481
+ print(" claude-mpm agents cache-commit --message 'your message'")
2482
+
2483
+ # Ask if user wants to commit first
2484
+ auto_commit = getattr(args, "auto_commit", False)
2485
+ if auto_commit:
2486
+ print("\n📝 Auto-committing changes...")
2487
+ success, msg = manager.commit_changes("feat: update agents")
2488
+ if not success:
2489
+ print(f"❌ Commit failed: {msg}")
2490
+ return CommandResult.error_result(f"Commit failed: {msg}")
2491
+ print(f"✅ {msg}")
2492
+ else:
2493
+ return CommandResult.error_result(
2494
+ "Uncommitted changes detected. Commit first or use --auto-commit"
2495
+ )
2496
+
2497
+ # Push changes
2498
+ branch = getattr(args, "branch", "main")
2499
+ print(f"📤 Pushing changes to {branch}...")
2500
+
2501
+ success, msg = manager.push_changes(branch)
2502
+
2503
+ if success:
2504
+ print(f"✅ {msg}")
2505
+ return CommandResult.success_result(msg)
2506
+ print(f"❌ {msg}")
2507
+ return CommandResult.error_result(msg)
2508
+
2509
+ except Exception as e:
2510
+ self.logger.error(f"Error pushing cache: {e}", exc_info=True)
2511
+ return CommandResult.error_result(f"Error pushing cache: {e}")
2512
+
2513
+ def _cache_sync(self, args) -> CommandResult:
2514
+ """Full cache sync: pull, commit (if needed), push."""
2515
+ try:
2516
+ from ...services.agents.cache_git_manager import CacheGitManager
2517
+
2518
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2519
+ manager = CacheGitManager(cache_dir)
2520
+
2521
+ if not manager.is_git_repo():
2522
+ print("❌ Cache is not a git repository")
2523
+ return CommandResult.error_result("Cache is not a git repository")
2524
+
2525
+ print("🔄 Syncing cache with remote...\n")
2526
+
2527
+ success, msg = manager.sync_with_remote()
2528
+
2529
+ # Print detailed sync message
2530
+ print(msg)
2531
+
2532
+ if success:
2533
+ print("\n✨ Cache sync complete!")
2534
+ return CommandResult.success_result("Cache synced successfully")
2535
+
2536
+ print("\n❌ Cache sync failed. See details above.")
2537
+ return CommandResult.error_result("Cache sync failed")
2538
+
2539
+ except Exception as e:
2540
+ self.logger.error(f"Error syncing cache: {e}", exc_info=True)
2541
+ return CommandResult.error_result(f"Error syncing cache: {e}")
2542
+
2122
2543
 
2123
2544
  def manage_agents(args):
2124
2545
  """