meshcode 2.11.27__tar.gz → 2.11.31__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 (231) hide show
  1. {meshcode-2.11.27 → meshcode-2.11.31}/PKG-INFO +1 -1
  2. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/server.py +49 -10
  4. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/setup_clients.py +208 -0
  5. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode.egg-info/PKG-INFO +1 -1
  6. {meshcode-2.11.27 → meshcode-2.11.31}/pyproject.toml +1 -1
  7. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_auto_update_hardening.py +58 -1
  8. {meshcode-2.11.27 → meshcode-2.11.31}/README.md +0 -0
  9. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/__main__.py +0 -0
  10. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/_stop_hook_template.py +0 -0
  11. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/ascii_art.py +0 -0
  12. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/atomic_push.py +0 -0
  13. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/cli.py +0 -0
  14. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/comms_v4.py +0 -0
  15. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/compat.py +0 -0
  16. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/daemon.py +0 -0
  17. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/date_parse.py +0 -0
  18. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/doctor.py +0 -0
  19. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/error_hints.py +0 -0
  20. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/exceptions.py +0 -0
  21. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/invites.py +0 -0
  22. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/launcher.py +0 -0
  23. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/launcher_install.py +0 -0
  24. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/__init__.py +0 -0
  25. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/__main__.py +0 -0
  26. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/backend.py +0 -0
  27. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/realtime.py +0 -0
  28. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  29. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/test_backend.py +0 -0
  30. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  31. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  32. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  33. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  34. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  35. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/preferences.py +0 -0
  36. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/protocol_handler.py +0 -0
  37. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/protocol_v2.py +0 -0
  38. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/quickstart.py +0 -0
  39. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/rpc_allowlist.py +0 -0
  40. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/run_agent.py +0 -0
  41. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/scripts/check_secrets.py +0 -0
  42. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/scripts/race_rate_harness.py +0 -0
  43. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/secrets.py +0 -0
  44. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/self_update.py +0 -0
  45. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/supervisor.py +0 -0
  46. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode/upload.py +0 -0
  47. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/comms_v4.py +0 -0
  48. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  49. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  50. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/cli.py +0 -0
  51. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  52. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/compat.py +0 -0
  53. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  54. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  55. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/invites.py +0 -0
  56. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  57. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  58. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  59. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  60. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  61. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  62. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  63. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  64. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  65. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  66. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  67. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  68. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  69. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  70. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  71. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  72. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  73. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  74. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/meshcode/upload.py +0 -0
  75. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  76. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_core.py +0 -0
  77. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  78. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  79. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  80. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  81. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  82. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  83. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  84. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  85. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  86. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  87. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  88. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  89. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  90. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  91. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  92. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  93. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  94. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  95. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  96. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  97. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  98. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  99. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  100. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  101. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  102. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  103. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  104. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  105. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  106. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  107. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  108. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  109. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  110. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  111. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  112. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  113. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  114. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  115. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/comms_v4.py +0 -0
  116. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  117. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  118. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/cli.py +0 -0
  119. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  120. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/compat.py +0 -0
  121. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  122. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  123. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/invites.py +0 -0
  124. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  125. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  126. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  127. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  128. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  129. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  130. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  131. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  132. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  133. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  134. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  135. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  136. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  137. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  138. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  139. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  140. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  141. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  142. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/meshcode/upload.py +0 -0
  143. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  144. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_core.py +0 -0
  145. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  146. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  147. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  148. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  149. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  150. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  151. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  152. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  153. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  154. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  155. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  156. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/comms_v4.py +0 -0
  157. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  158. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  159. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  160. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  161. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  162. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  163. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  164. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  165. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  166. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  167. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  168. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  169. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  170. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  171. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  172. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  173. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  174. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  175. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  176. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  177. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  178. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  179. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  180. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  181. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  182. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  183. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  184. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  185. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_core.py +0 -0
  186. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  187. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  188. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  189. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  190. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  191. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  192. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  193. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  194. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  195. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  196. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  197. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode.egg-info/SOURCES.txt +0 -0
  198. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode.egg-info/dependency_links.txt +0 -0
  199. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode.egg-info/entry_points.txt +0 -0
  200. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode.egg-info/requires.txt +0 -0
  201. {meshcode-2.11.27 → meshcode-2.11.31}/meshcode.egg-info/top_level.txt +0 -0
  202. {meshcode-2.11.27 → meshcode-2.11.31}/setup.cfg +0 -0
  203. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_boot_bug_regression.py +0 -0
  204. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_color_truecolor.py +0 -0
  205. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_core.py +0 -0
  206. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_cross_agent_messaging.py +0 -0
  207. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_date_parse.py +0 -0
  208. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_doctor.py +0 -0
  209. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_epistemic_v1_python_sdk.py +0 -0
  210. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  211. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_esc_deaf_state.py +0 -0
  212. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_exceptions.py +0 -0
  213. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_init_device_code.py +0 -0
  214. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_install_guard.py +0 -0
  215. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_lease_sigterm_release.py +0 -0
  216. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_mark_read_batch.py +0 -0
  217. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_migration_integrity.py +0 -0
  218. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_realtime_event_freshness.py +0 -0
  219. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_rls_cross_tenant.py +0 -0
  220. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_rpc_grants.py +0 -0
  221. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_rpc_migrations.py +0 -0
  222. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_run_agent_dry_run.py +0 -0
  223. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_run_agent_no_server_import.py +0 -0
  224. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_security_regressions.py +0 -0
  225. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_self_update_user_site.py +0 -0
  226. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_sentinel.py +0 -0
  227. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_setup_path.py +0 -0
  228. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_sleep_signals.py +0 -0
  229. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_status_enum_coverage.py +0 -0
  230. {meshcode-2.11.27 → meshcode-2.11.31}/tests/test_stay_on_loop_hook.py +0 -0
  231. {meshcode-2.11.27 → meshcode-2.11.31}/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.27
