meshcode 2.10.14__tar.gz → 2.10.16__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.14 → meshcode-2.10.16}/PKG-INFO +1 -1
  2. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/__init__.py +1 -1
  3. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/server.py +50 -27
  4. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.10.14 → meshcode-2.10.16}/pyproject.toml +1 -1
  6. {meshcode-2.10.14 → meshcode-2.10.16}/README.md +0 -0
  7. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/ascii_art.py +0 -0
  8. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/cli.py +0 -0
  9. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/comms_v4.py +0 -0
  10. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/invites.py +0 -0
  11. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/launcher.py +0 -0
  12. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/launcher_install.py +0 -0
  13. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/__init__.py +0 -0
  14. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/__main__.py +0 -0
  15. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/backend.py +0 -0
  16. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/realtime.py +0 -0
  17. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/test_backend.py +0 -0
  18. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  19. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  20. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/preferences.py +0 -0
  21. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/protocol_v2.py +0 -0
  22. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/run_agent.py +0 -0
  23. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/secrets.py +0 -0
  24. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/self_update.py +0 -0
  25. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode/setup_clients.py +0 -0
  26. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode.egg-info/SOURCES.txt +0 -0
  27. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode.egg-info/dependency_links.txt +0 -0
  28. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode.egg-info/entry_points.txt +0 -0
  29. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode.egg-info/requires.txt +0 -0
  30. {meshcode-2.10.14 → meshcode-2.10.16}/meshcode.egg-info/top_level.txt +0 -0
  31. {meshcode-2.10.14 → meshcode-2.10.16}/setup.cfg +0 -0
  32. {meshcode-2.10.14 → meshcode-2.10.16}/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.14
3
+ Version: 2.10.16
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.14"
2
+ __version__ = "2.10.16"
@@ -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 = [
@@ -67,16 +75,21 @@ def _agent_color(name: str) -> str:
67
75
 
68
76
 
69
77
  def _mc_log(msg: str, level: str = "info") -> None:
70
- """Colored [meshcode-mcp] log line. Uses agent color if available."""
78
+ """Colored [meshcode-mcp] log line. Uses agent color if available.
79
+
80
+ CRITICAL: Must write to stderr, NEVER stdout. MCP protocol uses stdout
81
+ for JSON-RPC — any non-JSON output to stdout corrupts the stream and
82
+ causes Claude Code to kill the connection.
83
+ """
71
84
  agent = os.environ.get("MESHCODE_AGENT", "")
72
85
  c = _agent_color(agent) if agent else "\033[36m"
73
86
  prefix = f"{c}{_ANSI_BOLD}[meshcode-mcp]{_ANSI_RESET}"
74
87
  if level == "error":
75
- print(f"{prefix} \033[91mERROR:{_ANSI_RESET} {msg}", "warn")
88
+ print(f"{prefix} \033[91mERROR:{_ANSI_RESET} {msg}", file=sys.stderr)
76
89
  elif level == "warn":
77
- print(f"{prefix} \033[33mWARNING:{_ANSI_RESET} {msg}", "warn")
90
+ print(f"{prefix} \033[33mWARNING:{_ANSI_RESET} {msg}", file=sys.stderr)
78
91
  else:
79
- print(f"{prefix} {c}{msg}{_ANSI_RESET}", "warn")
92
+ print(f"{prefix} {c}{msg}{_ANSI_RESET}", file=sys.stderr)
80
93
 
81
94
 
82
95
  # ============================================================
@@ -373,7 +386,7 @@ def _get_api_key() -> str:
373
386
  _API_KEY_CACHE = kc_val
374
387
  return kc_val
375
388
  except Exception as e:
376
- _mc_log(f" keychain lookup failed for profile '{profile}': {e}", "warn")
389
+ _mc_log(f" keychain lookup failed for profile '{profile}': {e}", file=sys.stderr)
377
390
  _API_KEY_CACHE = ""
378
391
  return ""
379
392
 
@@ -398,16 +411,16 @@ if not _PROJECT_ID:
398
411
  _PROJECT_ID = _r["project_id"]
399
412
  break
400
413
  elif isinstance(_r, dict) and _r.get("error"):
401
- _mc_log(f" mc_resolve_project: {_r['error']}", "warn")
414
+ _mc_log(f" mc_resolve_project: {_r['error']}", file=sys.stderr)
402
415
  except Exception as _e:
403
- _mc_log(f" mc_resolve_project failed: {_e}", "warn")
416
+ _mc_log(f" mc_resolve_project failed: {_e}", file=sys.stderr)
404
417
  if not _PROJECT_ID:
405
418
  _PROJECT_ID = be.get_project_id(PROJECT_NAME)
406
419
  if _PROJECT_ID:
407
420
  break
408
421
  if _boot_attempt < _BOOT_MAX_RETRIES - 1:
409
422
  _wait = _BOOT_BACKOFF[_boot_attempt]
410
- _mc_log(f" project resolution failed (attempt {_boot_attempt+1}/{_BOOT_MAX_RETRIES}), retrying in {_wait}s...", "warn")
423
+ _mc_log(f" project resolution failed (attempt {_boot_attempt+1}/{_BOOT_MAX_RETRIES}), retrying in {_wait}s...", file=sys.stderr)
411
424
  _time.sleep(_wait)
412
425
  if not _PROJECT_ID:
413
426
  _mc_log(f"project '{PROJECT_NAME}' not found after {_BOOT_MAX_RETRIES} attempts (check MESHCODE_KEYCHAIN_PROFILE / MESHCODE_API_KEY)", "error")
@@ -424,7 +437,7 @@ except Exception:
424
437
 
425
438
  _register_result = be.register_agent(PROJECT_NAME, AGENT_NAME, AGENT_ROLE or "MCP-connected agent", api_key=_get_api_key())
426
439
  if isinstance(_register_result, dict) and _register_result.get("error"):
427
- _mc_log(f" register failed: {_register_result['error']}", "warn")
440
+ _mc_log(f" register failed: {_register_result['error']}", file=sys.stderr)
428
441
 
429
442
  # ── Fetch profile color from dashboard (single source of truth) ──
430
443
  try:
@@ -458,7 +471,7 @@ def _flip_status(status: str, task: str = "") -> bool:
458
471
  return False
459
472
 
460
473
  if not _flip_status("idle", ""):
461
- _mc_log(f" could not flip status to idle", "warn")
474
+ _mc_log(f" could not flip status to idle", file=sys.stderr)
462
475
 
463
476
 
464
477
  # ============================================================
@@ -623,7 +636,7 @@ def _acquire_lease() -> bool:
623
636
  })
