meshcode 2.10.93__tar.gz → 2.10.94__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 (201) hide show
  1. {meshcode-2.10.93 → meshcode-2.10.94}/PKG-INFO +6 -1
  2. {meshcode-2.10.93 → meshcode-2.10.94}/README.md +5 -0
  3. meshcode-2.10.94/meshcode/__init__.py +82 -0
  4. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/server.py +72 -0
  5. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode.egg-info/PKG-INFO +6 -1
  6. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode.egg-info/SOURCES.txt +1 -0
  7. {meshcode-2.10.93 → meshcode-2.10.94}/pyproject.toml +1 -1
  8. meshcode-2.10.94/tests/test_auto_update_hardening.py +238 -0
  9. meshcode-2.10.93/meshcode/__init__.py +0 -82
  10. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/ascii_art.py +0 -0
  11. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/cli.py +0 -0
  12. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/comms_v4.py +0 -0
  13. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/compat.py +0 -0
  14. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/error_hints.py +0 -0
  15. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/exceptions.py +0 -0
  16. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/invites.py +0 -0
  17. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/launcher.py +0 -0
  18. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/launcher_install.py +0 -0
  19. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/__init__.py +0 -0
  20. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/__main__.py +0 -0
  21. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/backend.py +0 -0
  22. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/realtime.py +0 -0
  23. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/test_backend.py +0 -0
  24. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  25. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  26. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/preferences.py +0 -0
  27. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/protocol_v2.py +0 -0
  28. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/quickstart.py +0 -0
  29. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/run_agent.py +0 -0
  30. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/secrets.py +0 -0
  31. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/self_update.py +0 -0
  32. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/setup_clients.py +0 -0
  33. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/supervisor.py +0 -0
  34. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode/upload.py +0 -0
  35. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/comms_v4.py +0 -0
  36. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  37. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  38. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/cli.py +0 -0
  39. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  40. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/compat.py +0 -0
  41. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  42. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  43. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/invites.py +0 -0
  44. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  45. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  46. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  47. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  48. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  49. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  50. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  51. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  52. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  53. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  54. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  55. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  56. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  57. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  58. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  59. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  60. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  61. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  62. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/meshcode/upload.py +0 -0
  63. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  64. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_core.py +0 -0
  65. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  66. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  67. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  68. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  69. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  70. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  71. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  72. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  73. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  74. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  75. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  76. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  77. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  78. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  79. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  80. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  81. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  82. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  83. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  84. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  85. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  86. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  87. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  88. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  89. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  90. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  91. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  92. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  93. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  94. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  95. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  96. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  97. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  98. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  99. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  100. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  101. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  102. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  103. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/comms_v4.py +0 -0
  104. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  105. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  106. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/cli.py +0 -0
  107. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  108. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/compat.py +0 -0
  109. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  110. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  111. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/invites.py +0 -0
  112. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  113. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  114. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  115. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  116. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  117. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  118. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  119. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  120. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  121. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  122. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  123. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  124. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  125. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  126. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  127. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  128. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  129. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  130. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/meshcode/upload.py +0 -0
  131. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  132. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_core.py +0 -0
  133. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  134. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  135. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  136. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  137. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  138. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  139. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  140. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  141. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  142. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  143. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  144. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/comms_v4.py +0 -0
  145. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  146. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  147. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  148. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  149. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  150. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  151. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  152. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  153. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  154. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  155. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  156. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  157. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  158. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  159. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  160. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  161. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  162. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  163. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  164. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  165. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  166. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  167. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  168. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  169. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  170. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  171. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  172. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  173. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_core.py +0 -0
  174. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  175. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  176. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  177. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  178. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  179. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  180. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  181. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  182. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  183. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  184. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  185. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode.egg-info/dependency_links.txt +0 -0
  186. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode.egg-info/entry_points.txt +0 -0
  187. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode.egg-info/requires.txt +0 -0
  188. {meshcode-2.10.93 → meshcode-2.10.94}/meshcode.egg-info/top_level.txt +0 -0
  189. {meshcode-2.10.93 → meshcode-2.10.94}/setup.cfg +0 -0
  190. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_core.py +0 -0
  191. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_cross_agent_messaging.py +0 -0
  192. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_esc_deaf_state.py +0 -0
  193. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_exceptions.py +0 -0
  194. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_mark_read_batch.py +0 -0
  195. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_migration_integrity.py +0 -0
  196. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_realtime_event_freshness.py +0 -0
  197. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_rls_cross_tenant.py +0 -0
  198. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_rpc_migrations.py +0 -0
  199. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_security_regressions.py +0 -0
  200. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_sentinel.py +0 -0
  201. {meshcode-2.10.93 → meshcode-2.10.94}/tests/test_status_enum_coverage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.93
