meshcode 2.10.25__tar.gz → 2.10.27__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.25 → meshcode-2.10.27}/PKG-INFO +1 -1
  2. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/__init__.py +1 -1
  3. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/server.py +37 -18
  4. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.10.25 → meshcode-2.10.27}/pyproject.toml +1 -1
  6. {meshcode-2.10.25 → meshcode-2.10.27}/README.md +0 -0
  7. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/ascii_art.py +0 -0
  8. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/cli.py +0 -0
  9. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/comms_v4.py +0 -0
  10. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/invites.py +0 -0
  11. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/launcher.py +0 -0
  12. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/launcher_install.py +0 -0
  13. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/__init__.py +0 -0
  14. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/__main__.py +0 -0
  15. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/backend.py +0 -0
  16. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/realtime.py +0 -0
  17. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/test_backend.py +0 -0
  18. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  19. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  20. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/preferences.py +0 -0
  21. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/protocol_v2.py +0 -0
  22. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/run_agent.py +0 -0
  23. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/secrets.py +0 -0
  24. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/self_update.py +0 -0
  25. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode/setup_clients.py +0 -0
  26. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode.egg-info/SOURCES.txt +0 -0
  27. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode.egg-info/dependency_links.txt +0 -0
  28. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode.egg-info/entry_points.txt +0 -0
  29. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode.egg-info/requires.txt +0 -0
  30. {meshcode-2.10.25 → meshcode-2.10.27}/meshcode.egg-info/top_level.txt +0 -0
  31. {meshcode-2.10.25 → meshcode-2.10.27}/setup.cfg +0 -0
  32. {meshcode-2.10.25 → meshcode-2.10.27}/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.25
3
+ Version: 2.10.27
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.25"
2
+ __version__ = "2.10.27"
@@ -105,8 +105,12 @@ _SEEN_MSG_CAP = 1000
105
105
  # DEFAULT: ON. Disable with MESHCODE_AUTO_WAKE=0 if you don't want it.
106
106
  # ============================================================
107
107
  _IN_WAIT = False # True while meshcode_wait is blocking
108
- # Default ONopt-out via MESHCODE_AUTO_WAKE=0/false/no
109
- _AUTO_WAKE = os.environ.get("MESHCODE_AUTO_WAKE", "1").lower() not in ("0", "false", "no")
108
+ # Default OFF as of 2.10.27 the AppleScript/PowerShell keystroke injection
109
+ # wrote nudge text directly into the user's terminal, which corrupts stdin on
110
+ # terminals that don't interpret ANSI, interrupts the user mid-typing, and
111
+ # duplicates what the dashboard already surfaces. Opt-in with
112
+ # MESHCODE_AUTO_WAKE=1 for users who want the legacy behavior.
113
+ _AUTO_WAKE = os.environ.get("MESHCODE_AUTO_WAKE", "0").lower() in ("1", "true", "yes")
110
114
 
111
115
 
112
116
  def _try_auto_wake(from_agent: str, preview: str) -> None:
@@ -156,9 +160,11 @@ def _try_auto_wake(from_agent: str, preview: str) -> None:
156
160
  # Sanitize inputs: strip everything except alphanumeric, spaces, basic punctuation
157
161
  safe_agent = re.sub(r'[^a-zA-Z0-9_\- ]', '', from_agent)[:50]
158
162
  safe_preview = re.sub(r'[^a-zA-Z0-9_\-.,!? ]', '', preview)[:60]
159
- # Color-coded nudge with sender's agent color
160
- ac = _agent_color(safe_agent)
161
- nudge = f"{ac}{_ANSI_BOLD}[mesh]{_ANSI_RESET} {ac}{safe_agent}{_ANSI_RESET} {_ANSI_DIM}>{_ANSI_RESET} {safe_preview} {_ANSI_DIM}— meshcode_check(){_ANSI_RESET}"
163
+ # Plain-text nudge. ANSI colors were stripped 2026-04-16 because terminals
164
+ # that don't interpret escape sequences (TypeScript runners, some VSCode
165
+ # configurations, pipelines, tmux without termguicolors) render the raw
166
+ # bytes — "[91m[1m[mesh][0m …" — which is worse UX than no color at all.
167
+ nudge = f"[mesh] {safe_agent} > {safe_preview} — meshcode_check()"
162
168
  system = platform.system()