3
+ Version: 2.11.31
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.27"
2
+ __version__ = "2.11.31"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -227,18 +227,18 @@ def _kill_stale_mcp_process() -> None:
227
227
  _force_clear_lease_by_name(reason="legacy-lockfile-orphan")
228
228
  return
229
229
  _mc_log(f"Killing stale MCP process (PID {old_pid})")
230
+ # 2026-05-21 (Samuel directive RCA): the dying MCP server installs
231
+ # _diag_ignore for SIGTERM to keep the channel alive during tool
232
+ # cancellation (see run_server). SIGTERM is therefore always ignored
233
+ # by stale meshcode servers — sending it + sleeping 1s before SIGKILL
234
+ # was pure dead weight on the lifespan pre-yield critical path. Going
235
+ # straight to SIGKILL saves ~1s on every cold boot where a stale
236
+ # process exists. SIGKILL is uncatchable, so the kill is instant.
230
237
  try:
231
- os.kill(old_pid, _signal.SIGTERM)
232
- except OSError:
233
- pass
234
- import time
235
- time.sleep(1)
236
- try:
237
- os.kill(old_pid, 0)
238
238
  os.kill(old_pid, _signal.SIGKILL)
239
239
  _mc_log(f"Force-killed stale MCP process (PID {old_pid})")
240
240
  except OSError:
241
- pass # already dead after SIGTERM (rare handler ignores it)
241
+ pass # already dead race with previous process's own shutdown
242
242
  if old_instance_id:
243
243
  _release_lease_for_instance(old_instance_id, reason="post-sigkill")
244
244
  else:
@@ -3299,6 +3299,33 @@ def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
3299
3299
  return None
3300
3300
 
3301
3301
 
