meshcode 2.10.15__tar.gz → 2.10.17__tar.gz

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.
Files changed (32) hide show
  1. {meshcode-2.10.15 → meshcode-2.10.17}/PKG-INFO +1 -1
  2. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/__init__.py +1 -1
  3. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/server.py +47 -29
  4. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.10.15 → meshcode-2.10.17}/pyproject.toml +1 -1
  6. {meshcode-2.10.15 → meshcode-2.10.17}/README.md +0 -0
  7. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/ascii_art.py +0 -0
  8. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/cli.py +0 -0
  9. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/comms_v4.py +0 -0
  10. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/invites.py +0 -0
  11. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/launcher.py +0 -0
  12. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/launcher_install.py +0 -0
  13. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/__init__.py +0 -0
  14. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/__main__.py +0 -0
  15. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/backend.py +0 -0
  16. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/realtime.py +0 -0
  17. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/test_backend.py +0 -0
  18. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  19. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  20. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/preferences.py +0 -0
  21. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/protocol_v2.py +0 -0
  22. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/run_agent.py +0 -0
  23. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/secrets.py +0 -0
  24. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/self_update.py +0 -0
  25. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode/setup_clients.py +0 -0
  26. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode.egg-info/SOURCES.txt +0 -0
  27. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode.egg-info/dependency_links.txt +0 -0
  28. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode.egg-info/entry_points.txt +0 -0
  29. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode.egg-info/requires.txt +0 -0
  30. {meshcode-2.10.15 → meshcode-2.10.17}/meshcode.egg-info/top_level.txt +0 -0
  31. {meshcode-2.10.15 → meshcode-2.10.17}/setup.cfg +0 -0
  32. {meshcode-2.10.15 → meshcode-2.10.17}/tests/test_status_enum_coverage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.15
3
+ Version: 2.10.17
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -1,2 +1,2 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.10.15"
2
+ __version__ = "2.10.17"
@@ -22,6 +22,14 @@ from typing import Any, Dict, List, Optional, Union
22
22
 
23
23
  from meshcode import __version__ as _SDK_VERSION
24
24
 
25
+ # ── CRITICAL: Protect stdout for MCP JSON-RPC protocol ──────────
26
+ # MCP uses stdout exclusively for JSON-RPC. ANY stray print() to stdout
27
+ # corrupts the stream and causes Claude Code to kill the connection.
28
+ # Save the real stdout for FastMCP, then redirect sys.stdout to stderr
29
+ # so all print() calls (ours + third-party libs) go to stderr safely.
30
+ _REAL_STDOUT = sys.stdout # FastMCP will use this via mcp.run()
31
+ sys.stdout = sys.stderr # All print() now goes to stderr
32
+
25
33
 
26
34
  # ── Agent color for terminal logs (pure ANSI, zero tokens) ──────
