meshcode 2.11.88__tar.gz → 2.11.90__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.88 → meshcode-2.11.90}/PKG-INFO +1 -1
  2. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/hostd.py +47 -6
  4. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.11.88 → meshcode-2.11.90}/pyproject.toml +1 -1
  6. {meshcode-2.11.88 → meshcode-2.11.90}/README.md +0 -0
  7. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/__main__.py +0 -0
  8. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/_session_handoff_template.py +0 -0
  9. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/_stop_hook_template.py +0 -0
  10. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/ascii_art.py +0 -0
  11. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/atomic_push.py +0 -0
  12. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/claude_update.py +0 -0
  13. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/cli.py +0 -0
  14. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/comms_v4.py +0 -0
  15. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/compat.py +0 -0
  16. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/daemon.py +0 -0
  17. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/date_parse.py +0 -0
  18. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/doctor.py +0 -0
  19. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/error_hints.py +0 -0
  20. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/exceptions.py +0 -0
  21. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/invites.py +0 -0
  22. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/launcher.py +0 -0
  23. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/launcher_install.py +0 -0
  24. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/__init__.py +0 -0
  25. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/__main__.py +0 -0
  26. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/backend.py +0 -0
  27. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/realtime.py +0 -0
  28. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/server.py +0 -0
  29. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  30. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/test_backend.py +0 -0
  31. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  32. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  33. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  34. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  35. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  36. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/preferences.py +0 -0
  37. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/protocol_handler.py +0 -0
  38. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/protocol_v2.py +0 -0
  39. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/quickstart.py +0 -0
  40. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/rpc_allowlist.py +0 -0
  41. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/run_agent.py +0 -0
  42. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/scripts/check_secrets.py +0 -0
  43. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/scripts/race_rate_harness.py +0 -0
  44. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/secrets.py +0 -0
  45. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/self_update.py +0 -0
  46. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/setup_clients.py +0 -0
  47. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/supervisor.py +0 -0
  48. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/up.py +0 -0
  49. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode/upload.py +0 -0
  50. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode.egg-info/SOURCES.txt +0 -0
  51. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode.egg-info/dependency_links.txt +0 -0
  52. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode.egg-info/entry_points.txt +0 -0
  53. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode.egg-info/requires.txt +0 -0
  54. {meshcode-2.11.88 → meshcode-2.11.90}/meshcode.egg-info/top_level.txt +0 -0
  55. {meshcode-2.11.88 → meshcode-2.11.90}/setup.cfg +0 -0
  56. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_auto_update_hardening.py +0 -0
  57. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_autonomous_closegap_1.py +0 -0
  58. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_autonomous_closegap_2.py +0 -0
  59. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_autonomous_closegap_3.py +0 -0
  60. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_autonomous_prompt_inject.py +0 -0
  61. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_boot_bug_regression.py +0 -0
  62. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_color_truecolor.py +0 -0
  63. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_core.py +0 -0
  64. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_cross_agent_messaging.py +0 -0
  65. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_date_parse.py +0 -0
  66. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_doctor.py +0 -0
  67. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_epistemic_v1_python_sdk.py +0 -0
  68. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  69. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_esc_deaf_state.py +0 -0
  70. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_exceptions.py +0 -0
  71. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_file_upload.py +0 -0
  72. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_init_device_code.py +0 -0
  73. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_install_guard.py +0 -0
  74. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_lease_sigterm_release.py +0 -0
  75. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_mark_read_batch.py +0 -0
  76. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_marketplace_ratings.py +0 -0
  77. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_migration_integrity.py +0 -0
  78. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_realtime_event_freshness.py +0 -0
  79. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_rls_cross_tenant.py +0 -0
  80. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_rpc_grants.py +0 -0
  81. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_rpc_migrations.py +0 -0
  82. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_run_agent_dry_run.py +0 -0
  83. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_run_agent_no_server_import.py +0 -0
  84. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_security_regressions.py +0 -0
  85. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_self_update_user_site.py +0 -0
  86. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_sentinel.py +0 -0
  87. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_setup_path.py +0 -0
  88. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_sleep_signals.py +0 -0
  89. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_status_enum_coverage.py +0 -0
  90. {meshcode-2.11.88 → meshcode-2.11.90}/tests/test_stay_on_loop_hook.py +0 -0
  91. {meshcode-2.11.88 → meshcode-2.11.90}/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.88
3
+ Version: 2.11.90
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.88"
2
+ __version__ = "2.11.90"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -881,28 +881,58 @@ def _hostd_bootstrap_if_needed(ttl_sec: int = 3600, verbose: bool = False) -> bo
881
881
  return ok
882
882
 
883
883
 
884
+ def _running_daemon_is_stale() -> bool:
885
+ """ca947d7f: True ONLY if hostd_state.json records a running_version that is STRICTLY older
886
+ than the on-disk installed version. Absent / unknown / equal / newer -> False (FAIL-SAFE:
887
+ never bounce a healthy or ambiguous daemon on the login-critical path — commander's safety
888
+ condition). NOTE: a daemon predating the running_version stamp (<2.11.90) wrote no marker, so
889
+ this returns False for it — that one-time transition still needs a manual restart; this guards
890
+ FUTURE transitions as defense-in-depth (the daemon's own self-reexec is the primary path)."""
891
+ try:
892
+ rv = (_load_state() or {}).get("running_version")
893
+ if not rv:
894
+ return False
895
+ import importlib.metadata as _ilmd
896
+ ondisk = _ilmd.version("meshcode")
897
+ from meshcode import self_update as _su
898
+ return bool(_su._is_newer(ondisk, rv))
899
+ except Exception:
900
+ return False
901
+
902
+
884
903
  def _hostd_bootstrap(verbose: bool = False) -> bool:
885
904
  """Idempotent auto-install + start of hostd (task f12b9d36) — called from `meshcode login`
886
905
  so onboarding is just `pip install meshcode` + `meshcode login` (no manual `hostd install`).
887
- If the OS job already exists, just ensure it's running (don't bounce a live daemon); else
888
- install + start. Best-effort: NEVER raises login must not fail on a bootstrap hiccup."""
906
+ If the OS job already exists, just ensure it's running (don't bounce a live daemon) UNLESS the
907
+ running daemon is provably STALE (ca947d7f), in which case force-restart it so Stop's kill
908
+ sweep + launch fixes land. Best-effort: NEVER raises — login must not fail on a hiccup."""
889
909
  import platform
890
910
  try:
911
+ force = _running_daemon_is_stale() # bounce ONLY a provably-stale daemon
912
+ if force:
913
+ _log(f"hostd bootstrap: running daemon is STALE vs on-disk -> force-restart")
891
914
  sysname = platform.system()
892
915
  if sysname == "Darwin":
893
916
  if not _hostd_plist_path().exists():
894
917
  _hostd_install() # writes plist + launchctl load
895
918
  try:
896
919
  uid = str(os.getuid())
897
- subprocess.run(["launchctl", "kickstart", f"gui/{uid}/{_HOSTD_PLIST_LABEL}"],
898
- capture_output=True, text=True) # start if not already running
920
+ # `kickstart -k` restarts a running job; plain `kickstart` only starts if down.
921
+ args = ["launchctl", "kickstart", f"gui/{uid}/{_HOSTD_PLIST_LABEL}"]
922
+ if force:
923
+ args.insert(2, "-k")
924
+ subprocess.run(args, capture_output=True, text=True)
899
925
  except Exception:
900
926
  pass
901
927
  elif sysname == "Windows":
902
928
  q = subprocess.run(["schtasks", "/Query", "/TN", _HOSTD_TASK_NAME],
903
929
  capture_output=True, text=True)
904
930
  if q.returncode == 0:
905
- # task exists -> just ensure running (IgnoreNew => harmless if already up; no double-spawn)
931
+ if force:
932
+ # stale -> stop the running instance, then start fresh on the new wheel.
933
+ subprocess.run(["schtasks", "/End", "/TN", _HOSTD_TASK_NAME],
934
+ capture_output=True, text=True)
935
+ # task exists -> ensure running (IgnoreNew => harmless if already up; no double-spawn)
906
936
  subprocess.run(["schtasks", "/Run", "/TN", _HOSTD_TASK_NAME],
907
937
  capture_output=True, text=True)
908
938
  else:
@@ -910,6 +940,10 @@ def _hostd_bootstrap(verbose: bool = False) -> bool:
910
940
  _hostd_install_windows()
911
941
  else: # Linux + others
912
942
  if shutil.which("systemctl"):
943
+ if force:
944
+ subprocess.run(["systemctl", "--user", "restart", _HOSTD_SYSTEMD_UNIT],
945
+ capture_output=True, text=True)
946
+ return True
913
947
  act = subprocess.run(["systemctl", "--user", "is-active", _HOSTD_SYSTEMD_UNIT],
914
948
  capture_output=True, text=True)
915
949
  if act.stdout.strip() == "active":
@@ -1024,7 +1058,14 @@ def cmd_hostd(args: list) -> int:
1024
1058
  _log(f"registered host {host_id} in mc_host_config")
1025
1059
  else:
1026
1060
  _log(f"WARN: host registration failed (dashboard may not list this host): {_reg}")
1027
- _log(f"hostd starting — host_id={host_id} interval={POLL_INTERVAL_SEC}s stale={STALE_SECONDS}s")
1061
+ _log(f"hostd starting — host_id={host_id} interval={POLL_INTERVAL_SEC}s stale={STALE_SECONDS}s v{_RUNNING_VERSION}")
1062
+ # ca947d7f: stamp the version THIS daemon is running into hostd_state.json so
1063
+ # `meshcode login` (_hostd_bootstrap) can detect a STALE running daemon and force-
1064
+ # restart it (the one-time transition onto a self-reexec-capable build). Best-effort.
1065
+ try:
1066
+ _st = _load_state(); _st["running_version"] = _RUNNING_VERSION; _save_state(_st)
1067
+ except Exception:
1068
+ pass
1028
1069
  # uptime-since-spawn (core's suggestion): if the daemon dies <2min, the last alive log +
1029
1070
  # the uptime stamped on the FATAL line reveal the <2min pattern for RC.
1030
1071
  _spawn_mono = time.monotonic()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.88
3
+ Version: 2.11.90
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.88"
7
+ version = "2.11.90"
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