meshcode 2.11.135__tar.gz → 2.11.137__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 (105) hide show
  1. {meshcode-2.11.135 → meshcode-2.11.137}/PKG-INFO +2 -11
  2. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/__init__.py +1 -1
  3. meshcode-2.11.137/meshcode/helper_visuals.py +142 -0
  4. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/hostd.py +305 -53
  5. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/server.py +41 -0
  6. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/swarm.py +60 -0
  7. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/test_swarm.py +43 -0
  8. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/protocol_handler.py +55 -1
  9. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/run_agent.py +72 -0
  10. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode.egg-info/PKG-INFO +2 -11
  11. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode.egg-info/SOURCES.txt +3 -0
  12. {meshcode-2.11.135 → meshcode-2.11.137}/pyproject.toml +1 -1
  13. meshcode-2.11.137/tests/test_helper_visuals.py +199 -0
  14. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_hostd_zombie_sessions.py +344 -3
  15. meshcode-2.11.137/tests/test_pretrust_claude.py +86 -0
  16. {meshcode-2.11.135 → meshcode-2.11.137}/README.md +0 -0
  17. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/__main__.py +0 -0
  18. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/_session_handoff_template.py +0 -0
  19. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/_stop_hook_template.py +0 -0
  20. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/ascii_art.py +0 -0
  21. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/atomic_push.py +0 -0
  22. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/claude_update.py +0 -0
  23. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/cli.py +0 -0
  24. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/comms_v4.py +0 -0
  25. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/compat.py +0 -0
  26. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/daemon.py +0 -0
  27. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/date_parse.py +0 -0
  28. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/doctor.py +0 -0
  29. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/error_hints.py +0 -0
  30. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/exceptions.py +0 -0
  31. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/hooks/__init__.py +0 -0
  32. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/hooks/repo_path_lock.py +0 -0
  33. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/invites.py +0 -0
  34. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/launcher.py +0 -0
  35. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/launcher_install.py +0 -0
  36. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/__init__.py +0 -0
  37. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/__main__.py +0 -0
  38. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/backend.py +0 -0
  39. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/realtime.py +0 -0
  40. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  41. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/test_backend.py +0 -0
  42. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  43. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  44. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  45. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  46. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  47. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/preferences.py +0 -0
  48. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/protocol_v2.py +0 -0
  49. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/quickstart.py +0 -0
  50. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/rpc_allowlist.py +0 -0
  51. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/scripts/check_secrets.py +0 -0
  52. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/scripts/race_rate_harness.py +0 -0
  53. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/secrets.py +0 -0
  54. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/self_update.py +0 -0
  55. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/setup_clients.py +0 -0
  56. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/supervisor.py +0 -0
  57. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/up.py +0 -0
  58. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode/upload.py +0 -0
  59. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode.egg-info/dependency_links.txt +0 -0
  60. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode.egg-info/entry_points.txt +0 -0
  61. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode.egg-info/requires.txt +0 -0
  62. {meshcode-2.11.135 → meshcode-2.11.137}/meshcode.egg-info/top_level.txt +0 -0
  63. {meshcode-2.11.135 → meshcode-2.11.137}/setup.cfg +0 -0
  64. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_auto_update_hardening.py +0 -0
  65. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_autonomous_closegap_1.py +0 -0
  66. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_autonomous_closegap_2.py +0 -0
  67. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_autonomous_closegap_3.py +0 -0
  68. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_autonomous_prompt_inject.py +0 -0
  69. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_boot_bug_regression.py +0 -0
  70. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_color_truecolor.py +0 -0
  71. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_core.py +0 -0
  72. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_cross_agent_messaging.py +0 -0
  73. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_date_parse.py +0 -0
  74. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_doctor.py +0 -0
  75. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_epistemic_v1_python_sdk.py +0 -0
  76. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  77. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_esc_deaf_state.py +0 -0
  78. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_exceptions.py +0 -0
  79. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_file_upload.py +0 -0
  80. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_init_device_code.py +0 -0
  81. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_install_guard.py +0 -0
  82. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_lease_sigterm_release.py +0 -0
  83. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_live_mesh_guard.py +0 -0
  84. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_mark_read_batch.py +0 -0
  85. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_marketplace_ratings.py +0 -0
  86. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_migration_integrity.py +0 -0
  87. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_realtime_event_freshness.py +0 -0
  88. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_rls_cross_tenant.py +0 -0
  89. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_rpc_grants.py +0 -0
  90. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_rpc_migrations.py +0 -0
  91. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_run_agent_dry_run.py +0 -0
  92. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_run_agent_no_server_import.py +0 -0
  93. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_security_regressions.py +0 -0
  94. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_self_update_user_site.py +0 -0
  95. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_sentinel.py +0 -0
  96. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_session_replay_gate.py +0 -0
  97. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_setup_path.py +0 -0
  98. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_sleep_signals.py +0 -0
  99. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_status_enum_coverage.py +0 -0
  100. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_stay_on_loop_hook.py +0 -0
  101. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_stop_ghost_terminal.py +0 -0
  102. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_swarm_events.py +0 -0
  103. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_task_progress.py +0 -0
  104. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_terminal_lifecycle.py +0 -0
  105. {meshcode-2.11.135 → meshcode-2.11.137}/tests/test_wait_open_tasks_contradiction.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: meshcode