27
35
  _ANSI_COLORS = [
@@ -77,11 +85,11 @@ def _mc_log(msg: str, level: str = "info") -> None:
77
85
  c = _agent_color(agent) if agent else "\033[36m"
78
86
  prefix = f"{c}{_ANSI_BOLD}[meshcode-mcp]{_ANSI_RESET}"
79
87
  if level == "error":
80
- print(f"{prefix} \033[91mERROR:{_ANSI_RESET} {msg}", file=sys.stderr)
88
+ print(f"{prefix} \033[91mERROR:{_ANSI_RESET} {msg}", "warn")
81
89
  elif level == "warn":
82
- print(f"{prefix} \033[33mWARNING:{_ANSI_RESET} {msg}", file=sys.stderr)
90
+ print(f"{prefix} \033[33mWARNING:{_ANSI_RESET} {msg}", "warn")
83
91
  else:
84
- print(f"{prefix} {c}{msg}{_ANSI_RESET}", file=sys.stderr)
92
+ print(f"{prefix} {c}{msg}{_ANSI_RESET}", "warn")
85
93
 
86
94
 
87
95
  # ============================================================
@@ -378,7 +386,7 @@ def _get_api_key() -> str:
378
386
  _API_KEY_CACHE = kc_val
379
387
  return kc_val
380
388
  except Exception as e:
381
- _mc_log(f" keychain lookup failed for profile '{profile}': {e}", file=sys.stderr)
389
+ _mc_log(f" keychain lookup failed for profile '{profile}': {e}", "warn")
382
390
  _API_KEY_CACHE = ""
383
391
  return ""
384
392
 
@@ -403,17 +411,17 @@ if not _PROJECT_ID:
403
411
  _PROJECT_ID = _r["project_id"]
404
412
  break
405
413
  elif isinstance(_r, dict) and _r.get("error"):
406
- _mc_log(f" mc_resolve_project: {_r['error']}", file=sys.stderr)
414
+ _mc_log(f" mc_resolve_project: {_r['error']}", "warn")
407
415
  except Exception as _e:
408
- _mc_log(f" mc_resolve_project failed: {_e}", file=sys.stderr)
416
+ _mc_log(f" mc_resolve_project failed: {_e}", "warn")
409
417
  if not _PROJECT_ID:
410
418
  _PROJECT_ID = be.get_project_id(PROJECT_NAME)
411
419
  if _PROJECT_ID:
412
420
  break
413
421
  if _boot_attempt < _BOOT_MAX_RETRIES - 1:
414
422
  _wait = _BOOT_BACKOFF[_boot_attempt]
415
- _mc_log(f" project resolution failed (attempt {_boot_attempt+1}/{_BOOT_MAX_RETRIES}), retrying in {_wait}s...", file=sys.stderr)
416
- _time.sleep(_wait)
423
+ _mc_log(f" project resolution failed (attempt {_boot_attempt+1}/{_BOOT_MAX_RETRIES}), retrying in {_wait}s...", "warn")
424
+ import time; time.sleep(_wait)
417
425
  if not _PROJECT_ID:
418
426
  _mc_log(f"project '{PROJECT_NAME}' not found after {_BOOT_MAX_RETRIES} attempts (check MESHCODE_KEYCHAIN_PROFILE / MESHCODE_API_KEY)", "error")
419
427
  sys.exit(2)
@@ -429,7 +437,7 @@ except Exception:
429
437
 
430
438
  _register_result = be.register_agent(PROJECT_NAME, AGENT_NAME, AGENT_ROLE or "MCP-connected agent", api_key=_get_api_key())
431
439
  if isinstance(_register_result, dict) and _register_result.get("error"):
432
- _mc_log(f" register failed: {_register_result['error']}", file=sys.stderr)
440
+ _mc_log(f" register failed: {_register_result['error']}", "warn")
433
441
 
434
442
  # ── Fetch profile color from dashboard (single source of truth) ──
435
443
  try:
@@ -463,7 +471,7 @@ def _flip_status(status: str, task: str = "") -> bool:
463
471
  return False
464
472
 
465
473
  if not _flip_status("idle", ""):
466
- _mc_log(f" could not flip status to idle", file=sys.stderr)
474
+ _mc_log(f" could not flip status to idle", "warn")
467
475
 
468
476
 
469
477
  # ============================================================
@@ -628,7 +636,7 @@ def _acquire_lease() -> bool:
628
636
  })
629
637
  except Exception as e:
630
638
  # Non-fatal: RPC might not exist on older servers.
631
- _mc_log(f"stale-lease pre-clean skipped: {e}", file=sys.stderr)
639
+ _mc_log(f"stale-lease pre-clean skipped: {e}", "warn")
632
640
  for attempt in range(3):
633
641
  try:
634
642
  r = be.sb_rpc("mc_acquire_agent_lease", {
@@ -680,14 +688,14 @@ def _acquire_lease() -> bool:
680
688
  _mc_log(f"Could not start — agent '{AGENT_NAME}' is running in another window.", "error")
681
689
  _mc_log("Close the other window first, or use a different agent name.", "error")
682
690
  return False
683
- _mc_log(f"lease attempt {attempt+1}: {r.get('error')}", file=sys.stderr)
691
+ _mc_log(f"lease attempt {attempt+1}: {r.get('error')}", "warn")
684
692
  else:
685
693
  return True
686
694
  except Exception as e:
687
- _mc_log(f"lease attempt {attempt+1} failed: {e}", file=sys.stderr)
695
+ _mc_log(f"lease attempt {attempt+1} failed: {e}", "warn")
688
696
  if attempt < 2:
689
697
  _time.sleep(2)
690
- _mc_log(f" lease failed after 3 attempts — proceeding anyway", file=sys.stderr)
698
+ _mc_log(f" lease failed after 3 attempts — proceeding anyway", "warn")
691
699
  return True
692
700
 
693
701
  if not _acquire_lease():
@@ -705,7 +713,7 @@ def _boot_diagnostic() -> None:
705
713
  be.sb_select("mc_projects", f"id=eq.{_PROJECT_ID}", limit=1)
706
714
  checks_passed += 1
707
715
  except Exception as e:
708
- print(f"[meshcode] BOOT CHECK FAILED: Supabase API unreachable ({e}). Fix: check network/VPN.", file=sys.stderr)
716
+ print(f"[meshcode] BOOT CHECK FAILED: Supabase API unreachable ({e}). Fix: check network/VPN.", "warn")
709
717
 
710
718
  # Check 2: Lease valid
711
719
  try:
@@ -715,11 +723,11 @@ def _boot_diagnostic() -> None:
715
723
  if agent.get("instance_id") == _INSTANCE_ID:
716
724
  checks_passed += 1
717
725
  else:
718
- print(f"[meshcode] BOOT CHECK FAILED: Lease mismatch — expected {_INSTANCE_ID}, got {agent.get('instance_id')}. Fix: restart agent.", file=sys.stderr)
726
+ print(f"[meshcode] BOOT CHECK FAILED: Lease mismatch — expected {_INSTANCE_ID}, got {agent.get('instance_id')}. Fix: restart agent.", "warn")
719
727
  else:
720
- print(f"[meshcode] BOOT CHECK FAILED: Agent '{AGENT_NAME}' not found in project. Fix: register agent first.", file=sys.stderr)
728
+ print(f"[meshcode] BOOT CHECK FAILED: Agent '{AGENT_NAME}' not found in project. Fix: register agent first.", "warn")
721
729
  except Exception as e:
722
- print(f"[meshcode] BOOT CHECK FAILED: Could not verify lease ({e}).", file=sys.stderr)
730
+ print(f"[meshcode] BOOT CHECK FAILED: Could not verify lease ({e}).", "warn")
723
731
 
724
732
  # Check 3: Heartbeat recent
725
733
  try:
@@ -728,7 +736,7 @@ def _boot_diagnostic() -> None:
728
736
  if hb:
729
737
  checks_passed += 1
730
738
  else:
731
- print(f"[meshcode] BOOT CHECK WARNING: No heartbeat recorded yet.", file=sys.stderr)
739
+ print(f"[meshcode] BOOT CHECK WARNING: No heartbeat recorded yet.", "warn")
732
740
  else:
733
741
  checks_passed += 1 # skip if no agent data
734
742
  except Exception:
@@ -745,9 +753,9 @@ def _boot_diagnostic() -> None:
745
753
  checks_passed += 1 # non-critical
746
754
 
747
755
  if checks_passed == checks_total:
748
- print(f"[meshcode] All boot checks passed ({checks_passed}/{checks_total}).", file=sys.stderr)
756
+ print(f"[meshcode] All boot checks passed ({checks_passed}/{checks_total}).", "warn")
749
757
  else:
750
- print(f"[meshcode] Boot checks: {checks_passed}/{checks_total} passed. Agent starting anyway.", file=sys.stderr)
758
+ print(f"[meshcode] Boot checks: {checks_passed}/{checks_total} passed. Agent starting anyway.", "warn")
751
759
 
752
760
 
753
761
  _boot_diagnostic()
@@ -794,7 +802,7 @@ def _log_crash_to_db(reason: str = "unknown", error_detail: str = "") -> None:
794
802
  f"crashed: {reason[:100]}", api_key=_get_api_key())
795
803
  except Exception:
796
804
  pass
797
- _mc_log(f" crash logged: {reason}", file=sys.stderr)
805
+ _mc_log(f" crash logged: {reason}", "warn")
798
806
 
799
807
 
800
808
  def _on_exit() -> None:
@@ -1454,9 +1462,9 @@ try:
1454
1462
  elif isinstance(_ls_val, str):
1455
1463
  _LAST_SEEN_TS = _ls_val
1456
1464
  if _LAST_SEEN_TS:
1457
- print(f"[meshcode] Restored last_seen={_LAST_SEEN_TS} from mesh memory.", file=sys.stderr)
1465
+ print(f"[meshcode] Restored last_seen={_LAST_SEEN_TS} from mesh memory.", "warn")
1458
1466
  except Exception as _e:
1459
- print(f"[meshcode] Could not restore last_seen: {_e}", file=sys.stderr)
1467
+ print(f"[meshcode] Could not restore last_seen: {_e}", "warn")
1460
1468
 
1461
1469
 
1462
1470
  def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
@@ -2616,7 +2624,7 @@ def _auto_update() -> None:
2616
2624
  return
2617
2625
 
2618
2626
  # 3. Install the new version (blocking, 60s timeout)
2619
- print(f"[meshcode] Updating {current} → {latest}...", file=sys.stderr)
2627
+ print(f"[meshcode] Updating {current} → {latest}...", "warn")
2620
2628
  try:
2621
2629
  result = subprocess.run(
2622
2630
  [sys.executable, "-m", "pip", "install", "--upgrade",
@@ -2633,8 +2641,14 @@ def _auto_update() -> None:
2633
2641
  log.debug(f"[meshcode] Auto-update failed: {e}")
2634
2642
  return
2635
2643
 
2636
- # 4. Re-exec to load the new code
2637
- print(f"[meshcode] Updated to {latest}, restarting...", file=sys.stderr)
2644
+ # 4. In MCP mode, NEVER re-exec it kills the stdio pipe to Claude Code.
2645
+ # The new version will load on the next clean boot.
2646
+ if os.environ.get("MESHCODE_MCP_SERVE") == "1":
2647
+ print(f"[meshcode] Updated {current} → {latest}. Will load on next boot (MCP mode — cannot restart).", "warn")
2648
+ return
2649
+
2650
+ # CLI mode: safe to re-exec
2651
+ print(f"[meshcode] Updated to {latest}, restarting...", "warn")
2638
2652
  os.environ["MESHCODE_UPDATED"] = "1"
2639
2653
  try:
2640
2654
  os.execv(sys.executable, [sys.executable] + sys.argv)
@@ -2655,6 +2669,10 @@ def run_server():
2655
2669
  file=sys.stderr,
2656
2670
  )
2657
2671
  try:
2672
+ # Restore real stdout for FastMCP's JSON-RPC transport.
2673
+ # sys.stdout was redirected to stderr at module load to prevent
2674
+ # accidental stdout writes from corrupting the MCP protocol.
2675
+ sys.stdout = _REAL_STDOUT
2658
2676
  mcp.run()
2659
2677
  except KeyboardInterrupt:
2660
2678
  _log_crash_to_db("keyboard_interrupt", "User stopped the agent")
@@ -2665,6 +2683,6 @@ def run_server():
2665
2683
  import traceback as _tb
2666
2684
  tb_str = _tb.format_exc()
2667
2685
  _log_crash_to_db("unhandled_exception", f"{type(e).__name__}: {e}\n{tb_str}")
2668
- print(f"[meshcode-mcp] FATAL: {e}", file=sys.stderr)
2669
- print(f"[meshcode-mcp] Stack trace logged to mc_agent_crash_logs", file=sys.stderr)
2686
+ print(f"[meshcode-mcp] FATAL: {e}", "warn")
2687
+ print(f"[meshcode-mcp] Stack trace logged to mc_agent_crash_logs", "warn")
2670
2688
  sys.exit(1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.15
3
+ Version: 2.10.17
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.10.15"
7
+ version = "2.10.17"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes
File without changes