meshcode 2.11.27__tar.gz → 2.11.29__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.29}/PKG-INFO +1 -1
  2. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/backend.py +31 -5
  4. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/server.py +14 -0
  5. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/setup_clients.py +208 -0
  6. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode.egg-info/PKG-INFO +1 -1
  7. {meshcode-2.11.27 → meshcode-2.11.29}/pyproject.toml +1 -1
  8. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_auto_update_hardening.py +58 -1
  9. {meshcode-2.11.27 → meshcode-2.11.29}/README.md +0 -0
  10. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/__main__.py +0 -0
  11. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/_stop_hook_template.py +0 -0
  12. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/ascii_art.py +0 -0
  13. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/atomic_push.py +0 -0
  14. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/cli.py +0 -0
  15. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/comms_v4.py +0 -0
  16. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/compat.py +0 -0
  17. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/daemon.py +0 -0
  18. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/date_parse.py +0 -0
  19. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/doctor.py +0 -0
  20. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/error_hints.py +0 -0
  21. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/exceptions.py +0 -0
  22. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/invites.py +0 -0
  23. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/launcher.py +0 -0
  24. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/launcher_install.py +0 -0
  25. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/__init__.py +0 -0
  26. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/__main__.py +0 -0
  27. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/realtime.py +0 -0
  28. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  29. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/test_backend.py +0 -0
  30. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  31. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  32. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  33. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  34. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  35. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/preferences.py +0 -0
  36. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/protocol_handler.py +0 -0
  37. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/protocol_v2.py +0 -0
  38. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/quickstart.py +0 -0
  39. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/rpc_allowlist.py +0 -0
  40. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/run_agent.py +0 -0
  41. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/scripts/check_secrets.py +0 -0
  42. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/scripts/race_rate_harness.py +0 -0
  43. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/secrets.py +0 -0
  44. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/self_update.py +0 -0
  45. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/supervisor.py +0 -0
  46. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode/upload.py +0 -0
  47. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/comms_v4.py +0 -0
  48. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  49. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  50. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/cli.py +0 -0
  51. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  52. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/compat.py +0 -0
  53. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  54. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  55. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/invites.py +0 -0
  56. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  57. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  58. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  59. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  60. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  61. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  62. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  63. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  64. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  65. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  66. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  67. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  68. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  69. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  70. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  71. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  72. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  73. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  74. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/meshcode/upload.py +0 -0
  75. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  76. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_core.py +0 -0
  77. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  78. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  79. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  80. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  81. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  82. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  83. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  84. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  85. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  86. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  87. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  88. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  89. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  90. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  91. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  92. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  93. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  94. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  95. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  96. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  97. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  98. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  99. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  100. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  101. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  102. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  103. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  104. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  105. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  106. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  107. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  108. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  109. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  110. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  111. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  112. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  113. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  114. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  115. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/comms_v4.py +0 -0
  116. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  117. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  118. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/cli.py +0 -0
  119. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  120. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/compat.py +0 -0
  121. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  122. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  123. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/invites.py +0 -0
  124. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  125. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  126. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  127. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  128. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  129. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  130. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  131. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  132. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  133. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  134. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  135. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  136. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  137. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  138. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  139. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  140. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  141. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  142. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/meshcode/upload.py +0 -0
  143. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  144. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_core.py +0 -0
  145. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  146. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  147. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  148. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  149. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  150. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  151. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  152. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  153. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  154. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  155. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  156. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/comms_v4.py +0 -0
  157. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  158. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  159. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  160. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  161. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  162. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  163. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  164. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  165. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  166. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  167. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  168. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  169. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  170. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  171. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  172. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  173. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  174. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  175. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  176. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  177. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  178. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  179. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  180. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  181. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  182. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  183. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  184. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  185. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_core.py +0 -0
  186. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  187. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  188. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  189. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  190. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  191. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  192. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  193. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  194. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  195. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  196. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  197. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode.egg-info/SOURCES.txt +0 -0
  198. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode.egg-info/dependency_links.txt +0 -0
  199. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode.egg-info/entry_points.txt +0 -0
  200. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode.egg-info/requires.txt +0 -0
  201. {meshcode-2.11.27 → meshcode-2.11.29}/meshcode.egg-info/top_level.txt +0 -0
  202. {meshcode-2.11.27 → meshcode-2.11.29}/setup.cfg +0 -0
  203. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_boot_bug_regression.py +0 -0
  204. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_color_truecolor.py +0 -0
  205. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_core.py +0 -0
  206. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_cross_agent_messaging.py +0 -0
  207. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_date_parse.py +0 -0
  208. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_doctor.py +0 -0
  209. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_epistemic_v1_python_sdk.py +0 -0
  210. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  211. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_esc_deaf_state.py +0 -0
  212. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_exceptions.py +0 -0
  213. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_init_device_code.py +0 -0
  214. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_install_guard.py +0 -0
  215. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_lease_sigterm_release.py +0 -0
  216. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_mark_read_batch.py +0 -0
  217. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_migration_integrity.py +0 -0
  218. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_realtime_event_freshness.py +0 -0
  219. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_rls_cross_tenant.py +0 -0
  220. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_rpc_grants.py +0 -0
  221. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_rpc_migrations.py +0 -0
  222. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_run_agent_dry_run.py +0 -0
  223. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_run_agent_no_server_import.py +0 -0
  224. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_security_regressions.py +0 -0
  225. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_self_update_user_site.py +0 -0
  226. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_sentinel.py +0 -0
  227. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_setup_path.py +0 -0
  228. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_sleep_signals.py +0 -0
  229. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_status_enum_coverage.py +0 -0
  230. {meshcode-2.11.27 → meshcode-2.11.29}/tests/test_stay_on_loop_hook.py +0 -0
  231. {meshcode-2.11.27 → meshcode-2.11.29}/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.29
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.29"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -428,10 +428,16 @@ _recording_project_id = ""
428
428
  _recording_agent_name = ""