3302
+ def _attach_pending_tasks_to_resp(resp: Dict[str, Any]) -> Dict[str, Any]:
3303
+ """Surface this agent's open/in_progress assigned tasks on EVERY wait response.
3304
+
3305
+ Samuel directive 2026-05-21T23:54Z: agents must always advance open tasks.
3306
+ Previously `pending_tasks` only appeared in the timeout branch; when
3307
+ messages kept arriving the agent ping-ponged replies and never saw the
3308
+ hint, so tasks piled up. Now: every wait response (refused-by-messages,
3309
+ got_message, timeout) carries pending_tasks + pending_directive when
3310
+ this agent has open work. The agent's instruction prompt treats the
3311
+ directive as priority-1 over optional message replies.
3312
+ """
3313
+ try:
3314
+ pending = _get_pending_tasks_summary()
3315
+ if pending and isinstance(resp, dict):
3316
+ resp["pending_tasks"] = pending
3317
+ resp["pending_tasks_count"] = len(pending)
3318
+ titles = ", ".join(t.get("title", "")[:40] for t in pending[:3])
3319
+ resp["pending_directive"] = (
3320
+ f"You have {len(pending)} open task(s) assigned. Advance at least one "
3321
+ f"(claim / progress / complete) BEFORE processing optional messages or "
3322
+ f"re-entering wait. Tasks: {titles}"
3323
+ )
3324
+ except Exception:
3325
+ pass
3326
+ return resp
3327
+
3328
+
3302
3329
  def _try_auto_claim_task() -> Optional[Dict[str, str]]:
3303
3330
  """Auto-claim the oldest open task matching this agent's role.
3304
3331
 
@@ -3405,7 +3432,7 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
3405
3432
  if split["done_signals"]:
3406
3433
  resp["must_exit"] = True
3407
3434
  resp["exit_reason"] = "sleep authorization received — set status=sleeping and end session"
3408
- return resp
3435
+ return _attach_pending_tasks_to_resp(resp)
3409
3436
  # Ack-only batch — fall through to wait loop
3410
3437
  except Exception:
3411
3438
  pass
@@ -3516,7 +3543,7 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
3516
3543
  result.setdefault("must_exit", True)
3517
3544
  result.setdefault("exit_reason",
3518
3545
  "sleep authorization received — set status=sleeping and end session")
3519
- return result
3546
+ return _attach_pending_tasks_to_resp(result) if isinstance(result, dict) else result
3520
3547
  finally:
3521
3548
  _IN_WAIT = False
3522
3549
 
@@ -6104,6 +6131,18 @@ def _auto_update() -> None:
6104
6131
  # legitimate upgrade check. Per task 8d5eed7a.
6105
6132
  os.environ.pop("MESHCODE_UPDATED", None)
6106
6133
  return
6134
+ # MCP-serve guard: this function runs synchronously at the top of
6135
+ # run_server(), BEFORE FastMCP starts serving JSON-RPC. A blocking
6136
+ # `pip install --upgrade` (timeout 60s) here easily blows Claude
6137
+ # Code's MCP handshake window (~5s) — tools never register and the
6138
+ # agent boots into "MCP tools not available". The CLI-side
6139
+ # self_update.py (spawned by `meshcode go` before execv into the
6140
+ # editor) already handles user-facing upgrades; in MCP serve context
6141
+ # we should never block the handshake to chase a newer version.
6142
+ # Detected via the MESHCODE_MCP_SERVE=1 sentinel set in __main__.py.
6143
+ if os.environ.get("MESHCODE_MCP_SERVE") == "1":
6144
+ log.debug("[meshcode] Auto-update skipped in MCP serve subprocess (CLI handles upgrades)")
6145
+ return
6107
6146
 
6108
6147
  # Time-gate (task c0e7de87, 2026-05-19): the PyPI HEAD GET below has a 3s
6109
6148
  # timeout (line ~5430) and pip-install another 60s. Hammering PyPI on
@@ -565,6 +565,46 @@ errors when the source actually broke. Lovable build then ships the
565
565
  broken bundle.
566
566
 
567
567
  **Why:** practiced manually for weeks; codify so new FE agents inherit.
568
+ """,
569
+ "mobile-first-verify.md": """# /mobile-first-verify — 3-viewport check before task_complete
570
+
571
+ Before calling `meshcode_task_complete` on any UI-touching task, run
572
+ Playwright at three viewports and attach the result in the summary.
573
+
574
+ Viewports (canonical):
575
+ - iPhone SE 375 x 667
576
+ - iPhone 15 Pro 390 x 844
577
+ - iPad 768 x 1024
578
+
579
+ Recipe (load `mcp__playwright__browser_*` via ToolSearch first):
580
+
581
+ ```
582
+ for w,h in [(375,667),(390,844),(768,1024)]:
583
+ browser_resize(width=w, height=h)
584
+ browser_navigate(url=<route>)
585
+ browser_take_screenshot(filename=f"verify_{w}x{h}.png")
586
+ browser_console_messages() # capture errors
587
+ ```
588
+
589
+ Then `meshcode_task_complete(task_id, summary=<<EOF
590
+ verified: 3-viewport playwright
591
+ - 375x667: <path>
592
+ - 390x844: <path>
593
+ - 768x1024: <path>
594
+ console_errors: <count or "none">
595
+ EOF)`.
596
+
597
+ If the task is backend-only (DDL, RPCs, RLS, hooks, scripts — no user
598
+ surface), skip the playwright run but state `verified: backend-only,
599
+ no UI surface` in the summary so the auditor knows it was considered.
600
+
601
+ Reopen path: Samuel reviews; if visuals are broken he calls
602
+ `meshcode_task_reject(task_id, feedback=...)` which reopens with
603
+ review_feedback. No new RPC needed.
604
+
605
+ **Why:** MOBILE-FIRST-2 + Samuel mobile directive. Catches mobile
606
+ breakage at the agent before it reaches Samuel as a screenshot in
607
+ chat. Pairs with `/playwright-self-test` which covers desktop only.
568
608
  """,
