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.
- {meshcode-2.11.90 → meshcode-2.11.91}/PKG-INFO +1 -1
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/__init__.py +1 -1
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/hostd.py +54 -4
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.11.90 → meshcode-2.11.91}/pyproject.toml +1 -1
- {meshcode-2.11.90 → meshcode-2.11.91}/README.md +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/__main__.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/_session_handoff_template.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/_stop_hook_template.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/atomic_push.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/claude_update.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/cli.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/compat.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/daemon.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/date_parse.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/doctor.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/error_hints.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/exceptions.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/invites.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/launcher.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/preferences.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/protocol_handler.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/quickstart.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/rpc_allowlist.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/run_agent.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/scripts/check_secrets.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/scripts/race_rate_harness.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/secrets.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/self_update.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/supervisor.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/up.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode/upload.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/setup.cfg +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_auto_update_hardening.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_closegap_1.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_closegap_2.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_closegap_3.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_autonomous_prompt_inject.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_boot_bug_regression.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_color_truecolor.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_core.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_date_parse.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_doctor.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_epistemic_v1_python_sdk.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_epistemic_v1_stop_conditions.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_exceptions.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_file_upload.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_init_device_code.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_install_guard.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_lease_sigterm_release.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_marketplace_ratings.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_rpc_grants.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_run_agent_dry_run.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_run_agent_no_server_import.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_self_update_user_site.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_sentinel.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_setup_path.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_sleep_signals.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_stay_on_loop_hook.py +0 -0
- {meshcode-2.11.90 → meshcode-2.11.91}/tests/test_wait_open_tasks_contradiction.py +0 -0
|
@@ -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
|
-
|
|
100
|
-
|
|
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:
|
|
105
|
-
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|