meshcode 2.8.7__tar.gz → 2.8.8__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.8.7 → meshcode-2.8.8}/PKG-INFO +1 -1
  2. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/__init__.py +1 -1
  3. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/ascii_art.py +8 -2
  4. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/server.py +56 -26
  5. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/run_agent.py +3 -1
  6. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode.egg-info/PKG-INFO +1 -1
  7. {meshcode-2.8.7 → meshcode-2.8.8}/pyproject.toml +1 -1
  8. {meshcode-2.8.7 → meshcode-2.8.8}/README.md +0 -0
  9. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/cli.py +0 -0
  10. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/comms_v4.py +0 -0
  11. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/invites.py +0 -0
  12. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/launcher.py +0 -0
  13. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/launcher_install.py +0 -0
  14. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/__init__.py +0 -0
  15. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/__main__.py +0 -0
  16. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/backend.py +0 -0
  17. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/realtime.py +0 -0
  18. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/test_backend.py +0 -0
  19. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  20. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  21. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/preferences.py +0 -0
  22. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/protocol_v2.py +0 -0
  23. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/secrets.py +0 -0
  24. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/self_update.py +0 -0
  25. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode/setup_clients.py +0 -0
  26. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode.egg-info/SOURCES.txt +0 -0
  27. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode.egg-info/dependency_links.txt +0 -0
  28. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode.egg-info/entry_points.txt +0 -0
  29. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode.egg-info/requires.txt +0 -0
  30. {meshcode-2.8.7 → meshcode-2.8.8}/meshcode.egg-info/top_level.txt +0 -0
  31. {meshcode-2.8.7 → meshcode-2.8.8}/setup.cfg +0 -0
  32. {meshcode-2.8.7 → meshcode-2.8.8}/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.8.7
3
+ Version: 2.8.8
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.8.7"
2
+ __version__ = "2.8.8"
@@ -88,12 +88,18 @@ def generate_art(agent_name: str, size: int = 7) -> str:
88
88
  return "\n".join(lines)
89
89
 
90
90
 
91
- def render_welcome(agent_name: str, meshwork_name: str, ascii_art: str, version: str = "") -> str:
91
+ YELLOW = "\033[33m"
92
+ STAR = "★"
93
+
94
+
95
+ def render_welcome(agent_name: str, meshwork_name: str, ascii_art: str,
96
+ version: str = "", is_commander: bool = False) -> str:
92
97
  """Render the full colored welcome banner for terminal display."""
93
98
  h = _hash_bytes(agent_name)
94
99
  color = COLORS[h[0] % len(COLORS)]
95
100
 
96
101
  ver_str = f"v{version}" if version else ""
102
+ commander_badge = f" {YELLOW}{STAR} COMMANDER{RESET}" if is_commander else ""
97
103
  lines = []
98
104
  lines.append("")
99
105
  lines.append(f"{color}{BOLD} ╔══════════════════════════════════════════╗{RESET}")
