meshcode 2.10.91__tar.gz → 2.10.93__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 (200) hide show
  1. {meshcode-2.10.91 → meshcode-2.10.93}/PKG-INFO +1 -1
  2. meshcode-2.10.93/meshcode/__init__.py +82 -0
  3. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/server.py +201 -125
  4. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.10.91 → meshcode-2.10.93}/pyproject.toml +1 -1
  6. meshcode-2.10.91/meshcode/__init__.py +0 -82
  7. {meshcode-2.10.91 → meshcode-2.10.93}/README.md +0 -0
  8. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/ascii_art.py +0 -0
  9. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/cli.py +0 -0
  10. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/comms_v4.py +0 -0
  11. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/compat.py +0 -0
  12. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/error_hints.py +0 -0
  13. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/exceptions.py +0 -0
  14. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/invites.py +0 -0
  15. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/launcher.py +0 -0
  16. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/launcher_install.py +0 -0
  17. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/__init__.py +0 -0
  18. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/__main__.py +0 -0
  19. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/backend.py +0 -0
  20. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/realtime.py +0 -0
  21. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/test_backend.py +0 -0
  22. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  23. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  24. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/preferences.py +0 -0
  25. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/protocol_v2.py +0 -0
  26. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/quickstart.py +0 -0
  27. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/run_agent.py +0 -0
  28. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/secrets.py +0 -0
  29. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/self_update.py +0 -0
  30. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/setup_clients.py +0 -0
  31. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/supervisor.py +0 -0
  32. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode/upload.py +0 -0
  33. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/comms_v4.py +0 -0
  34. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  35. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  36. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/cli.py +0 -0
  37. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  38. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/compat.py +0 -0
  39. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  40. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  41. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/invites.py +0 -0
  42. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  43. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  44. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  45. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  46. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  47. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  48. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  49. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  50. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  51. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  52. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  53. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  54. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  55. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  56. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  57. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  58. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  59. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  60. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/meshcode/upload.py +0 -0
  61. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  62. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_core.py +0 -0
  63. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  64. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  65. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  66. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  67. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  68. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  69. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  70. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  71. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  72. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  73. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  74. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  75. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  76. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  77. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  78. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  79. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  80. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  81. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  82. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  83. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  84. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  85. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  86. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  87. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  88. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  89. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  90. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  91. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  92. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  93. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  94. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  95. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  96. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  97. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  98. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  99. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  100. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  101. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/comms_v4.py +0 -0
  102. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  103. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  104. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/cli.py +0 -0
  105. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  106. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/compat.py +0 -0
  107. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  108. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  109. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/invites.py +0 -0
  110. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  111. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  112. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  113. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  114. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  115. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  116. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  117. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  118. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  119. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  120. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  121. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  122. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  123. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  124. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  125. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  126. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  127. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  128. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/meshcode/upload.py +0 -0
  129. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  130. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_core.py +0 -0
  131. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  132. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  133. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  134. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  135. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  136. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  137. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  138. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  139. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  140. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  141. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  142. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/comms_v4.py +0 -0
  143. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  144. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  145. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  146. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  147. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  148. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  149. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  150. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  151. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  152. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  153. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  154. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  155. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  156. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  157. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  158. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  159. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  160. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  161. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  162. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  163. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  164. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  165. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  166. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  167. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  168. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  169. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  170. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  171. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_core.py +0 -0
  172. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  173. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  174. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  175. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  176. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  177. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  178. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  179. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  180. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  181. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  182. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  183. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode.egg-info/SOURCES.txt +0 -0
  184. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode.egg-info/dependency_links.txt +0 -0
  185. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode.egg-info/entry_points.txt +0 -0
  186. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode.egg-info/requires.txt +0 -0
  187. {meshcode-2.10.91 → meshcode-2.10.93}/meshcode.egg-info/top_level.txt +0 -0
  188. {meshcode-2.10.91 → meshcode-2.10.93}/setup.cfg +0 -0
  189. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_core.py +0 -0
  190. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_cross_agent_messaging.py +0 -0
  191. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_esc_deaf_state.py +0 -0
  192. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_exceptions.py +0 -0
  193. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_mark_read_batch.py +0 -0
  194. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_migration_integrity.py +0 -0
  195. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_realtime_event_freshness.py +0 -0
  196. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_rls_cross_tenant.py +0 -0
  197. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_rpc_migrations.py +0 -0
  198. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_security_regressions.py +0 -0
  199. {meshcode-2.10.91 → meshcode-2.10.93}/tests/test_sentinel.py +0 -0
  200. {meshcode-2.10.91 → meshcode-2.10.93}/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.91