429
429
  _recording_session_id = ""
430
430
 
431
- # RPCs that should NOT be recorded (internal/heartbeat/recording itself)
431
+ # RPCs that should NOT be recorded (internal/heartbeat/recording itself).
432
+ # M3a (SUPABASE-PROD-QUOTA-CRITICAL 2026-05-22): added mc_task_list +
433
+ # mc_count_pending + mc_mark_message_read — these were generating 87% of
434
+ # all session_events (~46k of 53k in last 6h) as null-tool tool_call rows
435
+ # from the wait-loop polling. Pure infrastructure noise — no analytic
436
+ # value. The session_events table was 1.2 GB driven mostly by these.
432
437
  _SKIP_RECORDING = {"mc_heartbeat", "mc_record_event", "mc_agent_set_status_by_api_key",
433
438
  "mc_acquire_agent_lease", "mc_release_agent_lease",
434
- "mc_update_agent", "mc_get_agents"}
439
+ "mc_update_agent", "mc_get_agents",
440
+ "mc_task_list", "mc_count_pending", "mc_mark_message_read"}
435
441
 
436
442
 
437
443
  def _get_api_key() -> Optional[str]:
@@ -963,13 +969,22 @@ def read_inbox(project_id: str, agent: str, mark_read: bool = True, api_key: Opt
963
969
 
964
970
 
965
971
  def count_pending(project_id: str, agent: str, api_key: Optional[str] = None) -> int:
966
- # Use SECURITY DEFINER RPC when api_key is available
972
+ # Use SECURITY DEFINER RPC when api_key is available.
973
+ # SEC-5 R-SEC5-A: call rate-limited _rl wrapper. Server-side returns
974
+ # cached payload on limit so Python contract stays {ok:true, count:int}.
975
+ # Falls back to non-rl on 404 if the wrapper isn't deployed yet.
967
976
  if api_key:
968
- result = sb_rpc("mc_count_pending", {
977
+ result = sb_rpc("mc_count_pending_rl", {
969
978
  "p_api_key": api_key,
970
979
  "p_project_id": project_id,
971
980
  "p_agent_name": agent,
972
981
  })
982
+ if isinstance(result, dict) and result.get("error_code") == "404":
983
+ result = sb_rpc("mc_count_pending", {
984
+ "p_api_key": api_key,
985
+ "p_project_id": project_id,
986
+ "p_agent_name": agent,
987
+ })
973
988
  if isinstance(result, dict) and result.get("ok"):
974
989
  return result.get("count", 0)
975
990
  # Fall through to direct query if RPC doesn't exist yet
@@ -1242,13 +1257,24 @@ def task_list(api_key, project_id, agent, status_filter=None, include_done=False
1242
1257
  cached = _TASK_LIST_CACHE.get(cache_key)
1243
1258
  if cached and (now - cached[1]) < _TASK_LIST_MIN_INTERVAL:
1244
1259
  return cached[0]
1245
- result = sb_rpc("mc_task_list", {
1260
+ # SEC-5 R-SEC5-A: call rate-limited _rl wrapper. Returns same shape as
1261
+ # original (with extra rate_limited/remaining metadata Python ignores).
1262
+ # Falls back to non-rl on 404 if wrapper isn't deployed.
1263
+ result = sb_rpc("mc_task_list_rl", {
1246
1264
  "p_api_key": api_key,
1247
1265
  "p_project_id": project_id,
1248
1266
  "p_agent": agent,
1249
1267
  "p_status_filter": status_filter,
1250
1268
  "p_include_done": include_done,
1251
1269
  })
1270
+ if isinstance(result, dict) and result.get("error_code") == "404":
1271
+ result = sb_rpc("mc_task_list", {
1272
+ "p_api_key": api_key,
1273
+ "p_project_id": project_id,
1274
+ "p_agent": agent,
1275
+ "p_status_filter": status_filter,
1276
+ "p_include_done": include_done,
1277
+ })
1252
1278
  with _TASK_LIST_CACHE_LOCK:
1253
1279
  if len(_TASK_LIST_CACHE) >= _TASK_LIST_CACHE_MAX:
1254
1280
  oldest_key = min(_TASK_LIST_CACHE, key=lambda k: _TASK_LIST_CACHE[k][1])
@@ -1646,6 +1646,8 @@ def _build_instructions() -> str:
1646
1646
 
1647
1647
  RULES: MCP tools only. Tasks > messages. Messages <100 tokens (long → task). No empty acks, JSON only. Thread via in_reply_to. sensitive=True for secrets. Sync vs async: for turn-based/shared-state work (chess, lock-step, "who goes first"), use meshcode_call (sync RPC, 30s) — async meshcode_send crosses ~50%/turn between same-model agents and yields-pongs.
1648
1648
 
1649
+ CLOSE TASKS IMMEDIATELY (#2 rule, sammybenu 2026-05-22T21:06Z): every time you finish/ship/deliver work for a claimed task, call meshcode_task_complete BEFORE re-entering wait. NO "I'll close it after one more thing." NO leaving claimed tasks lingering in_progress while you do something else — that creates phantom in-progress on the dashboard and the human gets angry. If the work needs human review, set requires_approval=true at task_create OR call meshcode_task_complete (it routes to in_review if reviewer set). The mesh dashboard reflects mc_tasks.status in real-time; stale in_progress = lying to the human.
1650
+
1649
1651
  SESSION START (run NOW, don't wait for input). If tool schemas are deferred:
1650
1652
  ToolSearch(query="select:meshcode_set_status,meshcode_check,meshcode_tasks,meshcode_auto_wake,meshcode_status,meshcode_wait,meshcode_send,meshcode_call,meshcode_claim,meshcode_task_claim,meshcode_task_complete,meshcode_remember,meshcode_recall")
1651
1653
  Then: set_status(online,ready) → check() → tasks() → auto_wake() → status() → wait(). Don't ask user "what to work on" — the mesh tells you.
@@ -6104,6 +6106,18 @@ def _auto_update() -> None:
6104
6106
  # legitimate upgrade check. Per task 8d5eed7a.
6105
6107
  os.environ.pop("MESHCODE_UPDATED", None)
6106
6108
  return
6109
+ # MCP-serve guard: this function runs synchronously at the top of
6110
+ # run_server(), BEFORE FastMCP starts serving JSON-RPC. A blocking
6111
+ # `pip install --upgrade` (timeout 60s) here easily blows Claude
6112
+ # Code's MCP handshake window (~5s) — tools never register and the
6113
+ # agent boots into "MCP tools not available". The CLI-side
6114
+ # self_update.py (spawned by `meshcode go` before execv into the
6115
+ # editor) already handles user-facing upgrades; in MCP serve context
6116
+ # we should never block the handshake to chase a newer version.
6117
+ # Detected via the MESHCODE_MCP_SERVE=1 sentinel set in __main__.py.
6118
+ if os.environ.get("MESHCODE_MCP_SERVE") == "1":
6119
+ log.debug("[meshcode] Auto-update skipped in MCP serve subprocess (CLI handles upgrades)")
6120
+ return
6107
6121
 
6108
6122
  # Time-gate (task c0e7de87, 2026-05-19): the PyPI HEAD GET below has a 3s
6109
6123
  # 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.29
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.29"
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