meshcode 2.11.90__tar.gz → 2.11.91__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 (91) hide show
  1. {meshcode-2.11.90 → meshcode-2.11.91}/PKG-INFO +1 -1
  2. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/hostd.py +54 -4
  4. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.11.90 → meshcode-2.11.91}/pyproject.toml +1 -1
  6. {meshcode-2.11.90 → meshcode-2.11.91}/README.md +0 -0
  7. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/__main__.py +0 -0
  8. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/_session_handoff_template.py +0 -0
  9. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/_stop_hook_template.py +0 -0
  10. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/ascii_art.py +0 -0
  11. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/atomic_push.py +0 -0
  12. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/claude_update.py +0 -0
  13. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/cli.py +0 -0
  14. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/comms_v4.py +0 -0
  15. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/compat.py +0 -0
  16. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/daemon.py +0 -0
  17. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/date_parse.py +0 -0
  18. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/doctor.py +0 -0
  19. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/error_hints.py +0 -0
  20. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/exceptions.py +0 -0
  21. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/invites.py +0 -0
  22. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/launcher.py +0 -0
  23. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/launcher_install.py +0 -0
  24. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/__init__.py +0 -0
  25. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/__main__.py +0 -0
  26. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/backend.py +0 -0
  27. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/realtime.py +0 -0
  28. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/server.py +0 -0
  29. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  30. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_backend.py +0 -0
  31. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  32. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  33. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  34. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  35. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  36. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/preferences.py +0 -0
  37. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/protocol_handler.py +0 -0
  38. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/protocol_v2.py +0 -0
  39. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/quickstart.py +0 -0
  40. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/rpc_allowlist.py +0 -0
  41. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/run_agent.py +0 -0
  42. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/scripts/check_secrets.py +0 -0
  43. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/scripts/race_rate_harness.py +0 -0
  44. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/secrets.py +0 -0
  45. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/self_update.py +0 -0
  46. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/setup_clients.py +0 -0
  47. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/supervisor.py +0 -0
  48. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/up.py +0 -0
  49. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/upload.py +0 -0
  50. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/SOURCES.txt +0 -0
  51. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/dependency_links.txt +0 -0
  52. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/entry_points.txt +0 -0
  53. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/requires.txt +0 -0
  54. {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/top_level.txt +0 -0
  55. {meshcode-2.11.90 → meshcode-2.11.91}/setup.cfg +0 -0
  56. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_auto_update_hardening.py +0 -0
  57. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_closegap_1.py +0 -0
  58. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_closegap_2.py +0 -0
  59. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_closegap_3.py +0 -0
  60. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_prompt_inject.py +0 -0
  61. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_boot_bug_regression.py +0 -0
  62. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_color_truecolor.py +0 -0
  63. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_core.py +0 -0
  64. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_cross_agent_messaging.py +0 -0
  65. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_date_parse.py +0 -0
  66. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_doctor.py +0 -0
  67. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_epistemic_v1_python_sdk.py +0 -0
  68. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  69. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_esc_deaf_state.py +0 -0
  70. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_exceptions.py +0 -0
  71. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_file_upload.py +0 -0
  72. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_init_device_code.py +0 -0
  73. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_install_guard.py +0 -0
  74. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_lease_sigterm_release.py +0 -0
  75. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_mark_read_batch.py +0 -0
  76. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_marketplace_ratings.py +0 -0
  77. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_migration_integrity.py +0 -0
  78. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_realtime_event_freshness.py +0 -0
  79. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_rls_cross_tenant.py +0 -0
  80. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_rpc_grants.py +0 -0
  81. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_rpc_migrations.py +0 -0
  82. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_run_agent_dry_run.py +0 -0
  83. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_run_agent_no_server_import.py +0 -0
  84. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_security_regressions.py +0 -0
  85. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_self_update_user_site.py +0 -0
  86. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_sentinel.py +0 -0
  87. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_setup_path.py +0 -0
  88. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_sleep_signals.py +0 -0
  89. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_status_enum_coverage.py +0 -0
  90. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_stay_on_loop_hook.py +0 -0
  91. {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_wait_open_tasks_contradiction.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.90
3
+ Version: 2.11.91
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,5 +1,5 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.11.90"
2
+ __version__ = "2.11.91"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -55,6 +55,27 @@ try:
55
55
  except Exception:
56
56
  _RUNNING_VERSION = "0.0.0"
57
57
  _LAST_UPDATE_KICK_MONO = 0.0
58
+ _REEXEC_GUARD_LOGGED = False
59
+
60
+
61
+ def _has_supervisor() -> bool:
62
+ """True if an OS supervisor (launchd/systemd/Task Scheduler) manages this hostd and will
63
+ relaunch it on clean exit. Field data (Samuel Mac): os.execv is BLOCKED in the sandboxed
64
+ runtime, so where a supervisor exists we PREFER exit-and-relaunch over execv."""
65
+ import platform
66
+ try:
67
+ s = platform.system()
68
+ if s == "Darwin":
69
+ return _hostd_plist_path().exists()
70
+ if s == "Windows":
71
+ return subprocess.run(["schtasks", "/Query", "/TN", _HOSTD_TASK_NAME],
72
+ capture_output=True, text=True).returncode == 0
73
+ if shutil.which("systemctl"):
74
+ return subprocess.run(["systemctl", "--user", "is-enabled", _HOSTD_SYSTEMD_UNIT],
75
+ capture_output=True, text=True).returncode == 0
76
+ except Exception:
77
+ pass
78
+ return False
58
79
 
59
80
 
60
81
  def _maybe_self_restart_on_version_drift() -> None:
@@ -96,13 +117,42 @@ def _maybe_self_restart_on_version_drift() -> None:
96
117
  newer = False
97
118
  if not newer:
98
119
  return
99
- _log(f"VERSION DRIFT: running {_RUNNING_VERSION}, on-disk {ondisk} -> self-reexec to load "
100
- f"new code (Stop kill sweep + daemon fixes). headless_pids persisted; KeepAlive re-attaches.")
120
+ # Loop-guard (backend2 finding): in a source/dev run, importlib.metadata can report a
121
+ # pip-installed wheel NEWER than the __init__.py actually executing, so the drift would
122
+ # PERSIST across restart -> storm. Persist the attempt; if we already tried to reach this
123
+ # exact on-disk target recently and didn't advance, skip until the guard window passes.
124
+ global _REEXEC_GUARD_LOGGED
125
+ try:
126
+ _st = _load_state()
127
+ except Exception:
128
+ _st = {}
129
+ _att = _st.get("reexec_attempt") or {}
130
+ if _att.get("target") == ondisk and (time.time() - float(_att.get("at", 0) or 0)) < 600:
131
+ if not _REEXEC_GUARD_LOGGED:
132
+ _REEXEC_GUARD_LOGGED = True
133
+ _log(f"version drift {_RUNNING_VERSION}->{ondisk} but a recent restart didn't advance the "
134
+ f"running version (source/dev run?). Skipping to avoid a restart storm; retry after 600s.")
135
+ return
136
+ _st["reexec_attempt"] = {"target": ondisk, "at": time.time()}
137
+ try:
138
+ _save_state(_st)
139
+ except Exception:
140
+ pass
141
+ _log(f"VERSION DRIFT: running {_RUNNING_VERSION}, on-disk {ondisk} -> restart to load new code "
142
+ f"(Stop kill sweep + daemon fixes). headless_pids persisted.")
143
+ # Prefer supervisor-restart where one manages hostd: field data (Samuel Mac) showed os.execv
144
+ # is BLOCKED in the sandboxed runtime and the os._exit->KeepAlive fallback is what actually
145
+ # restarts. So when a supervisor exists, exit cleanly and let it relaunch on the new wheel.
146
+ if _has_supervisor():
147
+ _log("supervisor present -> clean exit; launchd/systemd/schtasks relaunches on new code")
148
+ os._exit(0)
149
+ # No supervisor (e.g. dev foreground run): execv is the only in-place restart. If it's blocked,
150
+ # do NOT self-destruct (nothing would relaunch us) — stay on old code, retry after the guard window.
101
151
  try:
102
152
  os.execv(sys.executable, [sys.executable, "-m", "meshcode"] + sys.argv[1:])
103
153
  except Exception as e:
104
- _log(f"WARN: self-reexec failed ({e}); exiting so the supervisor restarts us")
105
- os._exit(0)
154
+ _log(f"WARN: no supervisor + execv failed ({e}); staying on {_RUNNING_VERSION}, retry after guard window")
155
+ return
106
156
 
107
157
  STATE_DIR = Path.home() / ".meshcode"
108
158
  HOST_ID_PATH = STATE_DIR / "host_id"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.90
3
+ Version: 2.11.91
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.11.90"
7
+ version = "2.11.91"
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