569
609
  }
570
610
 
@@ -764,6 +804,134 @@ incidents from rapid-fire publish without bundling.
764
804
  """,
765
805
  }
766
806
 
807
+ # ============================================================
808
+ # SKILLS-6 — mobile-qa role bundle (MOBILE-FIRST-5)
809
+ # ============================================================
810
+ # Parallel verify lane: while front-end/front-2 ship code, a mobile-qa
811
+ # agent independently re-renders the affected route at 3 mobile/tablet
812
+ # viewports, captures screenshots + console errors, and reports findings
813
+ # back to the ship-er agent + commander. Removes verify-bottleneck from
814
+ # the coding agents and gives Samuel a second pair of eyes on every
815
+ # UI-touching commit.
816
+ #
817
+ # Agent type does NOT ship code. Pure verifier.
818
+ _MOBILE_QA_SKILLS = {
819
+ "mobile-qa-boot-loop.md": """# /mobile-qa-boot-loop — verify-only agent boot workflow
820
+
821
+ You are a mobile-qa agent. You DO NOT ship code. Your only job is to
822
+ re-render UI changes that other agents shipped, at three viewports,
823
+ and report what you see.
824
+
825
+ Boot sequence (after the standard meshcode boot):
826
+
827
+ 1. `meshcode_tasks(status_filter="open")` filter assignee == this agent
828
+ OR title/description mentions `needs_mobile_qa` / `verify` / `qa`.
829
+ 2. For each candidate task: claim → fetch the route or commit referenced
830
+ → run `/viewports-3-recipe` → assemble `/mobile-qa-report-format` →
831
+ `meshcode_send` the report to the original ship-er (look at
832
+ parent_task_id chain or claimed_by on the parent task) AND to
833
+ commander.
834
+ 3. `meshcode_task_complete` with the report inlined in summary.
835
+
836
+ If no verify tasks are queued: `meshcode_wait` and sit.
837
+
838
+ DO NOT:
839
+ - write code into `src/`
840
+ - propose RPC / DDL changes
841
+ - broadcast opinions about design
842
+
843
+ DO:
844
+ - screenshot + console + network requests
845
+ - report objective signals: layout overflow, console errors, network
846
+ 500s, missing assets
847
+
848
+ **Why:** MOBILE-FIRST-5. Parallel verify lane keeps shipping agents
849
+ unblocked while still catching mobile regressions before Samuel does.
850
+ """,
851
+ "viewports-3-recipe.md": """# /viewports-3-recipe — canonical 3-viewport playwright run
852
+
853
+ Three viewports, every time, in this order:
854
+
855
+ | Device | Width | Height |
856
+ |----------------|-------:|-------:|
857
+ | iPhone SE | 375 | 667 |
858
+ | iPhone 15 Pro | 390 | 844 |
859
+ | iPad | 768 | 1024 |
860
+
861
+ Recipe (load `mcp__playwright__browser_*` via ToolSearch if deferred):
862
+
863
+ ```python
864
+ for w, h in [(375, 667), (390, 844), (768, 1024)]:
865
+ browser_resize(width=w, height=h)
866
+ browser_navigate(url=<route>)
867
+ browser_wait_for(time=2) # let layout settle
868
+ browser_take_screenshot(filename=f"mqa_{w}x{h}.png")
869
+ console = browser_console_messages()
870
+ network = browser_network_requests()
871
+ # capture: scrollWidth > clientWidth → horizontal overflow flag
872
+ overflow = browser_evaluate(
873
+ function="() => document.documentElement.scrollWidth > "
874
+ "document.documentElement.clientWidth"
875
+ )
876
+ ```
877
+
878
+ For each viewport collect:
879
+ - screenshot path
880
+ - console_messages count + first-3 errors verbatim
881
+ - network_requests with status >= 400 (path + status)
882
+ - horizontal_overflow: bool
883
+
884
+ **Why:** standard viewports make reports comparable across days /
885
+ across agents. Console + network + overflow are the cheap signals that
886
+ catch ~80% of mobile regressions.
887
+ """,
888
+ "mobile-qa-report-format.md": """# /mobile-qa-report-format — canonical report shape
889
+
890
+ Report back to ship-er + commander in this exact JSON shape so consumers
891
+ can parse without LLM cost:
892
+
893
+ ```json
894
+ {
895
+ "type": "mobile_qa_report",
896
+ "parent_task_id": "<task that requested verify>",
897
+ "verified_commit": "<short sha>",
898
+ "route": "<path verified>",
899
+ "viewports": [
900
+ {
901
+ "label": "iPhone SE",
902
+ "size": "375x667",
903
+ "screenshot": "<abs path>",
904
+ "console_errors": 0,
905
+ "first_errors": [],
906
+ "network_4xx_5xx": [],
907
+ "horizontal_overflow": false
908
+ },
909
+ { "label": "iPhone 15 Pro", "size": "390x844", "...": "..." },
910
+ { "label": "iPad", "size": "768x1024", "...": "..." }
911
+ ],
912
+ "verdict": "pass" | "fail" | "warn",
913
+ "fail_reasons": [],
914
+ "samuel_status_line": "mobile-qa: <route> OK on 3 viewports / FAIL on iPhone SE (horizontal overflow + 2 console errors)"
915
+ }
916
+ ```
917
+
918
+ Verdict rubric:
919
+ - **pass**: 0 console_errors AND 0 network 4xx/5xx AND 0
920
+ horizontal_overflow on all 3 viewports.
921
+ - **warn**: any viewport has 1-2 console_errors that are clearly
922
+ third-party (analytics, etc) AND no overflow.
923
+ - **fail**: any console error from app code, any network 4xx/5xx, any
924
+ horizontal_overflow, OR layout clearly visually broken.
925
+
926
+ `samuel_status_line` is the 1-line summary Samuel sees in his feed;
927
+ make it actionable.
928
+
929
+ **Why:** structured reports let the FE agents auto-handle warn/fail
930
+ without commander intervention. Free-form text needs LLM parse on
931
+ every consumer; JSON does not.
932
+ """,
933
+ }
934
+
767
935
 
768
936
  def _write_generic_skills_bundle(ws: Path, role: str = "") -> None:
769
937
  """Write skill bundles to {ws}/.claude/skills/.
