meshcode 2.11.110rc1__tar.gz → 2.11.111__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.110rc1 → meshcode-2.11.111}/PKG-INFO +1 -1
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/__init__.py +1 -1
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/comms_v4.py +9 -2
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/hostd.py +24 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/server.py +107 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/pyproject.toml +1 -1
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/README.md +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/__main__.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/_session_handoff_template 2.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/_session_handoff_template 3.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/_session_handoff_template.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/_stop_hook_template.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/atomic_push.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/claude_update 2.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/claude_update 3.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/claude_update.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/cli.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/compat.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/daemon.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/date_parse.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/doctor.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/error_hints.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/exceptions.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/hooks/__init__.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/hooks/repo_path_lock.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/hostd 2.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/invites.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/launcher.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/preferences.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/protocol_handler.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/quickstart.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/rpc_allowlist.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/run_agent.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/scripts/check_secrets.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/scripts/race_rate_harness.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/secrets.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/self_update.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/supervisor.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/up 2.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/up.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/upload.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/setup.cfg +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_auto_update_hardening.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_autonomous_closegap_1.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_autonomous_closegap_2.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_autonomous_closegap_3.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_autonomous_prompt_inject 2.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_autonomous_prompt_inject 3.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_autonomous_prompt_inject.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_boot_bug_regression.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_color_truecolor.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_core.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_date_parse.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_doctor.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_epistemic_v1_python_sdk.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_epistemic_v1_stop_conditions.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_exceptions.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_file_upload.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_init_device_code.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_install_guard.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_lease_sigterm_release.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_marketplace_ratings.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_rpc_grants.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_run_agent_dry_run.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_run_agent_no_server_import.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_self_update_user_site.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_sentinel.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_setup_path.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_sleep_signals.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_stay_on_loop_hook.py +0 -0
- {meshcode-2.11.110rc1 → meshcode-2.11.111}/tests/test_wait_open_tasks_contradiction.py +0 -0
|
@@ -2468,7 +2468,7 @@ TEAM:
|
|
|
2468
2468
|
SETUP (advanced):
|
|
2469
2469
|
setup <proj> <name> [role] Create workspace (auto by 'go')
|
|
2470
2470
|
add-agent <proj> <name> [role] Alias for `setup` above
|
|
2471
|
-
run <agent> [--project <name>] [--autonomous] Launch agent (auto by 'go')
|
|
2471
|
+
run <agent> [--project <name>] [--autonomous] [--repo <path>] Launch agent (auto by 'go')
|
|
2472
2472
|
register <proj> <name> [role] Register agent manually
|
|
2473
2473
|
setup <client> <proj> <name> [role] Legacy: global MCP config
|
|
2474
2474
|
|
|
@@ -2691,14 +2691,21 @@ by `meshcode go`.
|
|
|
2691
2691
|
EXAMPLES:
|
|
2692
2692
|
meshcode setup my-app backend "Backend Engineer"
|
|
2693
2693
|
""",
|
|
2694
|
-
"run": """meshcode run <agent> [--project <name>] [--editor claude|cursor|code]
|
|
2694
|
+
"run": """meshcode run <agent> [--project <name>] [--editor claude|cursor|code] [--repo <path>] [--dry-run]
|
|
2695
2695
|
|
|
2696
2696
|
Launch an agent in your preferred editor. Detects Claude Code, Cursor,
|
|
2697
2697
|
VS Code, Windsurf, or Codex. Use <project>/<agent> to disambiguate.
|
|
2698
2698
|
|
|
2699
|
+
--repo <path> Launch repo-scoped: cwd=<path> (the agent works inside that
|
|
2700
|
+
repo + reads its CLAUDE.md) with a hard repo-path lock that
|
|
2701
|
+
denies file ops outside it. Omit for a normal workspace launch.
|
|
2702
|
+
--dry-run Exercise the full bootstrap (no editor launch); exit 0 on a
|
|
2703
|
+
clean path.
|
|
2704
|
+
|
|
2699
2705
|
EXAMPLES:
|
|
2700
2706
|
meshcode run backend
|
|
2701
2707
|
meshcode run my-app/backend --editor cursor
|
|
2708
|
+
meshcode run backend --repo ~/code/my-repo
|
|
2702
2709
|
""",
|
|
2703
2710
|
"go": """meshcode go <agent> [--project <name>] [--dry-run]
|
|
2704
2711
|
|
|
@@ -159,6 +159,17 @@ STATE_DIR = Path.home() / ".meshcode"
|
|
|
159
159
|
HOST_ID_PATH = STATE_DIR / "host_id"
|
|
160
160
|
LOG_PATH = STATE_DIR / "hostd.log"
|
|
161
161
|
|
|
162
|
+
# BOOT-AUTOSTART GATE (task b6da0d54, Samuel: "terminals open by themselves at boot").
|
|
163
|
+
# hostd is launched at OS logon (Task Scheduler / launchd). On a fresh start it must NOT
|
|
164
|
+
# auto-respawn agents that were merely left desired_state='running' by a PRIOR session —
|
|
165
|
+
# that's the "terminals pop at boot" bug. We record hostd's own start time; an agent whose
|
|
166
|
+
# last heartbeat PREDATES this start (or who never heartbeated) is a boot-stale leftover and
|
|
167
|
+
# is skipped (explicit launch required). An agent that was alive AFTER this start and then
|
|
168
|
+
# died = a real crash -> respawned (crash-recovery preserved). Opt back into the old
|
|
169
|
+
# auto-launch-everything behavior with MESHCODE_BOOT_AUTOSTART=1.
|
|
170
|
+
_HOSTD_STARTED_AT = time.time()
|
|
171
|
+
_BOOT_AUTOSTART = os.environ.get("MESHCODE_BOOT_AUTOSTART", "").strip().lower() in ("1", "true", "yes", "on")
|
|
172
|
+
|
|
162
173
|
def _env_poll_interval() -> int:
|
|
163
174
|
# task 399d7b51 SPEED: poll faster so click->desired_state->spawn latency drops (was 45s).
|
|
164
175
|
# Env-configurable (survives upgrade); floor 3s so we never hammer the DB.
|
|
@@ -516,6 +527,19 @@ def _do_respawns(api_key: str, host_id: str) -> int:
|
|
|
516
527
|
# do NOT re-record here (that would inflate the count on a mere rate-limit skip).
|
|
517
528
|
_log(f"SKIP respawn {proj}/{agent}: not allowed (count={c.get('respawn_count')}, rate-limited/at-cap)")
|
|
518
529
|
continue
|
|
530
|
+
# BOOT-AUTOSTART GATE (task b6da0d54): don't auto-launch an agent whose last heartbeat
|
|
531
|
+
# PREDATES this hostd start (or never heartbeated) — that's a boot-stale 'running' leftover
|
|
532
|
+
# from a prior session, NOT a live-then-crashed agent. Skip it (explicit launch required) so
|
|
533
|
+
# rebooting / hostd-restart does NOT pop terminals. An agent alive AFTER startup that died =
|
|
534
|
+
# crash -> falls through to respawn (crash-recovery preserved). MESHCODE_BOOT_AUTOSTART=1 opts out.
|
|
535
|
+
if not _BOOT_AUTOSTART:
|
|
536
|
+
_hb_age = c.get("heartbeat_age_s")
|
|
537
|
+
_hostd_uptime = time.time() - _HOSTD_STARTED_AT
|
|
538
|
+
if _hb_age is None or _hb_age >= _hostd_uptime:
|
|
539
|
+
_log(f"BOOT-AUTOSTART OFF: skip auto-respawn {proj}/{agent} (no heartbeat since hostd "
|
|
540
|
+
f"start — boot-stale 'running' leftover; explicit launch required). "
|
|
541
|
+
f"Set MESHCODE_BOOT_AUTOSTART=1 to auto-launch at boot.")
|
|
542
|
+
continue
|
|
519
543
|
# RECYCLE FAST-PATH (task c0fc5597): a recycle-exited agent (recycle_fast) is relaunched
|
|
520
544
|
# PROMPTLY (the RPC returned it at a 15s stale gate, not STALE_SECONDS) and recorded as a
|
|
521
545
|
# RECYCLE (mc_record_recycle), NEVER against the crash respawn cap.
|
|
@@ -1591,6 +1591,105 @@ def _install_shutdown_signal_handlers() -> None:
|
|
|
1591
1591
|
_mc_log(f"could not register SIGINT handler: {e}", "warn")
|
|
1592
1592
|
|
|
1593
1593
|
|
|
1594
|
+
# ── Close-to-stop: closing the terminal STOPS the agent (task b6da0d54, Samuel) ─
|
|
1595
|
+
# DISTINCT from the graceful SIGTERM/SIGINT handler above. This fires on a real
|
|
1596
|
+
# console CLOSE (window/tab) and flips desired_state->stopped so hostd does NOT
|
|
1597
|
+
# respawn it (hostd respawns ONLY desired_state='running'). A genuine CRASH never
|
|
1598
|
+
# runs this (process is gone before the handler) -> desired_state stays 'running'
|
|
1599
|
+
# -> hostd crash-respawn is PRESERVED. ESC is NOT a close (the window stays open),
|
|
1600
|
+
# so it never triggers this. "al cerrar la terminal el agente se debe parar."
|
|
1601
|
+
_WIN_CTRL_HANDLER_REF = None # keep the WINFUNCTYPE callback alive (GC guard)
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
def _flip_desired_state_stopped(timeout_s: float = 3.0) -> None:
|
|
1605
|
+
"""Best-effort flip THIS agent's desired_state->stopped via mc_set_desired_state
|
|
1606
|
+
(api_key self-scoped to the calling agent). Fast — Windows CTRL_CLOSE allows ~5s
|
|
1607
|
+
before the OS force-kills, so we time-box the RPC and never block exit."""
|
|
1608
|
+
done = _threading.Event()
|
|
1609
|
+
|
|
1610
|
+
def _do():
|
|
1611
|
+
try:
|
|
1612
|
+
ak = _get_api_key()
|
|
1613
|
+
if ak:
|
|
1614
|
+
be.sb_rpc("mc_set_desired_state", {"p_api_key": ak, "p_state": "stopped"})
|
|
1615
|
+
except Exception:
|
|
1616
|
+
pass
|
|
1617
|
+
done.set()
|
|
1618
|
+
|
|
1619
|
+
try:
|
|
1620
|
+
_threading.Thread(target=_do, daemon=True, name="meshcode-close-set-stopped").start()
|
|
1621
|
+
done.wait(timeout=timeout_s)
|
|
1622
|
+
except Exception:
|
|
1623
|
+
try:
|
|
1624
|
+
ak = _get_api_key()
|
|
1625
|
+
if ak:
|
|
1626
|
+
be.sb_rpc("mc_set_desired_state", {"p_api_key": ak, "p_state": "stopped"})
|
|
1627
|
+
except Exception:
|
|
1628
|
+
pass
|
|
1629
|
+
|
|
1630
|
+
|
|
1631
|
+
def _close_to_stop_handler(signum=None, frame=None): # pragma: no cover - signal handler
|
|
1632
|
+
"""Terminal CLOSE -> stop this agent (no respawn). See the block comment above."""
|
|
1633
|
+
try:
|
|
1634
|
+
sys.stderr.write(
|
|
1635
|
+
f"[meshcode-mcp] terminal close (sig={signum}) — desired_state->stopped + release lease\n")
|
|
1636
|
+
sys.stderr.flush()
|
|
1637
|
+
except Exception:
|
|
1638
|
+
pass
|
|
1639
|
+
try:
|
|
1640
|
+
_flip_desired_state_stopped(timeout_s=3.0)
|
|
1641
|
+
except Exception:
|
|
1642
|
+
pass
|
|
1643
|
+
try:
|
|
1644
|
+
_release_lease_synchronous(timeout_s=1.0)
|
|
1645
|
+
except Exception:
|
|
1646
|
+
pass
|
|
1647
|
+
os._exit(0)
|
|
1648
|
+
|
|
1649
|
+
|
|
1650
|
+
def _install_close_to_stop_handlers() -> None:
|
|
1651
|
+
"""Register console-CLOSE handlers so closing the terminal STOPS the agent (b6da0d54).
|
|
1652
|
+
|
|
1653
|
+
Windows: SetConsoleCtrlHandler for CTRL_CLOSE/LOGOFF/SHUTDOWN — ALWAYS ON (a window
|
|
1654
|
+
close is never an ESC; reliably distinct). This is the prod fix (prod = Windows).
|
|
1655
|
+
|
|
1656
|
+
POSIX: SIGHUP->stop is GATED behind MESHCODE_CLOSE_STOP_SIGHUP=1 (default OFF). The
|
|
1657
|
+
run_server._diag_ignore deliberately IGNORES SIGHUP for ESC/session-restructure
|
|
1658
|
+
survival; reversing it unconditionally risks a false-stop on a transient SIGHUP.
|
|
1659
|
+
Enable only once verified that Claude ESC does not emit SIGHUP to this process.
|
|
1660
|
+
Never touches SIGINT (ESC) or SIGTERM (handled by the opt-in graceful handler)."""
|
|
1661
|
+
if sys.platform == "win32":
|
|
1662
|
+
try:
|
|
1663
|
+
import ctypes
|
|
1664
|
+
from ctypes import wintypes
|
|
1665
|
+
global _WIN_CTRL_HANDLER_REF
|
|
1666
|
+
_HANDLER = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.DWORD)
|
|
1667
|
+
CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT = 2, 5, 6
|
|
1668
|
+
|
|
1669
|
+
def _win_ctrl(ctrl_type):
|
|
1670
|
+
if ctrl_type in (CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT):
|
|
1671
|
+
_close_to_stop_handler(signum=f"win_ctrl:{ctrl_type}")
|
|
1672
|
+
return True
|
|
1673
|
+
return False # CTRL_C / CTRL_BREAK -> default handler (not our concern)
|
|
1674
|
+
|
|
1675
|
+
_WIN_CTRL_HANDLER_REF = _HANDLER(_win_ctrl)
|
|
1676
|
+
if ctypes.windll.kernel32.SetConsoleCtrlHandler(_WIN_CTRL_HANDLER_REF, True):
|
|
1677
|
+
_mc_log("registered Windows CTRL_CLOSE close=stop handler (b6da0d54)")
|
|
1678
|
+
else:
|
|
1679
|
+
_mc_log("SetConsoleCtrlHandler(close) returned 0", "warn")
|
|
1680
|
+
except Exception as e:
|
|
1681
|
+
_mc_log(f"could not register Windows close handler: {e}", "warn")
|
|
1682
|
+
else:
|
|
1683
|
+
if os.environ.get("MESHCODE_CLOSE_STOP_SIGHUP", "").lower() in ("1", "true", "yes"):
|
|
1684
|
+
import signal as _sig_mod
|
|
1685
|
+
try:
|
|
1686
|
+
_sig_mod.signal(_sig_mod.SIGHUP, _close_to_stop_handler)
|
|
1687
|
+
_mc_log("registered SIGHUP close=stop handler (MESHCODE_CLOSE_STOP_SIGHUP=1, b6da0d54)")
|
|
1688
|
+
except (ValueError, OSError) as e:
|
|
1689
|
+
_mc_log(f"could not register SIGHUP handler: {e}", "warn")
|
|
1690
|
+
# else: posix SIGHUP stays as run_server._diag_ignore (ESC-survival default)
|
|
1691
|
+
|
|
1692
|
+
|
|
1594
1693
|
# ── Crash logging + graceful shutdown ──────────────────────────
|
|
1595
1694
|
_SHUTDOWN_LOGGED = False
|
|
1596
1695
|
|
|
@@ -2645,6 +2744,14 @@ async def lifespan(_app):
|
|
|
2645
2744
|
except Exception as _sig_e:
|
|
2646
2745
|
log.debug(f"shutdown signal handler install failed: {_sig_e}")
|
|
2647
2746
|
|
|
2747
|
+
# Close-to-stop (task b6da0d54): closing the terminal flips desired_state->stopped
|
|
2748
|
+
# so hostd does not respawn (Samuel: 'al cerrar la terminal el agente se debe parar').
|
|
2749
|
+
# Windows CTRL_CLOSE always-on; posix SIGHUP gated (default OFF) — see the fn docstring.
|
|
2750
|
+
try:
|
|
2751
|
+
_install_close_to_stop_handlers()
|
|
2752
|
+
except Exception as _close_e:
|
|
2753
|
+
log.debug(f"close-to-stop handler install failed: {_close_e}")
|
|
2754
|
+
|
|
2648
2755
|
log.info(f"lifespan started — Realtime + heartbeat thread + orphan watchdog active for {AGENT_NAME}")
|
|
2649
2756
|
# Enable session recording in backend.py (hot-reloadable)
|
|
2650
2757
|
try:
|
|
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
|
{meshcode-2.11.110rc1 → meshcode-2.11.111}/meshcode/meshcode_mcp/test_prefs_claude_version.py
RENAMED
|
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
|