3
+ Version: 2.10.94
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -422,6 +422,11 @@ $env:MESHCODE_PROJECT_ID="your-project-uuid" # Windows PowerShell
422
422
 
423
423
  You can also run `meshcode doctor` (v2.10.41+) to diagnose stale paths, missing dependencies, and config issues across all your workspaces.
424
424
 
425
+ **9b. Windows: first relaunch shows the old version after a PyPI upgrade**
426
+ Auto-update on Unix uses `os.execv` to swap the running Python image in-place — one launch, latest code (v2.10.93+). On Windows this isn't possible: an `os.execv` replacement breaks Claude Code's stdio pipe to the MCP child (the new process has a different PID). Meshcode therefore installs the new version but defers the swap to the **next** launch on Windows. Expect: `[meshcode] note: Windows defers auto-update to next launch ...` on stderr, then close and re-open Claude Code once to get the new code. To force-load now, run `pip install --upgrade meshcode` manually before launching Claude Code.
427
+
428
+ If the dashboard tags an agent as having `boot_version_drift`, that means pip wrote the new version to disk but our running process is still the old one — typically benign on Windows (next launch fixes it) and worth investigating on Unix (path-precedence regression).
429
+
425
430
  **10. `MCP server failed to start` in the Claude Code `/mcp` panel**
426
431
  Run `claude --debug` to see the underlying error. Nine times out of ten it's a stale or missing key — run `meshcode login mc_xxx` again.
427
432
 
@@ -396,6 +396,11 @@ $env:MESHCODE_PROJECT_ID="your-project-uuid" # Windows PowerShell
396
396
 
397
397
  You can also run `meshcode doctor` (v2.10.41+) to diagnose stale paths, missing dependencies, and config issues across all your workspaces.
398
398
 
399
+ **9b. Windows: first relaunch shows the old version after a PyPI upgrade**
400
+ Auto-update on Unix uses `os.execv` to swap the running Python image in-place — one launch, latest code (v2.10.93+). On Windows this isn't possible: an `os.execv` replacement breaks Claude Code's stdio pipe to the MCP child (the new process has a different PID). Meshcode therefore installs the new version but defers the swap to the **next** launch on Windows. Expect: `[meshcode] note: Windows defers auto-update to next launch ...` on stderr, then close and re-open Claude Code once to get the new code. To force-load now, run `pip install --upgrade meshcode` manually before launching Claude Code.
401
+
402
+ If the dashboard tags an agent as having `boot_version_drift`, that means pip wrote the new version to disk but our running process is still the old one — typically benign on Windows (next launch fixes it) and worth investigating on Unix (path-precedence regression).
403
+
399
404
  **10. `MCP server failed to start` in the Claude Code `/mcp` panel**
400
405
  Run `claude --debug` to see the underlying error. Nine times out of ten it's a stale or missing key — run `meshcode login mc_xxx` again.
401
406
 