624
637
  except Exception as e:
625
638
  # Non-fatal: RPC might not exist on older servers.
626
- _mc_log(f"stale-lease pre-clean skipped: {e}", "warn")
639
+ _mc_log(f"stale-lease pre-clean skipped: {e}", file=sys.stderr)
627
640
  for attempt in range(3):
628
641
  try:
629
642
  r = be.sb_rpc("mc_acquire_agent_lease", {
@@ -675,14 +688,14 @@ def _acquire_lease() -> bool:
675
688
  _mc_log(f"Could not start — agent '{AGENT_NAME}' is running in another window.", "error")
676
689
  _mc_log("Close the other window first, or use a different agent name.", "error")
677
690
  return False
678
- _mc_log(f"lease attempt {attempt+1}: {r.get('error')}", "warn")
691
+ _mc_log(f"lease attempt {attempt+1}: {r.get('error')}", file=sys.stderr)
679
692
  else:
680
693
  return True
681
694
  except Exception as e:
682
- _mc_log(f"lease attempt {attempt+1} failed: {e}", "warn")
695
+ _mc_log(f"lease attempt {attempt+1} failed: {e}", file=sys.stderr)
683
696
  if attempt < 2:
684
697
  _time.sleep(2)
685
- _mc_log(f" lease failed after 3 attempts — proceeding anyway", "warn")
698
+ _mc_log(f" lease failed after 3 attempts — proceeding anyway", file=sys.stderr)
686
699
  return True
687
700
 
688
701
  if not _acquire_lease():
@@ -700,7 +713,7 @@ def _boot_diagnostic() -> None:
700
713
  be.sb_select("mc_projects", f"id=eq.{_PROJECT_ID}", limit=1)
701
714
  checks_passed += 1
702
715
  except Exception as e:
703
- print(f"[meshcode] BOOT CHECK FAILED: Supabase API unreachable ({e}). Fix: check network/VPN.", "warn")
716
+ print(f"[meshcode] BOOT CHECK FAILED: Supabase API unreachable ({e}). Fix: check network/VPN.", file=sys.stderr)
704
717
 
705
718
  # Check 2: Lease valid
706
719
  try:
@@ -710,11 +723,11 @@ def _boot_diagnostic() -> None:
710
723
  if agent.get("instance_id") == _INSTANCE_ID:
711
724
  checks_passed += 1
712
725
  else:
713
- print(f"[meshcode] BOOT CHECK FAILED: Lease mismatch — expected {_INSTANCE_ID}, got {agent.get('instance_id')}. Fix: restart agent.", "warn")
726
+ print(f"[meshcode] BOOT CHECK FAILED: Lease mismatch — expected {_INSTANCE_ID}, got {agent.get('instance_id')}. Fix: restart agent.", file=sys.stderr)
714
727
  else:
715
- print(f"[meshcode] BOOT CHECK FAILED: Agent '{AGENT_NAME}' not found in project. Fix: register agent first.", "warn")
728
+ print(f"[meshcode] BOOT CHECK FAILED: Agent '{AGENT_NAME}' not found in project. Fix: register agent first.", file=sys.stderr)
716
729
  except Exception as e:
717
- print(f"[meshcode] BOOT CHECK FAILED: Could not verify lease ({e}).", "warn")
730
+ print(f"[meshcode] BOOT CHECK FAILED: Could not verify lease ({e}).", file=sys.stderr)
718
731
 
719
732
  # Check 3: Heartbeat recent
720
733
  try:
@@ -723,7 +736,7 @@ def _boot_diagnostic() -> None:
723
736
  if hb:
724
737
  checks_passed += 1
725
738
  else:
726
- print(f"[meshcode] BOOT CHECK WARNING: No heartbeat recorded yet.", "warn")
739
+ print(f"[meshcode] BOOT CHECK WARNING: No heartbeat recorded yet.", file=sys.stderr)
727
740
  else:
728
741
  checks_passed += 1 # skip if no agent data
729
742
  except Exception:
@@ -740,9 +753,9 @@ def _boot_diagnostic() -> None:
740
753
  checks_passed += 1 # non-critical
741
754
 
742
755
  if checks_passed == checks_total:
743
- print(f"[meshcode] All boot checks passed ({checks_passed}/{checks_total}).", "warn")
756
+ print(f"[meshcode] All boot checks passed ({checks_passed}/{checks_total}).", file=sys.stderr)
744
757
  else:
745
- print(f"[meshcode] Boot checks: {checks_passed}/{checks_total} passed. Agent starting anyway.", "warn")
758
+ print(f"[meshcode] Boot checks: {checks_passed}/{checks_total} passed. Agent starting anyway.", file=sys.stderr)
746
759
 
747
760
 
748
761
  _boot_diagnostic()
@@ -789,7 +802,7 @@ def _log_crash_to_db(reason: str = "unknown", error_detail: str = "") -> None:
789
802
  f"crashed: {reason[:100]}", api_key=_get_api_key())
790
803
  except Exception:
791
804
  pass
792
- _mc_log(f" crash logged: {reason}", "warn")
805
+ _mc_log(f" crash logged: {reason}", file=sys.stderr)
793
806
 
794
807
 
795
808
  def _on_exit() -> None:
@@ -1449,9 +1462,9 @@ try:
1449
1462
  elif isinstance(_ls_val, str):
1450
1463
  _LAST_SEEN_TS = _ls_val
1451
1464
  if _LAST_SEEN_TS:
1452
- print(f"[meshcode] Restored last_seen={_LAST_SEEN_TS} from mesh memory.", "warn")
1465
+ print(f"[meshcode] Restored last_seen={_LAST_SEEN_TS} from mesh memory.", file=sys.stderr)
1453
1466
  except Exception as _e:
1454
- print(f"[meshcode] Could not restore last_seen: {_e}", "warn")
1467
+ print(f"[meshcode] Could not restore last_seen: {_e}", file=sys.stderr)
1455
1468
 
1456
1469
 
1457
1470
  def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
@@ -2611,7 +2624,7 @@ def _auto_update() -> None:
2611
2624
  return
2612
2625
 
2613
2626
  # 3. Install the new version (blocking, 60s timeout)
2614
- print(f"[meshcode] Updating {current} → {latest}...", "warn")
2627
+ print(f"[meshcode] Updating {current} → {latest}...", file=sys.stderr)
2615
2628
  try:
2616
2629
  result = subprocess.run(
2617
2630
  [sys.executable, "-m", "pip", "install", "--upgrade",
@@ -2628,8 +2641,14 @@ def _auto_update() -> None:
2628
2641
  log.debug(f"[meshcode] Auto-update failed: {e}")
2629
2642
  return
2630
2643
 
2631
- # 4. Re-exec to load the new code
2632
- print(f"[meshcode] Updated to {latest}, restarting...", "warn")
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).", file=sys.stderr)
2648
+ return
2649
+
2650
+ # CLI mode: safe to re-exec
2651
+ print(f"[meshcode] Updated to {latest}, restarting...", file=sys.stderr)
2633
2652
  os.environ["MESHCODE_UPDATED"] = "1"
2634
2653
  try:
2635
2654
  os.execv(sys.executable, [sys.executable] + sys.argv)
@@ -2650,6 +2669,10 @@ def run_server():
2650
2669
  file=sys.stderr,
2651
2670
  )
2652
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
2653
2676
  mcp.run()
2654
2677
  except KeyboardInterrupt:
2655
2678
  _log_crash_to_db("keyboard_interrupt", "User stopped the agent")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.14
3
+ Version: 2.10.16
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.14"
7
+ version = "2.10.16"
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