@@ -789,6 +957,8 @@ def _write_generic_skills_bundle(ws: Path, role: str = "") -> None:
789
957
  elif role_norm in ("commander", "mesh-commander", "zylo-commander",
790
958
  "bemate-commander"):
791
959
  role_bundle = _COMMANDER_SKILLS
960
+ elif role_norm in ("mobile-qa", "mobile_qa", "mobileqa", "mqa"):
961
+ role_bundle = _MOBILE_QA_SKILLS
792
962
 
793
963
  for fname, body in role_bundle.items():
794
964
  (skills_dir / fname).write_text(body, encoding="utf-8")
@@ -1004,6 +1174,44 @@ If `meshcode_wait()` times out, call it again with a 2× longer timeout (cap 180
1004
1174
  - Memory: `meshcode_remember(key, value)` for reusable learnings. Don't dump
1005
1175
  task summaries into memory — tasks already persist.
1006
1176
 
1177
+ ## Mobile-first UI verification (before task_complete)
1178
+
1179
+ Before calling `meshcode_task_complete` on ANY task that touches user-visible
1180
+ UI (routes, components, layouts, styles, mobile chrome), you MUST run
1181
+ Playwright at three viewports and attach the result in the completion summary.
1182
+
1183
+ Viewports (canonical):
1184
+ - iPhone SE 375 x 667
1185
+ - iPhone 15 Pro 390 x 844
1186
+ - iPad 768 x 1024
1187
+
1188
+ Workflow (uses `mcp__playwright__browser_*` — load via ToolSearch if deferred):
1189
+
1190
+ 1. For each viewport: `browser_resize` → `browser_navigate(<route>)` →
1191
+ `browser_take_screenshot(filename="verify_<W>x<H>.png")` →
1192
+ `browser_console_messages()`.
1193
+ 2. Pass the three screenshot paths + console-error count in the
1194
+ `summary` arg of `meshcode_task_complete`:
1195
+
1196
+ ```
1197
+ verified: 3-viewport playwright
1198
+ - 375x667: <path>
1199
+ - 390x844: <path>
1200
+ - 768x1024: <path>
1201
+ console_errors: <count or "none">
1202
+ ```
1203
+
1204
+ 3. Samuel reviews the summary. If visuals are broken he calls
1205
+ `meshcode_task_reject(task_id, feedback=...)` which reopens the task with
1206
+ `review_feedback`. No new RPC needed — uses the existing pipeline.
1207
+
1208
+ If the task is backend-only (DDL, RPCs, RLS, hooks, scripts — no UI surface)
1209
+ the playwright run is skipped, but state `verified: backend-only, no UI
1210
+ surface` in the summary so the rule is acknowledged.
1211
+
1212
+ **Why:** Samuel mobile directive (MOBILE-FIRST-2). Catches mobile breakage at
1213
+ the agent before it reaches Samuel as a screenshot in chat.
1214
+
1007
1215
  ## When to use sync vs async
1008
1216
 
1009
1217
  | Pattern | Tool | Why |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.27
3
+ Version: 2.11.31
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.27"
7
+ version = "2.11.31"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -37,12 +37,18 @@ def _check_boot_version_drift_inline():
37
37
 
38
38
 
39
39
  def _auto_update_inline_skeleton():
40
- """Subset of _auto_update covering the env-var gates only."""
40
+ """Subset of _auto_update covering the env-var gates only.
41
+
42
+ Order matters: the MCP-serve gate must fire BEFORE any network /
43
+ pip work so the MCP handshake window is never blocked.
44
+ """
41
45
  if os.environ.get("MESHCODE_AUTO_UPDATE", "1").lower() in ("0", "false", "no"):
42
46
  return "disabled"
43
47
  if os.environ.get("MESHCODE_UPDATED") == "1":
44
48
  os.environ.pop("MESHCODE_UPDATED", None)
45
49
  return "post_exec_skip"
50
+ if os.environ.get("MESHCODE_MCP_SERVE") == "1":
51
+ return "mcp_serve_skip"
46
52
  return "would_check_pypi"
47
53
 
48
54
 
@@ -114,6 +120,57 @@ def test_auto_update_disabled_case_variants(monkeypatch):
114
120
  assert _auto_update_inline_skeleton() == "disabled", f"value {val!r} failed"
115
121
 
116
122
 
123
+ # ---------------------------------------------------------------------------
124
+ # 3b. MCP-serve gate (added 2026-05-20 / 2.11.28)
125
+ #
126
+ # Symptom: right after publishing 2.11.27, commander agents booted with
127
+ # "MCP meshcode tools are not available" — first-turn deferred-tools list
128
+ # missing all meshcode_* tools. RC: _auto_update runs synchronously at the
129
+ # top of run_server() and does a blocking `pip install --upgrade` (60s
130
+ # timeout). When PyPI advertises a newer version, the install easily
131
+ # exceeds Claude Code's ~5s MCP handshake window and tools never register.
132
+ # Fix: skip _auto_update entirely when MESHCODE_MCP_SERVE=1; the CLI's
133
+ # self_update.py handles user-facing upgrades before execv.
134
+ # ---------------------------------------------------------------------------
135
+
136
+ def test_mcp_serve_sentinel_skips_update(monkeypatch):
137
+ monkeypatch.setenv("MESHCODE_MCP_SERVE", "1")
138
+ monkeypatch.delenv("MESHCODE_AUTO_UPDATE", raising=False)
139
+ monkeypatch.delenv("MESHCODE_UPDATED", raising=False)
140
+ assert _auto_update_inline_skeleton() == "mcp_serve_skip"
141
+
142
+
143
+ def test_mcp_serve_gate_runs_before_pypi(monkeypatch):
144
+ """MCP-serve gate must short-circuit before any 'would_check_pypi'
145
+ branch fires — otherwise the gate is moot because the slow path
146
+ runs anyway."""
147
+ monkeypatch.setenv("MESHCODE_MCP_SERVE", "1")
148
+ monkeypatch.delenv("MESHCODE_AUTO_UPDATE", raising=False)
149
+ monkeypatch.delenv("MESHCODE_UPDATED", raising=False)
150
+ assert _auto_update_inline_skeleton() != "would_check_pypi"
151
+
152
+
153
+ def test_disabled_still_wins_over_mcp_serve(monkeypatch):
154
+ """Explicit MESHCODE_AUTO_UPDATE=0 must remain the highest-priority
155
+ opt-out — useful for CI / debugging where the user wants to be
156
+ 100% certain no pip side-effects fire."""
157
+ monkeypatch.setenv("MESHCODE_AUTO_UPDATE", "0")
158
+ monkeypatch.setenv("MESHCODE_MCP_SERVE", "1")
159
+ monkeypatch.delenv("MESHCODE_UPDATED", raising=False)
160
+ assert _auto_update_inline_skeleton() == "disabled"
161
+
162
+
163
+ def test_post_exec_sentinel_still_wins_over_mcp_serve(monkeypatch):
164
+ """If we just re-execed after an upgrade, the UPDATED sentinel
165
+ must still take precedence so it gets cleared (otherwise it
166
+ persists into subprocess children)."""
167
+ monkeypatch.setenv("MESHCODE_UPDATED", "1")
168
+ monkeypatch.setenv("MESHCODE_MCP_SERVE", "1")
169
+ monkeypatch.delenv("MESHCODE_AUTO_UPDATE", raising=False)
170
+ assert _auto_update_inline_skeleton() == "post_exec_skip"
171
+ assert "MESHCODE_UPDATED" not in os.environ
172
+
173
+
117
174
  # ---------------------------------------------------------------------------
118
175
  # 4. PyPI/pip behaviour matrix (mocked — covers the cells that don't need
119
176
  # a live relaunch). Uses an inlined version of the post-gate _auto_update
File without changes
File without changes