163
169
  try:
164
170
  if system == "Darwin":
@@ -799,12 +805,11 @@ def _log_crash_to_db(reason: str = "unknown", error_detail: str = "") -> None:
799
805
 
800
806
 
801
807
 
802
- # NOTE: Do NOT install signal handlers (SIGTERM, SIGINT) or atexit hooks here.
803
- # FastMCP/anyio manages its own event loop and signal handling. Custom signal
804
- # handlers override Python's default KeyboardInterrupt, preventing anyio from
805
- # cancelling tasks cleanly. Network calls inside signal/atexit handlers can
806
- # deadlock or corrupt the event loop. The lease will be released by the
808
+ # NOTE: Do NOT install custom SIGTERM handlers or atexit hooks here — network
809
+ # calls inside them can deadlock the event loop. The lease is released by the
807
810
  # lifespan shutdown handler instead.
811
+ #
812
+ # SIGINT handling is special — see run_server() for why we set SIG_IGN there.
808
813
 
809
814
 
810
815
  # ============================================================
@@ -2795,14 +2800,7 @@ def _auto_update() -> None:
2795
2800
 
2796
2801
 
2797
2802
  def run_server():
2798
- """Start the MCP server on stdio (default for Claude Code).
2799
-
2800
- IMPORTANT: Do NOT wrap mcp.run() with try/except, signal handlers, or
2801
- atexit hooks. FastMCP/anyio manages its own event loop lifecycle and
2802
- signal handling. Any interference (custom SIGINT handler, atexit network
2803
- calls, catching KeyboardInterrupt) corrupts the event loop and causes
2804
- the MCP server to crash when Claude Code cancels a tool call (ESC).
2805
- """
2803
+ """Start the MCP server on stdio (default for Claude Code)."""
2806
2804
  _auto_update()
2807
2805
  print(
2808
2806
  f"[meshcode-mcp] Starting server for {AGENT_NAME}@{PROJECT_NAME}",
@@ -2812,4 +2810,25 @@ def run_server():
2812
2810
  # sys.stdout was redirected to stderr at module load to prevent
2813
2811
  # accidental stdout writes from corrupting the MCP protocol.
2814
2812
  sys.stdout = _REAL_STDOUT
2813
+
2814
+ # Claude Code cancels tool calls on ESC via TWO parallel channels:
2815
+ # (1) JSON-RPC `notifications/cancelled` over stdin (the correct path)
2816
+ # (2) SIGINT to the stdio subprocess (a destructive side-channel)
2817
+ # anyio's asyncio backend installs its own SIGINT handler inside
2818
+ # Runner.run() only if the current handler is `default_int_handler`
2819
+ # (see anyio/_backends/_asyncio.py ~L197-210). That handler cancels the
2820
+ # *main task* — which for a stdio server IS the whole server run —
2821
+ # tearing the event loop down and killing the subprocess. Setting
2822
+ # SIG_IGN before mcp.run() trips anyio's guard, so it leaves SIGINT
2823
+ # alone; the kernel drops the signal; only the notifications/cancelled
2824
+ # path remains, which cancels just the in-flight tool call as intended.
2825
+ # SIGTERM is deliberately untouched so Claude Code can still force-shut
2826
+ # the server on session end. stdin EOF remains the normal exit path.
2827
+ import signal
2828
+ try:
2829
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
2830
+ except (ValueError, OSError):
2831
+ # Non-main thread or platform that can't install handlers — harmless.
2832
+ pass
2833
+
2815
2834
  mcp.run()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.25
3
+ Version: 2.10.27
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.25"
7
+ version = "2.10.27"
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