@@ -105,7 +111,7 @@ def render_welcome(agent_name: str, meshwork_name: str, ascii_art: str, version:
105
111
  lines.append(f" {color}{line}{RESET}")
106
112
 
107
113
  lines.append("")
108
- lines.append(f" {BOLD}{color}●{RESET} {BOLD}{agent_name}{RESET} {DIM}is online{RESET}")
114
+ lines.append(f" {BOLD}{color}●{RESET} {BOLD}{agent_name}{RESET}{commander_badge} {DIM}is online{RESET}")
109
115
  lines.append(f" {DIM}meshwork:{RESET} {meshwork_name}")
110
116
  if version:
111
117
  lines.append(f" {DIM}version:{RESET} {version}")
@@ -12,11 +12,41 @@ import json
12
12
  import logging
13
13
  import os
14
14
  import sys
15
+ import hashlib as _hashlib
15
16
  from collections import deque
16
17
  from contextlib import asynccontextmanager
17
18
  from typing import Any, Dict, List, Optional, Union
18
19
 
19
20
 
21
+ # ── Agent color for terminal logs (pure ANSI, zero tokens) ──────
22
+ _ANSI_COLORS = [
23
+ "\033[36m", "\033[35m", "\033[32m", "\033[33m", "\033[34m",
24
+ "\033[91m", "\033[96m", "\033[95m", "\033[92m", "\033[94m",
25
+ ]
26
+ _ANSI_RESET = "\033[0m"
27
+ _ANSI_BOLD = "\033[1m"
28
+ _ANSI_DIM = "\033[2m"
29
+
30
+
31
+ def _agent_color(name: str) -> str:
32
+ """Deterministic ANSI color from agent name hash."""
33
+ h = int(_hashlib.md5(name.encode()).hexdigest()[:8], 16)
34
+ return _ANSI_COLORS[h % len(_ANSI_COLORS)]
35
+
36
+
37
+ def _mc_log(msg: str, level: str = "info") -> None:
38
+ """Colored [meshcode-mcp] log line. Uses agent color if available."""
39
+ agent = os.environ.get("MESHCODE_AGENT", "")
40
+ c = _agent_color(agent) if agent else "\033[36m"
41
+ prefix = f"{c}{_ANSI_BOLD}[meshcode-mcp]{_ANSI_RESET}"
42
+ if level == "error":
43
+ print(f"{prefix} \033[91mERROR:{_ANSI_RESET} {msg}", "warn")
44
+ elif level == "warn":
45
+ print(f"{prefix} \033[33mWARNING:{_ANSI_RESET} {msg}", "warn")
46
+ else:
47
+ print(f"{prefix} {c}{msg}{_ANSI_RESET}", "warn")
48
+
49
+
20
50
  # ============================================================
21
51
  # Dedupe: track IDs of messages we've already returned from
22
52
  # meshcode_wait / meshcode_check so the same row doesn't show
@@ -309,7 +339,7 @@ def _get_api_key() -> str:
309
339
  _API_KEY_CACHE = kc_val
310
340
  return kc_val
311
341
  except Exception as e:
312
- print(f"[meshcode-mcp] WARNING: keychain lookup failed for profile '{profile}': {e}", file=sys.stderr)
342
+ _mc_log(f" keychain lookup failed for profile '{profile}': {e}", "warn")
313
343
  _API_KEY_CACHE = ""
314
344
  return ""
315
345
 
@@ -330,13 +360,13 @@ if not _PROJECT_ID:
330
360
  if isinstance(_r, dict) and _r.get("project_id"):
331
361
  _PROJECT_ID = _r["project_id"]
332
362
  elif isinstance(_r, dict) and _r.get("error"):
333
- print(f"[meshcode-mcp] WARNING: mc_resolve_project: {_r['error']}", file=sys.stderr)
363
+ _mc_log(f" mc_resolve_project: {_r['error']}", "warn")
334
364
  except Exception as _e:
335
- print(f"[meshcode-mcp] WARNING: mc_resolve_project failed: {_e}", file=sys.stderr)
365
+ _mc_log(f" mc_resolve_project failed: {_e}", "warn")
336
366
  if not _PROJECT_ID:
337
367
  _PROJECT_ID = be.get_project_id(PROJECT_NAME)
338
368
  if not _PROJECT_ID:
339
- print(f"[meshcode-mcp] ERROR: project '{PROJECT_NAME}' not found (check MESHCODE_KEYCHAIN_PROFILE / MESHCODE_API_KEY)", file=sys.stderr)
369
+ _mc_log(f"project '{PROJECT_NAME}' not found (check MESHCODE_KEYCHAIN_PROFILE / MESHCODE_API_KEY)", "error")
340
370
  sys.exit(2)
341
371
 
342
372
  # Resolve project plan for adaptive features (heartbeat interval, etc.)
@@ -350,7 +380,7 @@ except Exception:
350
380
 
351
381
  _register_result = be.register_agent(PROJECT_NAME, AGENT_NAME, AGENT_ROLE or "MCP-connected agent", api_key=_get_api_key())
352
382
  if isinstance(_register_result, dict) and _register_result.get("error"):
353
- print(f"[meshcode-mcp] WARNING: register failed: {_register_result['error']}", file=sys.stderr)
383
+ _mc_log(f" register failed: {_register_result['error']}", "warn")
354
384
 
355
385
  # Flip to online so the dashboard reflects the live MCP session.
356
386
  # Use the SECURITY DEFINER RPC (mc_agent_set_status_by_api_key) so we
@@ -368,7 +398,7 @@ def _flip_status(status: str, task: str = "") -> bool:
368
398
  return False
369
399
 
370
400
  if not _flip_status("idle", ""):
371
- print(f"[meshcode-mcp] WARNING: could not flip status to idle", file=sys.stderr)
401
+ _mc_log(f" could not flip status to idle", "warn")
372
402
 
373
403
 
374
404
  # ============================================================
@@ -530,7 +560,7 @@ def _acquire_lease() -> bool:
530
560
  })
531
561
  except Exception as e:
532
562
  # Non-fatal: RPC might not exist on older servers.
533
- print(f"[meshcode-mcp] stale-lease pre-clean skipped: {e}", file=sys.stderr)
563
+ _mc_log(f"stale-lease pre-clean skipped: {e}", "warn")
534
564
  for attempt in range(3):
535
565
  try:
536
566
  r = be.sb_rpc("mc_acquire_agent_lease", {
@@ -547,11 +577,11 @@ def _acquire_lease() -> bool:
547
577
  if attempt < 2:
548
578
  # The old lease might be stale — wait and retry
549
579
  # (the 90s stale check in the RPC should clear it)
550
- print(f"[meshcode-mcp] Lease held by another instance — retrying in {2 * (attempt+1)}s...", file=sys.stderr)
580
+ _mc_log(f"Lease held by another instance — retrying in {2 * (attempt+1)}s...")
551
581
  _time.sleep(2 * (attempt + 1))
552
582
  continue
553
583
  # Final attempt — force release the old lease and try once more
554
- print(f"[meshcode-mcp] Force-releasing stale lease...", file=sys.stderr)
584
+ _mc_log("Force-releasing stale lease...")
555
585
  try:
556
586
  be.sb_rpc("mc_release_agent_lease", {
557
587
  "p_api_key": api_key,
@@ -575,21 +605,21 @@ def _acquire_lease() -> bool:
575
605
  "p_instance_id": _INSTANCE_ID,
576
606
  })
577
607
  if isinstance(r2, dict) and r2.get("ok"):
578
- print(f"[meshcode-mcp] Lease acquired after force-release.", file=sys.stderr)
608
+ _mc_log("Lease acquired after force-release.")
579
609
  return True
580
610
  except Exception:
581
611
  pass
582
- print(f"[meshcode-mcp] ERROR: Could not start — agent '{AGENT_NAME}' is running in another window.", file=sys.stderr)
583
- print(f"[meshcode-mcp] Close the other window first, or use a different agent name.", file=sys.stderr)
612
+ _mc_log(f"Could not start — agent '{AGENT_NAME}' is running in another window.", "error")
613
+ _mc_log("Close the other window first, or use a different agent name.", "error")
584
614
  return False
585
- print(f"[meshcode-mcp] lease attempt {attempt+1}: {r.get('error')}", file=sys.stderr)
615
+ _mc_log(f"lease attempt {attempt+1}: {r.get('error')}", "warn")
586
616
  else:
587
617
  return True
588
618
  except Exception as e:
589
- print(f"[meshcode-mcp] lease attempt {attempt+1} failed: {e}", file=sys.stderr)
619
+ _mc_log(f"lease attempt {attempt+1} failed: {e}", "warn")
590
620
  if attempt < 2:
591
621
  _time.sleep(2)
592
- print(f"[meshcode-mcp] WARNING: lease failed after 3 attempts — proceeding anyway", file=sys.stderr)
622
+ _mc_log(f" lease failed after 3 attempts — proceeding anyway", "warn")
593
623
  return True
594
624
 
595
625
  if not _acquire_lease():
@@ -607,7 +637,7 @@ def _boot_diagnostic() -> None:
607
637
  be.sb_select("mc_projects", f"id=eq.{_PROJECT_ID}", limit=1)
608
638
  checks_passed += 1
609
639
  except Exception as e:
610
- print(f"[meshcode] BOOT CHECK FAILED: Supabase API unreachable ({e}). Fix: check network/VPN.", file=sys.stderr)
640
+ print(f"[meshcode] BOOT CHECK FAILED: Supabase API unreachable ({e}). Fix: check network/VPN.", "warn")
611
641
 
612
642
  # Check 2: Lease valid
613
643
  try:
@@ -617,11 +647,11 @@ def _boot_diagnostic() -> None:
617
647
  if agent.get("instance_id") == _INSTANCE_ID:
618
648
  checks_passed += 1
619
649
  else:
620
- print(f"[meshcode] BOOT CHECK FAILED: Lease mismatch — expected {_INSTANCE_ID}, got {agent.get('instance_id')}. Fix: restart agent.", file=sys.stderr)
650
+ print(f"[meshcode] BOOT CHECK FAILED: Lease mismatch — expected {_INSTANCE_ID}, got {agent.get('instance_id')}. Fix: restart agent.", "warn")
621
651
  else:
622
- print(f"[meshcode] BOOT CHECK FAILED: Agent '{AGENT_NAME}' not found in project. Fix: register agent first.", file=sys.stderr)
652
+ print(f"[meshcode] BOOT CHECK FAILED: Agent '{AGENT_NAME}' not found in project. Fix: register agent first.", "warn")
623
653
  except Exception as e:
624
- print(f"[meshcode] BOOT CHECK FAILED: Could not verify lease ({e}).", file=sys.stderr)
654
+ print(f"[meshcode] BOOT CHECK FAILED: Could not verify lease ({e}).", "warn")
625
655
 
626
656
  # Check 3: Heartbeat recent
627
657
  try:
@@ -630,7 +660,7 @@ def _boot_diagnostic() -> None:
630
660
  if hb:
631
661
  checks_passed += 1
632
662
  else:
633
- print(f"[meshcode] BOOT CHECK WARNING: No heartbeat recorded yet.", file=sys.stderr)
663
+ print(f"[meshcode] BOOT CHECK WARNING: No heartbeat recorded yet.", "warn")
634
664
  else:
635
665
  checks_passed += 1 # skip if no agent data
636
666
  except Exception:
@@ -647,9 +677,9 @@ def _boot_diagnostic() -> None:
647
677
  checks_passed += 1 # non-critical
648
678
 
649
679
  if checks_passed == checks_total:
650
- print(f"[meshcode] All boot checks passed ({checks_passed}/{checks_total}).", file=sys.stderr)
680
+ print(f"[meshcode] All boot checks passed ({checks_passed}/{checks_total}).", "warn")
651
681
  else:
652
- print(f"[meshcode] Boot checks: {checks_passed}/{checks_total} passed. Agent starting anyway.", file=sys.stderr)
682
+ print(f"[meshcode] Boot checks: {checks_passed}/{checks_total} passed. Agent starting anyway.", "warn")
653
683
 
654
684
 
655
685
  _boot_diagnostic()
@@ -1291,9 +1321,9 @@ try:
1291
1321
  elif isinstance(_ls_val, str):
1292
1322
  _LAST_SEEN_TS = _ls_val
1293
1323
  if _LAST_SEEN_TS:
1294
- print(f"[meshcode] Restored last_seen={_LAST_SEEN_TS} from mesh memory.", file=sys.stderr)
1324
+ print(f"[meshcode] Restored last_seen={_LAST_SEEN_TS} from mesh memory.", "warn")
1295
1325
  except Exception as _e:
1296
- print(f"[meshcode] Could not restore last_seen: {_e}", file=sys.stderr)
1326
+ print(f"[meshcode] Could not restore last_seen: {_e}", "warn")
1297
1327
 
1298
1328
 
1299
1329
  def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
@@ -2406,7 +2436,7 @@ def _auto_update() -> None:
2406
2436
  return
2407
2437
 
2408
2438
  # 3. Install the new version (blocking, 60s timeout)
2409
- print(f"[meshcode] Updating {current} → {latest}...", file=sys.stderr)
2439
+ print(f"[meshcode] Updating {current} → {latest}...", "warn")
2410
2440
  try:
2411
2441
  result = subprocess.run(
2412
2442
  [sys.executable, "-m", "pip", "install", "--upgrade",
@@ -2424,7 +2454,7 @@ def _auto_update() -> None:
2424
2454
  return
2425
2455
 
2426
2456
  # 4. Re-exec to load the new code
2427
- print(f"[meshcode] Updated to {latest}, restarting...", file=sys.stderr)
2457
+ print(f"[meshcode] Updated to {latest}, restarting...", "warn")
2428
2458
  os.environ["MESHCODE_UPDATED"] = "1"
2429
2459
  try:
2430
2460
  os.execv(sys.executable, [sys.executable] + sys.argv)
@@ -342,7 +342,9 @@ def run(agent: str, project: Optional[str] = None, editor_override: Optional[str
342
342
  from . import __version__ as cli_version
343
343
  # Try to fetch stored art from server, generate if missing
344
344
  ascii_art = _fetch_or_generate_art(agent, resolved_project)
345
- print(render_welcome(agent, resolved_project, ascii_art, cli_version))
345
+ # Check if this agent is the commander
346
+ is_cmd = "commander" in agent.lower()
347
+ print(render_welcome(agent, resolved_project, ascii_art, cli_version, is_commander=is_cmd))
346
348
  except Exception:
347
349
  pass # Non-critical — skip banner on error
348
350
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.8.7
3
+ Version: 2.8.8
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.8.7"
7
+ version = "2.8.8"
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
File without changes
File without changes
File without changes
File without changes