3
- Version: 2.11.135
3
+ Version: 2.11.137
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -18,17 +18,8 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Operating System :: OS Independent
19
19
  Requires-Python: >=3.9
20
20
  Description-Content-Type: text/markdown
21
- Requires-Dist: mcp[cli]>=1.0.0
22
- Requires-Dist: websockets>=12.0
23
- Requires-Dist: realtime>=2.0.0
24
- Requires-Dist: keyring>=24.0
25
- Requires-Dist: cryptography>=41.0
26
21
  Provides-Extra: test
27
- Requires-Dist: pytest>=8; extra == "test"
28
22
  Provides-Extra: dev
29
- Requires-Dist: build>=1.0; extra == "dev"
30
- Requires-Dist: twine>=4; extra == "dev"
31
- Requires-Dist: pytest>=8; extra == "dev"
32
23
 
33
24
  # MeshCode
34
25
 
@@ -1,5 +1,5 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.11.135"
2
+ __version__ = "2.11.137"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -0,0 +1,142 @@
1
+ """Helper terminal visuals (task d8f8e325 — Samuel msgs edf0ed8d + 68c7fee0).
2
+
3
+ ENJAMBRE helpers must open VISUALLY DISTINCT from top-level agents on every
4
+ platform, so a wall of fleet tabs reads instantly: amber = ephemeral helper,
5
+ normal = real agent. Two layers (both silent-degrade — a visuals failure must
6
+ NEVER break a spawn):
7
+
8
+ [1] UNIVERSAL — `meshcode run` emits OSC 0/2 (title "helper:<name>") +
9
+ OSC 11 (dark-amber background) at session start. Works in Windows
10
+ Terminal, iTerm2 and most xterm-compatible Linux terminals regardless
11
+ of which launcher opened the window; terminals that ignore OSC 11
12
+ (e.g. macOS Terminal.app) still get the title.
13
+ [2] PER-PLATFORM at spawn — Windows Terminal gets `--tabColor <amber>` +
14
+ `--title helper:<name>` on the fleet tab; the Linux/macOS launcher
15
+ scripts prepend the same OSC prelude so the tint applies even before
16
+ `meshcode run` boots.
17
+
18
+ HOW A SPAWNER KNOWS IT'S A HELPER (no agent_kind in the spawn payloads —
19
+ probed live 2026-06-12: mc_agents_needing_respawn candidates and
20
+ mc_host_config_get agents carry no kind field):
21
+
22
+ - MARKER FILE: swarm.spawn_helper() runs on the PARENT's host, which is the
23
+ same host the helper spawns on (W5: helper row inherits the parent's
24
+ host/repo). It stamps ~/.meshcode/helpers/<name>.json with the helper's
25
+ TTL; spawners treat a FRESH marker as "helper". TTL expiry is the
26
+ cleanup (helpers are ephemeral by contract, TTL <= 86400).
27
+ - NAME PREFIX fallback: a name starting with 'helper' counts even without
28
+ a marker (covers cross-host edge cases + the observed naming convention).
29
+
30
+ Tradeoff (documented): a top-level agent that shares a helper's bare name on
31
+ the same host within the marker TTL would render amber — cosmetic only, and
32
+ name collisions are already rejected server-side within a meshwork.
33
+ """
34
+ from __future__ import annotations
35
+
36
+ import json
37
+ import re
38
+ import sys
39
+ import time
40
+ from pathlib import Path
41
+
42
+ # Spec colors (task d8f8e325): amber tab; dark-amber background tint that
43
+ # keeps default light-on-dark text readable.
44
+ HELPER_TAB_COLOR = "#E8A33D"
45
+ HELPER_BG_COLOR = "#3A2310"
46
+ HELPER_TITLE_PREFIX = "helper:"
47
+
48
+ _MARKER_TTL_CAP_S = 86400 # mirror of the server-side helper TTL ceiling
49
+
50
+
51
+ def _helpers_dir() -> Path:
52
+ """Marker directory, behind a function so tests can patch it."""
53
+ return Path.home() / ".meshcode" / "helpers"
54
+
55
+
56
+ def _safe_name(name: str) -> str:
57
+ return re.sub(r"[^A-Za-z0-9_.-]", "_", (name or "").strip()).strip("_")[:80]
58
+
59
+
60
+ def mark_helper(name: str, ttl_seconds: int = 3600) -> None:
61
+ """Stamp <name> as a helper on THIS host (called by swarm.spawn_helper).
62
+ Best-effort: never raises. Opportunistically prunes expired markers."""
63
+ try:
64
+ safe = _safe_name(name)
65
+ if not safe:
66
+ return
67
+ d = _helpers_dir()
68
+ d.mkdir(parents=True, exist_ok=True)
69
+ ttl = max(60, min(int(ttl_seconds or 3600), _MARKER_TTL_CAP_S))
70
+ (d / f"{safe}.json").write_text(
71
+ json.dumps({"name": name, "expires_at": time.time() + ttl}),
72
+ encoding="utf-8")
73
+ for p in d.glob("*.json"):
74
+ try:
75
+ if float(json.loads(p.read_text(encoding="utf-8"))
76
+ .get("expires_at", 0)) < time.time():
77
+ p.unlink()
78
+ except Exception:
79
+ continue
80
+ except Exception:
81
+ pass
82
+
83
+
84
+ def unmark_helper(name: str) -> None:
85
+ """Drop the marker (helper retired). Best-effort."""
86
+ try:
87
+ safe = _safe_name(name)
88
+ if safe:
89
+ (_helpers_dir() / f"{safe}.json").unlink(missing_ok=True)
90
+ except Exception:
91
+ pass
92
+
93
+
94
+ def is_helper(target: str) -> bool:
95
+ """True when `target` (bare 'name' or 'project/name') is a swarm helper:
96
+ fresh marker on this host OR the 'helper' name prefix. Never raises."""
97
+ try:
98
+ agent = (target or "").rsplit("/", 1)[-1].strip()
99
+ if not agent:
100
+ return False
101
+ if agent.lower().startswith("helper"):
102
+ return True
103
+ p = _helpers_dir() / f"{_safe_name(agent)}.json"
104
+ if not p.exists():
105
+ return False
106
+ data = json.loads(p.read_text(encoding="utf-8"))
107
+ return float(data.get("expires_at", 0)) >= time.time()
108
+ except Exception:
109
+ return False
110
+
111
+
112
+ def helper_title(target: str) -> str:
113
+ """Tab/window title for a helper: 'helper:<bare name>' (sanitized)."""
114
+ agent = _safe_name((target or "").rsplit("/", 1)[-1])
115
+ return f"{HELPER_TITLE_PREFIX}{agent or 'agent'}"[:48]
116
+
117
+
118
+ def osc_prelude(target: str) -> str:
119
+ """Escape string: OSC 0 title + OSC 11 background. Terminals that don't
120
+ support either sequence ignore it (that IS the degradation path)."""
121
+ return (f"\x1b]0;{helper_title(target)}\x07"
122
+ f"\x1b]11;{HELPER_BG_COLOR}\x07")
123
+
124
+
125
+ def osc_prelude_shell(target: str) -> str:
126
+ """The same prelude as a POSIX-shell `printf` command (for launcher
127
+ scripts / bash -lc command strings). Title is sanitized [A-Za-z0-9_.-:]
128
+ so it can never break out of the single quotes."""
129
+ return ("printf '\\033]0;%s\\007\\033]11;%s\\007' 2>/dev/null || true"
130
+ % (helper_title(target), HELPER_BG_COLOR))
131
+
132
+
133
+ def emit_osc(target: str) -> None:
134
+ """Universal layer: write the prelude to the live terminal from
135
+ `meshcode run`. Best-effort, TTY-gated (a piped/CI stdout never sees
136
+ escape garbage)."""
137
+ try:
138
+ if sys.stdout.isatty():
139
+ sys.stdout.write(osc_prelude(target))
140
+ sys.stdout.flush()
141
+ except Exception:
142
+ pass