@@ -0,0 +1,82 @@
1
+ """MeshCode — Real-time communication between AI agents."""
2
+ __version__ = "2.10.94"
3
+
4
+ # Exception hierarchy — eagerly imported (lightweight, no deps)
5
+ from meshcode.exceptions import ( # noqa: F401
6
+ MeshCodeError,
7
+ AuthError,
8
+ RPCError,
9
+ MeshCodeTimeoutError,
10
+ MeshCodeConnectionError,
11
+ )
12
+
13
+ # Public API — lazy imports to avoid heavy deps at import time
14
+ def __getattr__(name):
15
+ if name == "backend":
16
+ from meshcode.meshcode_mcp import backend
17
+ return backend
18
+ if name in _BACKEND_EXPORTS:
19
+ from meshcode.meshcode_mcp import backend
20
+ return getattr(backend, name)
21
+ if name in _SECRETS_EXPORTS:
22
+ from meshcode import secrets
23
+ return getattr(secrets, name)
24
+ raise AttributeError(f"module 'meshcode' has no attribute {name!r}")
25
+
26
+
27
+ # Backend: core messaging & agent management
28
+ _BACKEND_EXPORTS = {
29
+ "send_message",
30
+ "read_inbox",
31
+ "count_pending",
32
+ "get_board",
33
+ "heartbeat",
34
+ "set_status",
35
+ "register_agent",
36
+ "get_project_id",
37
+ "sb_rpc",
38
+ "task_create",
39
+ "task_list",
40
+ "encrypt_payload",
41
+ "decrypt_payload",
42
+ }
43
+
44
+ # Secrets: credential management
45
+ _SECRETS_EXPORTS = {
46
+ "get_api_key",
47
+ "set_api_key",
48
+ "list_profiles",
49
+ }
50
+
51
+ __all__ = [
52
+ "__version__",
53
+ "backend",
54
+ # Exceptions
55
+ "MeshCodeError",
56
+ "AuthError",
57
+ "RPCError",
58
+ "MeshCodeTimeoutError",
59
+ "MeshCodeConnectionError",
60
+ # Messaging
61
+ "send_message",
62
+ "read_inbox",
63
+ "count_pending",
64
+ # Agent management
65
+ "register_agent",
66
+ "get_project_id",
67
+ "get_board",
68
+ "heartbeat",
69
+ "set_status",
70
+ # Tasks
71
+ "task_create",
72
+ "task_list",
73
+ # Low-level
74
+ "sb_rpc",
75
+ # Encryption
76
+ "encrypt_payload",
77
+ "decrypt_payload",
78
+ # Credentials
79
+ "get_api_key",
80
+ "set_api_key",
81
+ "list_profiles",
82
+ ]
@@ -1747,6 +1747,25 @@ async def lifespan(_app):
1747
1747
  be.set_status(_PROJECT_ID, AGENT_NAME, "idle", "MCP session active", api_key=_get_api_key())
1748
1748
  log.info(f"[meshcode] Agent {AGENT_NAME} online — initial heartbeat sent")
1749
1749
  _log_activity_bg("agent_online", f"{AGENT_NAME} came online")
1750
+ # Soft-relay any boot_version_drift detected at startup. One-shot:
1751
+ # consume the env-var sentinel set in run_server() so we don't
1752
+ # spam the commander on every retry attempt or future heartbeat.
1753
+ _drift = os.environ.pop("_MESHCODE_BOOT_DRIFT", None)
1754
+ if _drift:
1755
+ try:
1756
+ be.send_message(
1757
+ _PROJECT_ID, AGENT_NAME, "mesh-commander",
1758
+ {
1759
+ "type": "boot_version_drift",
1760
+ "drift": _drift,
1761
+ "agent": AGENT_NAME,
1762
+ "platform": sys.platform,
1763
+ },
1764
+ msg_type="report",
1765
+ api_key=_get_api_key(),
1766
+ )
1767
+ except Exception as _drift_e:
1768
+ log.debug(f"boot_version_drift relay failed: {_drift_e}")
1750
1769
  break
1751
1770
  except Exception as e:
1752
1771
  log.warning(f"initial heartbeat attempt {_attempt+1} failed: {e}")
@@ -4305,6 +4324,12 @@ def _auto_update() -> None:
4305
4324
  log.debug("[meshcode] Auto-update disabled (MESHCODE_AUTO_UPDATE=0)")
4306
4325
  return
4307
4326
  if os.environ.get("MESHCODE_UPDATED") == "1":
4327
+ # Sentinel was set by the parent process right before it execv'd
4328
+ # into us. Clear it now — single-use per upgrade. Without this, any
4329
+ # subprocess we spawn (or a downstream re-exec triggered by some
4330
+ # other code path) inherits MESHCODE_UPDATED=1 and skips the next
4331
+ # legitimate upgrade check. Per task 8d5eed7a.
4332
+ os.environ.pop("MESHCODE_UPDATED", None)
4308
4333
  return
4309
4334
 
4310
4335
  import subprocess
@@ -4389,9 +4414,56 @@ def _auto_update() -> None:
4389
4414
  log.debug(f"[meshcode] Re-exec failed: {e}, continuing with old version")
4390
4415
 
4391
4416
 