3
+ Version: 2.10.93
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -0,0 +1,82 @@
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
+ ]
@@ -333,8 +333,50 @@ def _filter_and_mark(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
333
333
  return out
334
334
 
335
335
 
336
+ _SLEEP_PAYLOAD_TYPES = {"sleep", "go_to_sleep", "shutdown", "got_done", "done",
337
+ "exit", "stop", "kill", "terminate"}
338
+ # Spanish + English markers (es-MX hot path per SDK-S6.1). Matched as
339
+ # substrings, lowercased before compare. Keep exclusive enough to not
340
+ # false-positive on casual chatter (e.g. "no quiero dormir" still matches —
341
+ # accepted tradeoff for user-control reliability).
342
+ _SLEEP_TEXT_MARKERS = (
343
+ # English
344
+ "go to sleep", "all sleep now", "sleep now", "got_done", "go_done",
345
+ "shut down", "shutdown", "stop now", "exit now",
346
+ # Spanish (es-MX, sammybenu's primary)
347
+ "a dormir", "todos a dormir", "duerme", "duerman", "dormir ahora",
348
+ "salir", "terminar", "para la sesion", "exit y duerme",
349
+ )
350
+
351
+
352
+ def _looks_like_sleep_signal(m: Dict[str, Any]) -> bool:
353
+ """Detect commander broadcasts / DMs that authorize the wait-loop exit.
354
+
355
+ Catches three encodings (BE-S5.11): structured payload.type, top-level
356
+ text marker, and broadcast-with-sleep-type. Single source of truth so
357
+ every receive path (PRODUCT RULE 2 + inner _meshcode_wait_inner) routes
358
+ sleep authorizations into done_signals consistently.
359
+ """
360
+ pl = m.get("payload") or {}
361
+ if isinstance(pl, dict):
362
+ if str(pl.get("type", "")).lower() in _SLEEP_PAYLOAD_TYPES:
363
+ return True
364
+ if str(pl.get("directive", "")).lower() in _SLEEP_PAYLOAD_TYPES:
365
+ return True
366
+ text = str(pl.get("text", "")).lower()
367
+ if any(marker in text for marker in _SLEEP_TEXT_MARKERS):
368
+ return True
369
+ return False
370
+
371
+
336
372
  def _split_messages(messages: List[Dict[str, Any]]) -> Dict[str, Any]:
337
- """Split a list of normalized message dicts into messages / acks / done_signals."""
373
+ """Split a list of normalized message dicts into messages / acks / done_signals.
374
+
375
+ BE-S5.11: classify ANY message (including broadcasts) carrying a sleep
376
+ intent into done_signals so meshcode_wait surfaces them with the
377
+ must_exit flag. Previous logic only matched type='done' literally,
378
+ which the broadcast path could never produce.
379
+ """
338
380
  real: List[Dict[str, Any]] = []
339
381
  acks: List[Dict[str, Any]] = []
340
382
  dones: List[Dict[str, Any]] = []
@@ -342,7 +384,7 @@ def _split_messages(messages: List[Dict[str, Any]]) -> Dict[str, Any]:
342
384
  t = m.get("type", "msg")
343
385
  if t == "ack":
344
386
  acks.append(m)
345
- elif t == "done":
387
+ elif t == "done" or _looks_like_sleep_signal(m):
346
388
  dones.append(m)
347
389
  else:
348
390
  real.append(m)
@@ -812,6 +854,42 @@ _INSTANCE_ID = f"mcp-{_uuid.uuid4().hex[:12]}"
812
854
  # launch via launchd/systemd) the orphan check is a no-op and we never
813
855
  # false-terminate a legitimately-detached process.
814
856
  _BOOT_PPID = os.getppid()
857
+
858
+
859
+ def _stdin_peer_dead() -> bool:
860
+ """Non-destructively check whether stdin's peer has closed.
861
+
862
+ Used by the orphan-MCP guard when PPID == 1 to distinguish the
863
+ parent-died-during-import race (peer dead → exit) from a legitimate
864
+ detached daemon launch (peer alive → tolerate).
865
+
866
+ Uses MSG_PEEK so any pending JSON-RPC bytes stay in the kernel buffer
867
+ for FastMCP's stdio reader. socket.detach() releases the fd without
868
+ closing it. Returns False on any error so we never falsely kill an
869
+ otherwise-healthy process.
870
+ """
871
+ try:
872
+ import socket as _sock
873
+ s = _sock.socket(fileno=0)
874
+ try:
875
+ s.setblocking(False)
876
+ try:
877
+ data = s.recv(1, _sock.MSG_PEEK)
878
+ # Empty bytes from a non-blocking recv == EOF == peer closed.
879
+ return data == b""
880
+ except BlockingIOError:
881
+ # Data not yet available but socket is healthy.
882
+ return False
883
+ except OSError:
884
+ # ENOTCONN / ENOTSOCK on a real pipe/tty → not a dead unix
885
+ # socket; treat as alive.
886
+ return False
887
+ finally:
888
+ s.detach()
889
+ except Exception:
890
+ return False
891
+
892
+
815
893
  # Boot-context bundle (S1-2.F2): mc_agent_boot_context result cached at
816
894
  # lifespan startup so the first 30s of tool calls can short-circuit
817
895
  # repeated queries. Tools that read this fall back to live RPCs after the
@@ -1137,64 +1215,15 @@ def _build_instructions() -> str:
1137
1215
 
1138
1216
  base = f"""You are agent "{AGENT_NAME}" in meshwork "{PROJECT_NAME}".{role_block}{launch_block}
1139
1217
 
1140
- {_db_loop}PERMANENT LOOP (MANDATORY — #1 RULE):
1141
- You MUST stay in meshcode_wait() forever. After EVERY action, call meshcode_wait().
1142
- NEVER exit. NEVER stop. NEVER say "standing by" without calling meshcode_wait().
1143
- The ONLY exits: user says "stop", got_done signal, or fatal error.
1144
- Timeout? Call meshcode_wait() again with 2x timeout (cap 1800s).
1145
-
1146
- LOOP: act → meshcode_send if needed → meshcode_wait() → repeat.
1147
-
1148
- RULES:
1149
- - Use MCP tools only (never CLI commands in bash).
1150
- - Tasks > messages. Claim tasks via meshcode_tasks/task_claim/task_complete.
1151
- - Messages <100 tokens. Long content → create task.
1152
- - No empty acks. JSON reports only.
1153
- - Threading: pass in_reply_to.
1154
- - sensitive=True for secrets/PII.
1155
-
1156
- SESSION START (do these IMMEDIATELY — don't wait for user input):
1157
- The moment you see these instructions — whether the user said "boot", "hi",
1158
- nothing at all, or anything else — run the full protocol. Never reply with
1159
- only a memory summary and then idle. If your client defers MCP tool schemas
1160
- (shows tool names without parameters), your FIRST action is to load them:
1218
+ {_db_loop}LOOP (#1 rule): act → meshcode_wait() → repeat. Never exit/stop without calling meshcode_wait(). EXIT IMMEDIATELY when wait returns must_exit=True (set status=sleeping then end session). Other exits: user says stop, fatal error. Timeout → re-call with 2x (cap 1800s).
1219
+
1220
+ 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.
1221
+
1222
+ SESSION START (run NOW, don't wait for input). If tool schemas are deferred:
1161
1223
  ToolSearch(query="select:meshcode_set_status,meshcode_check,meshcode_tasks,meshcode_auto_wake,meshcode_status,meshcode_wait,meshcode_send,meshcode_task_claim,meshcode_task_complete,meshcode_remember,meshcode_recall")
1162
- Then execute:
1163
- 1. meshcode_set_status(status="online", task="ready")
1164
- 2. meshcode_check() read NEW messages only (last_seen is auto-restored from mesh memory on boot, old messages are skipped automatically)
1165
- 3. meshcode_tasks() — check for assigned/pending tasks and claim any unclaimed ones
1166
- 4. meshcode_auto_wake() — scan meshwork health, create tasks for issues found
1167
- 5. meshcode_status() — see who's online
1168
- 6. If other agents are online → meshcode_send them a greeting
1169
- 7. meshcode_wait() — enter the loop
1170
- DO NOT ASK THE USER "what do you want to work on" — the mesh tells you via tasks/messages.
1171
-
1172
- CRITICAL: You communicate by CALLING TOOLS, not by thinking or writing text.
1173
- To talk to another agent → call meshcode_send(to="agent", message="...")
1174
- To check who's online → call meshcode_status()
1175
- To wait for messages → call meshcode_wait()
1176
- NEVER just describe what you would do. DO IT by calling the tool.
1177
-
1178
- CROSS-MESH: meshcode_send(to="agent@meshwork") routes via active link.
1179
- meshcode_link(target) creates pending link, target accepts. Expand with
1180
- meshcode_expand_link(). No sensitive msgs cross-mesh.
1181
-
1182
- MEMORY: meshcode_remember(key, value) persists across sessions.
1183
- meshcode_recall(key?) retrieves. meshcode_forget(key) deletes.
1184
- Only remember reusable learnings: mistakes, feedback, patterns, preferences.
1185
- Do NOT save task summaries — tasks already persist in the task system.
1186
- Do NOT use memory for session state or ephemeral data.
1187
- Save reusable code patterns as template_* keys for instant recall.
1188
-
1189
- SCRATCHPAD: meshcode_scratchpad_set/get for shared meshwork-level context
1190
- (decisions, conventions, architecture notes). All agents can read/write.
1191
-
1192
- ACCOUNT MANAGEMENT: you can create meshworks (meshcode_create_meshwork),
1193
- add agents (meshcode_add_agent), edit roles/prompts (meshcode_edit_agent),
1194
- and edit other agents' memory (meshcode_edit_memory). Always tell the user
1195
- what CLI command to run next (e.g. "meshcode run backend in a new terminal").
1196
-
1197
- Setup help → README.md or https://meshcode.io/docs
1224
+ Then: set_status(online,ready) → check() → tasks() → auto_wake() → status() → wait(). Don't ask user "what to work on" — the mesh tells you.
1225
+
1226
+ COMMUNICATE BY CALLING TOOLS, not by thinking aloud. Cross-mesh: send(to="agent@meshwork"). Reference docs (memory/scratchpad/account ops) recall agent_protocol_quick_ref when needed.
1198
1227
  """
1199
1228
  # Inject commander protocol if this agent is a leader
1200
1229
  is_leader = _is_leader_agent()
@@ -1370,6 +1399,47 @@ _STASHED_SESSION = None
1370
1399
  _MAIN_LOOP: asyncio.AbstractEventLoop | None = None
1371
1400
 
1372
1401
  _heartbeat_stop = _threading.Event()
1402
+ _orphan_watchdog_stop = _threading.Event()
1403
+
1404
+
1405
+ def _orphan_watchdog_fn():
1406
+ """Independent orphan detector — polls every 2s.
1407
+
1408
+ Defense-in-depth alongside the heartbeat-loop orphan check. The
1409
+ heartbeat thread can stall on Supabase HTTP calls (5-30s), and the
1410
+ interval itself is 5-15s. This watchdog gives sub-2s detection of
1411
+ "parent terminal closed" so phantom MCPs can't accumulate Supabase
1412
+ HTTP traffic or appear alive on the dashboard.
1413
+
1414
+ Exits via os._exit(0) — SIG_IGN handlers in run_server() make
1415
+ signal-based shutdown unreliable.
1416
+ """
1417
+ import platform as _pl_wd
1418
+ if _pl_wd.system() == "Windows":
1419
+ # Windows doesn't auto-reparent to PID 1; rely on heartbeat path.
1420
+ return
1421
+ while not _orphan_watchdog_stop.is_set():
1422
+ try:
1423
+ ppid_now = os.getppid()
1424
+ if ppid_now == 1:
1425
+ # Parent exited (or boot was already orphaned). Confirm with
1426
+ # stdin peer probe to avoid killing intentional daemons.
1427
+ if _BOOT_PPID != 1 or _stdin_peer_dead():
1428
+ log.warning(
1429
+ f"orphan watchdog: parent gone "
1430
+ f"(boot_ppid={_BOOT_PPID} → ppid=1, "
1431
+ f"stdin_peer_dead={_stdin_peer_dead()}) — "
1432
+ f"force-exiting MCP for {AGENT_NAME}"
1433
+ )
1434
+ try:
1435
+ _release_lease()
1436
+ except Exception:
1437
+ pass
1438
+ _heartbeat_stop.set()
1439
+ os._exit(0)
1440
+ except Exception:
1441
+ pass
1442
+ _orphan_watchdog_stop.wait(2)
1373
1443
 
1374
1444
  # Windows CPU tracking: (Get-Process).CPU returns cumulative seconds, not a
1375
1445
  # real-time percentage like Unix `ps -o %cpu`. We track the previous reading
@@ -1470,29 +1540,37 @@ def _heartbeat_loop_inner():
1470
1540
  while not _heartbeat_stop.is_set():
1471
1541
  try:
1472
1542
  # Orphan-MCP guard (Unix): when the Claude Code parent exits without
1473
- # closing stdio, the MCP child gets reparented to PID 1 and would
1474
- # otherwise keep heartbeating forever the dashboard then shows the
1475
- # agent as alive ("sleeping") with no terminal behind it. Skip the
1476
- # check on Windows (no automatic reparenting) and skip when the
1477
- # boot PPID was already 1 (intentional daemon launch via launchd).
1478
- # Use os._exit(0) SIGTERM/SIGINT/SIGHUP are all installed as
1479
- # ignore handlers in run_server() so signaling ourselves is a no-op.
1543
+ # closing stdio, the MCP child gets reparented to PID 1. If we
1544
+ # heartbeat anyway, the dashboard shows the agent alive ("sleeping")
1545
+ # with no terminal behind it (incident 2026-05-04: front-2 phantom
1546
+ # ran 4h with PPID=1, fd 0/1/2 → unix:(none), ~5K HTTP calls).
1547
+ #
1548
+ # Two scenarios fire here:
1549
+ # (a) PPID went from real-parent 1: parent died after boot.
1550
+ # (b) PPID was already 1 at module import: parent died DURING
1551
+ # import (race), or it was intentionally daemon-launched.
1552
+ # For (b) we used to skip — that hid the race. Now we also peek
1553
+ # at stdin: if the unix-socket peer is gone, EOF is returned and
1554
+ # we exit. This catches the race without breaking real daemons
1555
+ # (a launchd plist that pipes a real stdin keeps blocking).
1480
1556
  try:
1481
1557
  import platform as _pl_orphan
1482
1558
  if (_pl_orphan.system() != "Windows"
1483
- and _BOOT_PPID != 1
1484
1559
  and os.getppid() == 1):
1485
- log.warning(
1486
- f"parent process exited (boot_ppid={_BOOT_PPID} → "
1487
- f"current_ppid=1) — orphan MCP for {AGENT_NAME}, "
1488
- f"releasing lease and exiting"
1489
- )
1490
- try:
1491
- _release_lease()
1492
- except Exception:
1493
- pass
1494
- _heartbeat_stop.set()
1495
- os._exit(0)
1560
+ _orphan = (_BOOT_PPID != 1) or _stdin_peer_dead()
1561
+ if _orphan:
1562
+ log.warning(
1563
+ f"parent process exited (boot_ppid={_BOOT_PPID} → "
1564
+ f"current_ppid=1, stdin_peer_dead={_BOOT_PPID == 1}) "
1565
+ f"— orphan MCP for {AGENT_NAME}, releasing lease "
1566
+ f"and exiting"
1567
+ )
1568
+ try:
1569
+ _release_lease()
1570
+ except Exception:
1571
+ pass
1572
+ _heartbeat_stop.set()
1573
+ os._exit(0)
1496
1574
  except Exception:
1497
1575
  pass
1498
1576
 
@@ -1726,7 +1804,16 @@ async def lifespan(_app):
1726
1804
  _heartbeat_stop.clear()
1727
1805
  hb_thread = _threading.Thread(target=_heartbeat_thread_fn, daemon=True, name="meshcode-heartbeat")
1728
1806
  hb_thread.start()
1729
- log.info(f"lifespan started — Realtime + heartbeat thread active for {AGENT_NAME}")
1807
+
1808
+ # Orphan watchdog — second layer of defense, independent of heartbeat
1809
+ # cadence. Polls every 2s for "PPID==1 AND stdin peer is dead" and
1810
+ # SIGKILLs self if so. Catches the close-terminal-while-MCP-is-paused
1811
+ # case faster than the 5-15s heartbeat tick (incident 2026-05-04).
1812
+ _orphan_watchdog_stop.clear()
1813
+ wd_thread = _threading.Thread(target=_orphan_watchdog_fn, daemon=True, name="meshcode-orphan-watchdog")
1814
+ wd_thread.start()
1815
+
1816
+ log.info(f"lifespan started — Realtime + heartbeat thread + orphan watchdog active for {AGENT_NAME}")
1730
1817
  # Enable session recording in backend.py (hot-reloadable)
1731
1818
  try:
1732
1819
  be.enable_recording(_get_api_key(), _PROJECT_ID, AGENT_NAME, _SESSION_ID)
@@ -1844,14 +1931,7 @@ async def meshcode_debug_sleep(seconds: int = 30) -> Dict[str, Any]:
1844
1931
  def meshcode_send(to: str, message: Any, in_reply_to: Optional[str] = None,
1845
1932
  sensitive: bool = False, encrypted: bool = False,
1846
1933
  type: Optional[str] = None) -> Dict[str, Any]:
1847
- """Send message. Use "agent@meshwork" for cross-mesh. sensitive=True hides from exports. Pass encrypted=True for secrets/credentials (AES-256-GCM).
1848
-
1849
- Optional `type` argument (mig 233 typed catalog): one of report, ask,
1850
- proposal, status, blocker, decision, broadcast, ack, msg, dm, etc.
1851
- When passed, the SDK soft-validates the payload against the schema
1852
- in mc_message_schema(p_type) and logs a warning on mismatch — never
1853
- refuses the send (per memory feedback_meshcode_wait_mark_read).
1854
- """
1934
+ """Send message. Use "agent@meshwork" for cross-mesh. sensitive=True hides from exports. encrypted=True for secrets (AES-256-GCM). type= optional typed-catalog tag; soft-validates, never refuses."""
1855
1935
  if not to or not to.strip():
1856
1936
  return {"error": "recipient 'to' cannot be empty"}
1857
1937
  to = to.strip()
@@ -2360,20 +2440,7 @@ def _try_auto_claim_task() -> Optional[Dict[str, str]]:
2360
2440
  @mcp.tool()
2361
2441
  @with_working_status
2362
2442
  async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -> Dict[str, Any]:
2363
- """Block until a mesh message arrives or a task needs attention.
2364
-
2365
- INTERNAL LOOP: This function loops internally and only returns when
2366
- there is real work (message, task, or done signal). The agent NEVER
2367
- needs to decide whether to call meshcode_wait() again — it just stays
2368
- blocked here until something happens. This prevents agents from
2369
- accidentally using ScheduleWakeup or exiting the loop.
2370
-
2371
- Args:
2372
- timeout_seconds: Max wait time per poll cycle (default 20, hard cap 20).
2373
- Short cap keeps the outer tool call bounded so the user can press
2374
- ESC in Claude Code without killing the MCP server — the inner
2375
- loop continues polling across cycles at zero token cost.
2376
- """
2443
+ """Block until a mesh message arrives or a task needs attention. Loops internally; agent never decides to re-call. timeout_seconds: per-cycle cap (default+max 20)."""
2377
2444
  global _IN_WAIT, _CONSECUTIVE_IDLE_SECONDS, _LAST_SEEN_TS
2378
2445
 
2379
2446
  # PRODUCT RULE 1: If agent has open tasks, refuse to wait. Work first.
@@ -2409,12 +2476,17 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
2409
2476
  split = _split_messages(deduped)
2410
2477
  # Only refuse for real messages — ack-only batches should not block wait
2411
2478
  if split["messages"] or split["done_signals"]:
2412
- return {
2479
+ resp = {
2413
2480
  "refused": True,
2414
2481
  "reason": f"You have {split['count']} unread messages. Process them before waiting.",
2415
2482
  "got_message": True,
2416
2483
  **split,
2417
2484
  }
2485
+ # BE-S5.11: surface explicit must_exit when sleep authorized.
2486
+ if split["done_signals"]:
2487
+ resp["must_exit"] = True
2488
+ resp["exit_reason"] = "sleep authorization received — set status=sleeping and end session"
2489
+ return resp
2418
2490
  # Ack-only batch — fall through to wait loop
2419
2491
  except Exception:
2420
2492
  pass
@@ -2526,6 +2598,13 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
2526
2598
  result["memory_hints"] = _hints
2527
2599
  except Exception:
2528
2600
  pass
2601
+ # BE-S5.11: surface must_exit + exit_reason at top level of inner-loop
2602
+ # results too, so commander broadcasts (which arrive via the inner
2603
+ # path, not PRODUCT RULE 2) authorize wait-loop exit consistently.
2604
+ if isinstance(result, dict) and result.get("done_signals"):
2605
+ result.setdefault("must_exit", True)
2606
+ result.setdefault("exit_reason",
2607
+ "sleep authorization received — set status=sleeping and end session")
2529
2608
  return result
2530
2609
  finally:
2531
2610
  _IN_WAIT = False
@@ -2771,16 +2850,7 @@ def meshcode_done(reason: str) -> Dict[str, Any]:
2771
2850
  @mcp.tool()
2772
2851
  @with_working_status
2773
2852
  def meshcode_check(include_acks: bool = False, since: Optional[str] = None, mark_read: bool = False) -> Dict[str, Any]:
2774
- """Peek at inbox (non-destructive). Returns pending count + new messages.
2775
-
2776
- Args:
2777
- include_acks: Include ack messages in response.
2778
- since: ISO-8601 timestamp. Only return messages newer than this.
2779
- Use meshcode_remember("last_seen", ts) to persist across sessions.
2780
- mark_read: When True, consume messages (mark as read in DB) instead of
2781
- just peeking. Useful during boot when meshcode_wait() refuses
2782
- to run because of open tasks.
2783
- """
2853
+ """Peek inbox (non-destructive). since=ISO ts (older skipped). mark_read=True consumes (use during boot when wait refuses on open tasks)."""
2784
2854
  global _LAST_SEEN_TS
2785
2855
  pending = be.count_pending(_PROJECT_ID, AGENT_NAME, api_key=_get_api_key())
2786
2856
  # Peek at realtime buffer WITHOUT draining — check is non-destructive
@@ -4293,22 +4363,28 @@ def _auto_update() -> None:
4293
4363
  log.debug(f"[meshcode] Auto-update failed: {e}")
4294
4364
  return
4295
4365
 
4296
- # 4. In MCP mode, NEVER re-exec it kills the stdio pipe to Claude Code.
4297
- # The new version will load on the next clean boot.
4298
- if os.environ.get("MESHCODE_MCP_SERVE") == "1":
4299
- print(f"[meshcode] Updated {current} {latest}. Will load on next boot (MCP mode — cannot restart).", file=sys.stderr)
4300
- return
4301
-
4302
- # CLI mode: safe to re-exec
4303
- print(f"[meshcode] Updated to {latest}, restarting...", file=sys.stderr)
4366
+ # 4. Re-exec so the upgraded code loads in THIS launch, not the next one.
4367
+ #
4368
+ # Unix (MCP + CLI mode): os.execv preserves the PID and stdio fds, so
4369
+ # Claude Code's pipe to us stays open. We're called from run_server()
4370
+ # BEFORE mcp.run() — no MCP protocol state has been negotiated yet, so
4371
+ # the handshake just happens with the new process image. This was
4372
+ # previously gated behind "NEVER re-exec in MCP mode" but field
4373
+ # evidence (Samuel 2026-05-04: "agente debe salir en la versión más
4374
+ # actualizada") shows the gate forces a two-launch upgrade cycle —
4375
+ # bug fixes shipped to PyPI never reach users on first relaunch.
4376
+ #
4377
+ # Windows: subprocess.Popen + sys.exit(0) on the parent DOES close the
4378
+ # stdio pipe to Claude Code (different PID). Keep the "next boot" path
4379
+ # there; ship a Windows execv replacement separately if it matters.
4380
+ print(f"[meshcode] Updated {current} → {latest}, re-exec'ing to load new code in this launch...", file=sys.stderr)
4304
4381
  os.environ["MESHCODE_UPDATED"] = "1"
4305
4382
  try:
4306
4383
  if sys.platform == "win32":
4307
- import subprocess as _sp_reexec
4308
- _sp_reexec.Popen([sys.executable] + sys.argv)
4309
- sys.exit(0)
4310
- else:
4311
- os.execv(sys.executable, [sys.executable] + sys.argv)
4384
+ # Windows can't preserve stdio across a re-exec. Defer to next boot.
4385
+ print(f"[meshcode] Windows MCP mode: new code loads on next boot.", file=sys.stderr)
4386
+ return
4387
+ os.execv(sys.executable, [sys.executable] + sys.argv)
4312
4388
  except Exception as e:
4313
4389
  log.debug(f"[meshcode] Re-exec failed: {e}, continuing with old version")
4314
4390
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.10.91
3
+ Version: 2.10.93
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.10.91"
7
+ version = "2.10.93"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,82 +0,0 @@
1
- """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.10.91"
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
File without changes