4417
+ def _check_boot_version_drift():
4418
+ """Compare pip-installed version (on disk) vs imported __version__.
4419
+
4420
+ Returns (installed, loaded) tuple if they differ, else None. Used as a
4421
+ canary for "auto-update wrote new code to disk but our running process
4422
+ is still the old version" — should be unreachable on Unix after the
4423
+ 2.10.93 execv fix, but the empirical check guards against:
4424
+ - path-precedence regressions (multiple meshcode installs)
4425
+ - Windows MCP mode (we deliberately defer there)
4426
+ - execv failures that fall through to the old version
4427
+ Best-effort: must not raise.
4428
+ """
4429
+ try:
4430
+ from importlib.metadata import version as _md_version
4431
+ from meshcode import __version__ as _loaded
4432
+ _installed = _md_version("meshcode")
4433
+ if _installed != _loaded:
4434
+ return (_installed, _loaded)
4435
+ except Exception:
4436
+ pass
4437
+ return None
4438
+
4439
+
4392
4440
  def run_server():
4393
4441
  """Start the MCP server on stdio (default for Claude Code)."""
4394
4442
  _auto_update()
4443
+ # Telemetry canary: surface any installed/loaded version drift loudly
4444
+ # to stderr so it shows up in Claude Code's MCP server output. The first
4445
+ # heartbeat carries the loaded version to mc_agents; this stderr line is
4446
+ # the human-visible signal that auto-update did NOT land cleanly.
4447
+ _drift = _check_boot_version_drift()
4448
+ if _drift is not None:
4449
+ _installed, _loaded = _drift
4450
+ print(
4451
+ f"[meshcode] WARN boot_version_drift: installed={_installed} loaded={_loaded} "
4452
+ f"— pip has a newer build on disk than what's running in this process. "
4453
+ f"Restart should pick it up. If it persists, check sys.path precedence.",
4454
+ file=sys.stderr,
4455
+ )
4456
+ # Stash for the heartbeat thread to relay to commander on first beat.
4457
+ os.environ["_MESHCODE_BOOT_DRIFT"] = f"{_installed}->{_loaded}"
4458
+ if sys.platform == "win32":
4459
+ # Windows can't execv-preserve stdio; auto-update defers to next boot.
4460
+ # Always announce so Windows users know why their first launch may
4461
+ # still show an older version even with PyPI updated.
4462
+ print(
4463
+ "[meshcode] note: Windows defers auto-update to next launch "
4464
+ "(execv preserves Claude Code's stdio pipe only on Unix).",
4465
+ file=sys.stderr,
4466
+ )
4395
4467
  print(
4396
4468
  f"[meshcode-mcp] Starting server for {AGENT_NAME}@{PROJECT_NAME}",
4397
4469
  file=sys.stderr,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.93
3
+ Version: 2.10.94
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -422,6 +422,11 @@ $env:MESHCODE_PROJECT_ID="your-project-uuid" # Windows PowerShell
422
422
 
423
423
  You can also run `meshcode doctor` (v2.10.41+) to diagnose stale paths, missing dependencies, and config issues across all your workspaces.
424
424
 
425
+ **9b. Windows: first relaunch shows the old version after a PyPI upgrade**
426
+ Auto-update on Unix uses `os.execv` to swap the running Python image in-place — one launch, latest code (v2.10.93+). On Windows this isn't possible: an `os.execv` replacement breaks Claude Code's stdio pipe to the MCP child (the new process has a different PID). Meshcode therefore installs the new version but defers the swap to the **next** launch on Windows. Expect: `[meshcode] note: Windows defers auto-update to next launch ...` on stderr, then close and re-open Claude Code once to get the new code. To force-load now, run `pip install --upgrade meshcode` manually before launching Claude Code.
427
+
428
+ If the dashboard tags an agent as having `boot_version_drift`, that means pip wrote the new version to disk but our running process is still the old one — typically benign on Windows (next launch fixes it) and worth investigating on Unix (path-precedence regression).
429
+
425
430
  **10. `MCP server failed to start` in the Claude Code `/mcp` panel**
426
431
  Run `claude --debug` to see the underlying error. Nine times out of ten it's a stale or missing key — run `meshcode login mc_xxx` again.
427
432
 
@@ -183,6 +183,7 @@ meshcode/meshcode_mcp/server.py
183
183
  meshcode/meshcode_mcp/test_backend.py
184
184
  meshcode/meshcode_mcp/test_realtime.py
185
185
  meshcode/meshcode_mcp/test_server_wrapper.py
186
+ tests/test_auto_update_hardening.py
186
187
  tests/test_core.py
187
188
  tests/test_cross_agent_messaging.py
188
189
  tests/test_esc_deaf_state.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.10.93"
7
+ version = "2.10.94"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,238 @@
1
+ """Smoke tests for the auto-update hardening landed in 5a7427f (task 8d5eed7a).
2
+
3
+ The full meshcode_mcp.server module bootstraps a live project at import
4
+ time (sys.exit on failure), which makes it inhospitable to vanilla pytest
5
+ runs. These tests therefore re-implement the small helpers under test
6
+ inline — the logic is intentionally a verbatim copy of the patched code
7
+ in server.py so any drift between source and tests is caught by review.
8
+
9
+ Covered:
10
+ 1. _check_boot_version_drift — None when versions match, tuple on mismatch.
11
+ 2. MESHCODE_UPDATED sentinel pop on consume (single-use semantics).
12
+ 3. MESHCODE_AUTO_UPDATE=0 short-circuits before any state mutation.
13
+
14
+ PyPI/relaunch-dependent matrix cells are tracked separately in the task
15
+ runbook (Phase 3 deliverable).
16
+ """
17
+
18
+ import os
19
+ from importlib import metadata
20
+ from unittest import mock
21
+
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Inline copies of the patched helpers (kept in lockstep with server.py).
25
+ # ---------------------------------------------------------------------------
26
+
27
+ def _check_boot_version_drift_inline():
28
+ try:
29
+ from importlib.metadata import version as _md_version
30
+ from meshcode import __version__ as _loaded
31
+ _installed = _md_version("meshcode")
32
+ if _installed != _loaded:
33
+ return (_installed, _loaded)
34
+ except Exception:
35
+ pass
36
+ return None
37
+
38
+
39
+ def _auto_update_inline_skeleton():
40
+ """Subset of _auto_update covering the env-var gates only."""
41
+ if os.environ.get("MESHCODE_AUTO_UPDATE", "1").lower() in ("0", "false", "no"):
42
+ return "disabled"
43
+ if os.environ.get("MESHCODE_UPDATED") == "1":
44
+ os.environ.pop("MESHCODE_UPDATED", None)
45
+ return "post_exec_skip"
46
+ return "would_check_pypi"
47
+
48
+
49
+ # ---------------------------------------------------------------------------
50
+ # 1. Drift helper
51
+ # ---------------------------------------------------------------------------
52
+
53
+ def test_drift_none_when_versions_match():
54
+ """No drift on a clean install where pip and __version__ agree."""
55
+ assert _check_boot_version_drift_inline() is None
56
+
57
+
58
+ def test_drift_returns_tuple_when_versions_diverge():
59
+ """Patching importlib.metadata.version to return a fake newer build
60
+ must surface (installed, loaded) so the caller can log + telemetry."""
61
+ fake_installed = "99.99.99"
62
+ with mock.patch.object(metadata, "version", return_value=fake_installed):
63
+ result = _check_boot_version_drift_inline()
64
+ assert result is not None
65
+ installed, loaded = result
66
+ assert installed == fake_installed
67
+ assert loaded != fake_installed
68
+
69
+
70
+ def test_drift_swallows_metadata_exceptions():
71
+ """Helper must never raise — telemetry is best-effort."""
72
+ with mock.patch.object(metadata, "version", side_effect=metadata.PackageNotFoundError("meshcode")):
73
+ assert _check_boot_version_drift_inline() is None
74
+
75
+
76
+ # ---------------------------------------------------------------------------
77
+ # 2. Sentinel pop
78
+ # ---------------------------------------------------------------------------
79
+
80
+ def test_sentinel_pop_clears_environment(monkeypatch):
81
+ monkeypatch.setenv("MESHCODE_UPDATED", "1")
82
+ monkeypatch.delenv("MESHCODE_AUTO_UPDATE", raising=False)
83
+ assert _auto_update_inline_skeleton() == "post_exec_skip"
84
+ assert "MESHCODE_UPDATED" not in os.environ
85
+
86
+
87
+ def test_sentinel_pop_idempotent(monkeypatch):
88
+ """Running twice in a row (simulating a child-of-execv that imports
89
+ twice) must not raise even though the sentinel is gone the second time."""
90
+ monkeypatch.setenv("MESHCODE_UPDATED", "1")
91
+ monkeypatch.delenv("MESHCODE_AUTO_UPDATE", raising=False)
92
+ _auto_update_inline_skeleton()
93
+ # Sentinel is already cleared — the second invocation should fall
94
+ # through to the would-check-pypi branch (or the disabled branch if
95
+ # MESHCODE_AUTO_UPDATE is ever set to 0). It must not raise KeyError.
96
+ result = _auto_update_inline_skeleton()
97
+ assert result in {"would_check_pypi", "disabled"}
98
+
99
+
100
+ # ---------------------------------------------------------------------------
101
+ # 3. Disabled short-circuit
102
+ # ---------------------------------------------------------------------------
103
+
104
+ def test_auto_update_disabled(monkeypatch):
105
+ monkeypatch.setenv("MESHCODE_AUTO_UPDATE", "0")
106
+ monkeypatch.delenv("MESHCODE_UPDATED", raising=False)
107
+ assert _auto_update_inline_skeleton() == "disabled"
108
+
109
+
110
+ def test_auto_update_disabled_case_variants(monkeypatch):
111
+ for val in ("0", "false", "FALSE", "No", "no"):
112
+ monkeypatch.setenv("MESHCODE_AUTO_UPDATE", val)
113
+ monkeypatch.delenv("MESHCODE_UPDATED", raising=False)
114
+ assert _auto_update_inline_skeleton() == "disabled", f"value {val!r} failed"
115
+
116
+
117
+ # ---------------------------------------------------------------------------
118
+ # 4. PyPI/pip behaviour matrix (mocked — covers the cells that don't need
119
+ # a live relaunch). Uses an inlined version of the post-gate _auto_update
120
+ # body so we can drive each branch independently.
121
+ # ---------------------------------------------------------------------------
122
+
123
+ import json as _json
124
+ import subprocess as _sp
125
+ import urllib.request as _urlreq
126
+
127
+
128
+ def _ver_tuple(v):
129
+ return tuple(int(x) for x in v.split(".") if x.isdigit())
130
+
131
+
132
+ def _auto_update_pypi_step(current, fake_latest, raise_on_open=None,
133
+ raise_on_pip=None, on_pip_call=None):
134
+ """Inlined copy of the post-gate _auto_update logic.
135
+
136
+ Returns one of {'no_latest', 'already_latest', 'pip_failed',
137
+ 'timeout', 'would_execv'} so each branch is observable.
138
+ """
139
+ if raise_on_open is not None:
140
+ try:
141
+ raise raise_on_open
142
+ except Exception:
143
+ return "no_latest"
144
+
145
+ latest = fake_latest
146
+ if not latest:
147
+ return "no_latest"
148
+ try:
149
+ if _ver_tuple(latest) <= _ver_tuple(current):
150
+ return "already_latest"
151
+ except Exception:
152
+ return "no_latest"
153
+
154
+ # Mock pip install
155
+ try:
156
+ if raise_on_pip is _sp.TimeoutExpired:
157
+ raise _sp.TimeoutExpired(cmd="pip", timeout=60)
158
+ if raise_on_pip is not None:
159
+ raise raise_on_pip
160
+ if on_pip_call is not None:
161
+ on_pip_call()
162
+ except _sp.TimeoutExpired:
163
+ return "timeout"
164
+ except Exception:
165
+ return "pip_failed"
166
+ return "would_execv"
167
+
168
+
169
+ def test_pypi_newer_triggers_execv():
170
+ pip_calls = []
171
+ result = _auto_update_pypi_step(
172
+ current="2.10.93",
173
+ fake_latest="99.99.99",
174
+ on_pip_call=lambda: pip_calls.append(1),
175
+ )
176
+ assert result == "would_execv"
177
+ assert len(pip_calls) == 1
178
+
179
+
180
+ def test_pypi_same_no_op():
181
+ pip_calls = []
182
+ result = _auto_update_pypi_step(
183
+ current="2.10.93",
184
+ fake_latest="2.10.93",
185
+ on_pip_call=lambda: pip_calls.append(1),
186
+ )
187
+ assert result == "already_latest"
188
+ assert pip_calls == []
189
+
190
+
191
+ def test_pypi_older_no_op():
192
+ pip_calls = []
193
+ result = _auto_update_pypi_step(
194
+ current="2.10.93",
195
+ fake_latest="2.10.0",
196
+ on_pip_call=lambda: pip_calls.append(1),
197
+ )
198
+ assert result == "already_latest"
199
+ assert pip_calls == []
200
+
201
+
202
+ def test_offline_swallowed():
203
+ result = _auto_update_pypi_step(
204
+ current="2.10.93",
205
+ fake_latest=None,
206
+ raise_on_open=OSError("offline"),
207
+ )
208
+ assert result == "no_latest"
209
+
210
+
211
+ def test_pip_timeout_returns_gracefully():
212
+ """Slow-net cell: pip exceeds 60s → graceful return, no execv."""
213
+ result = _auto_update_pypi_step(
214
+ current="2.10.93",
215
+ fake_latest="99.99.99",
216
+ raise_on_pip=_sp.TimeoutExpired,
217
+ )
218
+ assert result == "timeout"
219
+
220
+
221
+ def test_pip_install_failure_swallowed():
222
+ result = _auto_update_pypi_step(
223
+ current="2.10.93",
224
+ fake_latest="99.99.99",
225
+ raise_on_pip=RuntimeError("pip exploded"),
226
+ )
227
+ assert result == "pip_failed"
228
+
229
+
230
+ def test_version_compare_handles_non_numeric():
231
+ """Pre-release strings ('2.10.93rc1') must not crash the comparator."""
232
+ result = _auto_update_pypi_step(
233
+ current="2.10.93",
234
+ fake_latest="2.10.93rc1",
235
+ )
236
+ # _ver_tuple drops non-numeric segments — both reduce to (2,10,93),
237
+ # so the path is "already_latest" (<=).
238
+ assert result == "already_latest"
@@ -1,82 +0,0 @@
1
- """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.10.93"
3
-
4
- # Exception hierarchy — eagerly imported (lightweight, no deps)
5
- from meshcode.exceptions import ( # noqa: F401
6
- MeshCodeError,
7
- AuthError,
8
- RPCError,
9
- MeshCodeTimeoutError,
10
- MeshCodeConnectionError,
11
- )
12
-
13
- # Public API — lazy imports to avoid heavy deps at import time
14
- def __getattr__(name):
15
- if name == "backend":
16
- from meshcode.meshcode_mcp import backend
17
- return backend
18
- if name in _BACKEND_EXPORTS:
19
- from meshcode.meshcode_mcp import backend
20
- return getattr(backend, name)
21
- if name in _SECRETS_EXPORTS:
22
- from meshcode import secrets
23
- return getattr(secrets, name)
24
- raise AttributeError(f"module 'meshcode' has no attribute {name!r}")
25
-
26
-
27
- # Backend: core messaging & agent management
28
- _BACKEND_EXPORTS = {
29
- "send_message",
30
- "read_inbox",
31
- "count_pending",
32
- "get_board",
33
- "heartbeat",
34
- "set_status",
35
- "register_agent",
36
- "get_project_id",
37
- "sb_rpc",
38
- "task_create",
39
- "task_list",
40
- "encrypt_payload",
41
- "decrypt_payload",
42
- }
43
-
44
- # Secrets: credential management
45
- _SECRETS_EXPORTS = {
46
- "get_api_key",
47
- "set_api_key",
48
- "list_profiles",
49
- }
50
-
51
- __all__ = [
52
- "__version__",
53
- "backend",
54
- # Exceptions
55
- "MeshCodeError",
56
- "AuthError",
57
- "RPCError",
58
- "MeshCodeTimeoutError",
59
- "MeshCodeConnectionError",
60
- # Messaging
61
- "send_message",
62
- "read_inbox",
63
- "count_pending",
64
- # Agent management
65
- "register_agent",
66
- "get_project_id",
67
- "get_board",
68
- "heartbeat",
69
- "set_status",
70
- # Tasks
71
- "task_create",
72
- "task_list",
73
- # Low-level
74
- "sb_rpc",
75
- # Encryption
76
- "encrypt_payload",
77
- "decrypt_payload",
78
- # Credentials
79
- "get_api_key",
80
- "set_api_key",
81
- "list_profiles",
82
- ]
File without changes