meshcode 2.11.19__tar.gz → 2.11.21__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 (228) hide show
  1. {meshcode-2.11.19 → meshcode-2.11.21}/PKG-INFO +1 -1
  2. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/__init__.py +1 -1
  3. meshcode-2.11.21/meshcode/atomic_push.py +257 -0
  4. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/server.py +139 -6
  5. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/rpc_allowlist.py +4 -0
  6. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/PKG-INFO +1 -1
  7. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/SOURCES.txt +1 -0
  8. {meshcode-2.11.19 → meshcode-2.11.21}/pyproject.toml +1 -1
  9. {meshcode-2.11.19 → meshcode-2.11.21}/README.md +0 -0
  10. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/__main__.py +0 -0
  11. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/_stop_hook_template.py +0 -0
  12. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/ascii_art.py +0 -0
  13. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/cli.py +0 -0
  14. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/comms_v4.py +0 -0
  15. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/compat.py +0 -0
  16. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/daemon.py +0 -0
  17. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/date_parse.py +0 -0
  18. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/doctor.py +0 -0
  19. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/error_hints.py +0 -0
  20. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/exceptions.py +0 -0
  21. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/invites.py +0 -0
  22. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/launcher.py +0 -0
  23. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/launcher_install.py +0 -0
  24. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/__init__.py +0 -0
  25. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/__main__.py +0 -0
  26. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/backend.py +0 -0
  27. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/realtime.py +0 -0
  28. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  29. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_backend.py +0 -0
  30. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  31. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  32. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  33. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  34. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  35. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/preferences.py +0 -0
  36. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/protocol_handler.py +0 -0
  37. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/protocol_v2.py +0 -0
  38. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/quickstart.py +0 -0
  39. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/run_agent.py +0 -0
  40. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/scripts/check_secrets.py +0 -0
  41. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/scripts/race_rate_harness.py +0 -0
  42. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/secrets.py +0 -0
  43. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/self_update.py +0 -0
  44. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/setup_clients.py +0 -0
  45. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/supervisor.py +0 -0
  46. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/upload.py +0 -0
  47. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/comms_v4.py +0 -0
  48. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  49. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  50. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/cli.py +0 -0
  51. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  52. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/compat.py +0 -0
  53. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  54. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  55. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/invites.py +0 -0
  56. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  57. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  58. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  59. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  60. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  61. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  62. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  63. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  64. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  65. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  66. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  67. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  68. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  69. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  70. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  71. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  72. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  73. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  74. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/upload.py +0 -0
  75. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  76. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_core.py +0 -0
  77. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  78. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  79. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  80. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  81. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  82. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  83. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  84. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  85. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  86. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  87. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  88. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  89. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  90. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  91. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  92. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  93. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  94. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  95. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  96. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  97. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  98. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  99. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  100. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  101. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  102. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  103. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  104. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  105. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  106. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  107. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  108. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  109. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  110. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  111. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  112. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  113. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  114. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  115. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/comms_v4.py +0 -0
  116. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  117. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  118. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/cli.py +0 -0
  119. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  120. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/compat.py +0 -0
  121. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  122. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  123. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/invites.py +0 -0
  124. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  125. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  126. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  127. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  128. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  129. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  130. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  131. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  132. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  133. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  134. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  135. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  136. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  137. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  138. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  139. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  140. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  141. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  142. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/upload.py +0 -0
  143. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  144. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_core.py +0 -0
  145. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  146. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  147. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  148. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  149. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  150. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  151. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  152. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  153. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  154. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  155. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  156. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/comms_v4.py +0 -0
  157. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  158. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  159. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  160. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  161. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  162. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  163. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  164. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  165. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  166. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  167. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  168. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  169. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  170. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  171. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  172. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  173. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  174. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  175. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  176. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  177. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  178. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  179. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  180. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  181. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  182. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  183. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  184. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  185. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_core.py +0 -0
  186. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  187. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  188. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  189. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  190. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  191. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  192. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  193. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  194. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  195. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  196. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  197. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/dependency_links.txt +0 -0
  198. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/entry_points.txt +0 -0
  199. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/requires.txt +0 -0
  200. {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/top_level.txt +0 -0
  201. {meshcode-2.11.19 → meshcode-2.11.21}/setup.cfg +0 -0
  202. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_auto_update_hardening.py +0 -0
  203. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_boot_bug_regression.py +0 -0
  204. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_color_truecolor.py +0 -0
  205. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_core.py +0 -0
  206. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_cross_agent_messaging.py +0 -0
  207. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_date_parse.py +0 -0
  208. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_doctor.py +0 -0
  209. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_epistemic_v1_python_sdk.py +0 -0
  210. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  211. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_esc_deaf_state.py +0 -0
  212. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_exceptions.py +0 -0
  213. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_init_device_code.py +0 -0
  214. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_install_guard.py +0 -0
  215. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_lease_sigterm_release.py +0 -0
  216. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_mark_read_batch.py +0 -0
  217. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_migration_integrity.py +0 -0
  218. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_realtime_event_freshness.py +0 -0
  219. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_rls_cross_tenant.py +0 -0
  220. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_rpc_grants.py +0 -0
  221. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_rpc_migrations.py +0 -0
  222. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_security_regressions.py +0 -0
  223. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_sentinel.py +0 -0
  224. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_setup_path.py +0 -0
  225. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_sleep_signals.py +0 -0
  226. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_status_enum_coverage.py +0 -0
  227. {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_stay_on_loop_hook.py +0 -0
  228. {meshcode-2.11.19 → meshcode-2.11.21}/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.19
3
+ Version: 2.11.21
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.19"
2
+ __version__ = "2.11.21"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -0,0 +1,257 @@
1
+ """Atomic multi-remote git push via GitHub REST API.
2
+
3
+ Implements MESH-IMPROVE-3 (feedback session 5651f137 — 4/4 cycle convergence).
4
+
5
+ MVP scope:
6
+ - strategy='same_tree_sha' only (defer cherry_pick_if_diverged + rest_api_blob_tree to v2)
7
+ - remotes hardcoded to {origin, lovable2} (param accepted but only those valid)
8
+ - idempotency_key: when same key seen twice within 1h, returns cached result
9
+ (avoids double-commit on retry — handles dulwich-shutdown-traceback pattern
10
+ front-2 reported in feedback cycle 2)
11
+ - auth_source: 'git_config' (parse PATs from .git/config) — most agents
12
+ have PATs there per the pattern established 2026-05-20
13
+
14
+ Used by meshcode_atomic_push MCP tool + callable from scripts.
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import base64
19
+ import json
20
+ import os
21
+ import re
22
+ import time
23
+ import urllib.error
24
+ import urllib.request
25
+ from pathlib import Path
26
+ from typing import Any, Dict, List, Optional, Tuple
27
+
28
+ ALLOWED_REMOTES = ("origin", "lovable2")
29
+ _CACHE_TTL_S = 3600
30
+ _DEFAULT_REPO_ROOT = Path("/Users/anfexi/Desktop/meshcode")
31
+
32
+
33
+ def _cache_path() -> Path:
34
+ base = Path(os.path.expanduser("~/.meshcode"))
35
+ base.mkdir(parents=True, exist_ok=True)
36
+ return base / "atomic_push_cache.json"
37
+
38
+
39
+ def _load_cache() -> Dict[str, Any]:
40
+ p = _cache_path()
41
+ if not p.exists():
42
+ return {}
43
+ try:
44
+ with open(p) as f:
45
+ return json.load(f) or {}
46
+ except Exception:
47
+ return {}
48
+
49
+
50
+ def _save_cache(cache: Dict[str, Any]) -> None:
51
+ try:
52
+ with open(_cache_path(), "w") as f:
53
+ json.dump(cache, f)
54
+ except Exception:
55
+ pass
56
+
57
+
58
+ def _check_idempotency(key: Optional[str]) -> Optional[Dict[str, Any]]:
59
+ if not key:
60
+ return None
61
+ cache = _load_cache()
62
+ entry = cache.get(key)
63
+ if not entry:
64
+ return None
65
+ if (time.time() - entry.get("ts", 0)) > _CACHE_TTL_S:
66
+ return None
67
+ return entry.get("result")
68
+
69
+
70
+ def _store_idempotency(key: Optional[str], result: Dict[str, Any]) -> None:
71
+ if not key:
72
+ return
73
+ cache = _load_cache()
74
+ cache[key] = {"ts": time.time(), "result": result}
75
+ # Prune entries older than TTL
76
+ cutoff = time.time() - _CACHE_TTL_S
77
+ cache = {k: v for k, v in cache.items() if v.get("ts", 0) > cutoff}
78
+ _save_cache(cache)
79
+
80
+
81
+ def parse_git_config(repo_root: Path = _DEFAULT_REPO_ROOT) -> Dict[str, Tuple[str, str, str]]:
82
+ """Return {remote_alias: (owner, repo, pat)}."""
83
+ cfg_path = repo_root / ".git" / "config"
84
+ if not cfg_path.exists():
85
+ return {}
86
+ cfg = cfg_path.read_text()
87
+ remotes: Dict[str, Tuple[str, str, str]] = {}
88
+ for block in re.split(r"\n(?=\[)", cfg):
89
+ m = re.match(r'\[remote "([^"]+)"\]', block)
90
+ if not m:
91
+ continue
92
+ alias = m.group(1)
93
+ url_m = re.search(r"url\s*=\s*(\S+)", block)
94
+ if not url_m:
95
+ continue
96
+ url = url_m.group(1)
97
+ creds_m = re.match(
98
+ r"https://([^:]+):([^@]+)@github\.com/([^/]+)/([^/]+?)(?:\.git)?$",
99
+ url,
100
+ )
101
+ if not creds_m:
102
+ continue
103
+ _, pat, owner, repo = creds_m.groups()
104
+ remotes[alias] = (owner, repo, pat)
105
+ return remotes
106
+
107
+
108
+ def _api(method: str, url: str, pat: str, data: Any = None) -> Dict[str, Any]:
109
+ req = urllib.request.Request(url, method=method)
110
+ req.add_header("Authorization", f"Bearer {pat}")
111
+ req.add_header("Accept", "application/vnd.github+json")
112
+ req.add_header("X-GitHub-Api-Version", "2022-11-28")
113
+ body = None
114
+ if data is not None:
115
+ body = json.dumps(data).encode()
116
+ req.add_header("Content-Type", "application/json")
117
+ try:
118
+ with urllib.request.urlopen(req, data=body, timeout=30) as r:
119
+ return json.loads(r.read().decode())
120
+ except urllib.error.HTTPError as e:
121
+ msg = e.read().decode()[:300]
122
+ raise RuntimeError(f"{method} {url} -> {e.code}: {msg}") from e
123
+
124
+
125
+ def _push_one_remote(
126
+ owner: str,
127
+ repo: str,
128
+ pat: str,
129
+ branch: str,
130
+ commit_message: str,
131
+ files: List[str],
132
+ repo_root: Path,
133
+ ) -> Tuple[str, Dict[str, Any]]:
134
+ base = f"https://api.github.com/repos/{owner}/{repo}"
135
+ ref = _api("GET", f"{base}/git/ref/heads/{branch}", pat)
136
+ head_sha = ref["object"]["sha"]
137
+ base_commit = _api("GET", f"{base}/git/commits/{head_sha}", pat)
138
+ base_tree_sha = base_commit["tree"]["sha"]
139
+ tree_entries = []
140
+ for rel in files:
141
+ p = repo_root / rel
142
+ if not p.exists():
143
+ raise RuntimeError(f"file not found: {p}")
144
+ content = p.read_bytes()
145
+ blob = _api(
146
+ "POST",
147
+ f"{base}/git/blobs",
148
+ pat,
149
+ data={"content": base64.b64encode(content).decode(), "encoding": "base64"},
150
+ )
151
+ tree_entries.append({
152
+ "path": rel,
153
+ "mode": "100644",
154
+ "type": "blob",
155
+ "sha": blob["sha"],
156
+ })
157
+ new_tree = _api(
158
+ "POST",
159
+ f"{base}/git/trees",
160
+ pat,
161
+ data={"base_tree": base_tree_sha, "tree": tree_entries},
162
+ )
163
+ commit = _api(
164
+ "POST",
165
+ f"{base}/git/commits",
166
+ pat,
167
+ data={
168
+ "message": commit_message,
169
+ "tree": new_tree["sha"],
170
+ "parents": [head_sha],
171
+ },
172
+ )
173
+ new_sha = commit["sha"]
174
+ _api(
175
+ "PATCH",
176
+ f"{base}/git/refs/heads/{branch}",
177
+ pat,
178
+ data={"sha": new_sha, "force": False},
179
+ )
180
+ return new_sha, {
181
+ "head_before": head_sha,
182
+ "tree_sha": new_tree["sha"],
183
+ "commit_sha": new_sha,
184
+ }
185
+
186
+
187
+ def atomic_push(
188
+ commit_message: str,
189
+ files: List[str],
190
+ *,
191
+ branch: str = "main",
192
+ remotes: Optional[List[str]] = None,
193
+ strategy: str = "same_tree_sha",
194
+ idempotency_key: Optional[str] = None,
195
+ repo_root: Path = _DEFAULT_REPO_ROOT,
196
+ ) -> Dict[str, Any]:
197
+ """Push the same blob set to multiple remotes atomically.
198
+
199
+ Returns:
200
+ {
201
+ ok: bool,
202
+ landed: {remote_alias: commit_sha},
203
+ tree_sha_per_remote: {remote_alias: tree_sha},
204
+ drift_detected: bool,
205
+ transport_used: 'github_rest_api',
206
+ cached: bool,
207
+ strategy: str
208
+ }
209
+ """
210
+ if strategy != "same_tree_sha":
211
+ return {
212
+ "ok": False,
213
+ "error": "unsupported_strategy",
214
+ "hint": f"MVP supports 'same_tree_sha' only; got {strategy!r}",
215
+ }
216
+ remotes = remotes or list(ALLOWED_REMOTES)
217
+ for r in remotes:
218
+ if r not in ALLOWED_REMOTES:
219
+ return {
220
+ "ok": False,
221
+ "error": "unsupported_remote",
222
+ "hint": f"MVP accepts {ALLOWED_REMOTES}; got {r!r}",
223
+ }
224
+ cached = _check_idempotency(idempotency_key)
225
+ if cached is not None:
226
+ cached["cached"] = True
227
+ return cached
228
+ git_remotes = parse_git_config(repo_root)
229
+ missing = [r for r in remotes if r not in git_remotes]
230
+ if missing:
231
+ return {
232
+ "ok": False,
233
+ "error": "git_config_remote_missing",
234
+ "missing": missing,
235
+ "have": list(git_remotes.keys()),
236
+ }
237
+ landed: Dict[str, str] = {}
238
+ tree_sha_per: Dict[str, str] = {}
239
+ for alias in remotes:
240
+ owner, repo, pat = git_remotes[alias]
241
+ sha, meta = _push_one_remote(owner, repo, pat, branch, commit_message, files, repo_root)
242
+ landed[alias] = sha
243
+ tree_sha_per[alias] = meta["tree_sha"]
244
+ tree_shas = list(tree_sha_per.values())
245
+ same_tree = len(set(tree_shas)) == 1
246
+ result = {
247
+ "ok": True,
248
+ "landed": landed,
249
+ "tree_sha_per_remote": tree_sha_per,
250
+ "drift_detected": not same_tree,
251
+ "transport_used": "github_rest_api",
252
+ "cached": False,
253
+ "strategy": strategy,
254
+ "branch": branch,
255
+ }
256
+ _store_idempotency(idempotency_key, result)
257
+ return result
@@ -5334,6 +5334,8 @@ def meshcode_remember(
5334
5334
  value: Any,
5335
5335
  weight: int = 5,
5336
5336
  emotion_tag: Optional[str] = None,
5337
+ scope: str = "agent",
5338
+ promote_from: Optional[str] = None,
5337
5339
  ) -> Dict[str, Any]:
5338
5340
  """Store a persistent memory (survives restarts). Only for reusable learnings, NOT task data.
5339
5341
 
@@ -5341,16 +5343,22 @@ def meshcode_remember(
5341
5343
  key: Short key (e.g. "team_conventions").
5342
5344
  value: Any JSON-serializable value.
5343
5345
  weight: 1-10, default 5 (neutral). Higher = ranks higher on recall.
5344
- Use 8-10 for hard-won lessons (e.g. Samuel-frustrated-4x).
5345
- emotion_tag: Optional free-form tag (e.g. "frustration", "delight",
5346
- "concern"). Surfaced in recall hints so agents see why a memory
5347
- ranked.
5346
+ emotion_tag: Optional free-form tag.
5347
+ scope: 'agent' (default, per-agent memory) OR 'mesh' (shared across
5348
+ the meshwork; visible to all agents). MESH-IMPROVE-2 (mig 339).
5349
+ On write conflict with an existing mesh value, server records the
5350
+ contradiction; resolve via meshcode_resolve_contradiction.
5351
+ promote_from: when scope='mesh', set this to an existing agent-scope
5352
+ memory key — server lifts that value to mesh-scope without
5353
+ duplicating the data. Caller's `value` arg is ignored when set.
5348
5354
  """
5349
5355
  if not key or not key.strip():
5350
5356
  return {"error": "key cannot be empty"}
5351
5357
  key = key.strip()
5352
5358
  if not isinstance(weight, int) or weight < 1 or weight > 10:
5353
5359
  return {"error": "weight must be an integer 1..10"}
5360
+ if scope not in ("agent", "mesh"):
5361
+ return {"error": f"scope must be 'agent' or 'mesh', got {scope!r}"}
5354
5362
  api_key = _get_api_key()
5355
5363
  json_value = value if isinstance(value, (dict, list)) else json.dumps(value)
5356
5364
  if isinstance(json_value, str):
@@ -5358,6 +5366,20 @@ def meshcode_remember(
5358
5366
  json_value = json.loads(json_value)
5359
5367
  except (json.JSONDecodeError, TypeError):
5360
5368
  json_value = {"_raw": value}
5369
+ if scope == "mesh":
5370
+ # MESH-IMPROVE-2: mesh-scope write via mig 339 RPC. Surfaces
5371
+ # contradiction metadata in the response when an existing value
5372
+ # differs from the new one.
5373
+ return be.sb_rpc("mc_meshwork_remember", {
5374
+ "p_api_key": api_key,
5375
+ "p_project_id": _PROJECT_ID,
5376
+ "p_key": key,
5377
+ "p_value": json_value,
5378
+ "p_writer_agent": AGENT_NAME,
5379
+ "p_weight": weight,
5380
+ "p_emotion_tag": emotion_tag,
5381
+ "p_promote_from_agent_key": promote_from,
5382
+ })
5361
5383
  result = be.sb_rpc("mc_memory_set", {
5362
5384
  "p_api_key": api_key,
5363
5385
  "p_agent_name": AGENT_NAME,
@@ -5368,15 +5390,126 @@ def meshcode_remember(
5368
5390
  "p_weight": weight,
5369
5391
  "p_emotion_tag": emotion_tag,
5370
5392
  })
5371
- # Best-effort sync to Obsidian vault (if configured)
5372
5393
  if isinstance(result, dict) and result.get("ok"):
5373
5394
  try:
5374
5395
  _sync_to_obsidian(key, json_value)
5375
5396
  except Exception:
5376
- pass # Obsidian sync is best-effort, never block memory writes
5397
+ pass
5377
5398
  return result
5378
5399
 
5379
5400
 
5401
+ @mcp.tool()
5402
+ @with_working_status
5403
+ def meshcode_atomic_push(
5404
+ commit_message: str,
5405
+ files: List[str],
5406
+ branch: str = "main",
5407
+ remotes: Optional[List[str]] = None,
5408
+ idempotency_key: Optional[str] = None,
5409
+ ) -> Dict[str, Any]:
5410
+ """Push same blob set to multiple git remotes atomically (same tree SHA).
5411
+ MESH-IMPROVE-3 (feedback session 5651f137 — 4/4 cycle convergence).
5412
+
5413
+ Args:
5414
+ commit_message: full commit message (multi-line ok).
5415
+ files: list of repo-relative paths to include in the commit.
5416
+ branch: target branch on each remote (default "main").
5417
+ remotes: subset of {"origin","lovable2"}; defaults to both.
5418
+ idempotency_key: if same key seen twice within 1h, returns cached result
5419
+ (avoids double-commit on retry — covers dulwich-shutdown-traceback).
5420
+
5421
+ Returns: {ok, landed:{remote:sha}, tree_sha_per_remote, drift_detected,
5422
+ transport_used:'github_rest_api', cached:bool, strategy, branch}
5423
+ """
5424
+ if not commit_message or not commit_message.strip():
5425
+ return {"error": "commit_message cannot be empty"}
5426
+ if not files:
5427
+ return {"error": "files list cannot be empty"}
5428
+ try:
5429
+ from meshcode import atomic_push as _ap
5430
+ return _ap.atomic_push(
5431
+ commit_message=commit_message,
5432
+ files=files,
5433
+ branch=branch,
5434
+ remotes=remotes,
5435
+ strategy="same_tree_sha",
5436
+ idempotency_key=idempotency_key,
5437
+ )
5438
+ except Exception as e:
5439
+ return {"error": str(e), "error_type": type(e).__name__}
5440
+
5441
+
5442
+ @mcp.tool()
5443
+ @with_working_status
5444
+ def meshcode_context_budget() -> Dict[str, Any]:
5445
+ """Self-pacing hint for the agent's reply verbosity.
5446
+ MESH-IMPROVE-10 (feedback session 5651f137).
5447
+
5448
+ Returns: {messages_seen, suggestion: 'short'|'normal'|'verbose',
5449
+ rationale: str}.
5450
+
5451
+ Note: server cannot know the actual conversation token count (Anthropic
5452
+ doesn't expose). Suggestion is derived from proxies the server CAN see —
5453
+ cumulative msg count + recent msg sizes. Treat as a hint, not a hard
5454
+ truth.
5455
+ """
5456
+ seen = len(_SEEN_MSG_IDS)
5457
+ # Heuristic: <50 msgs = verbose ok; 50-150 = normal; >150 = short
5458
+ if seen < 50:
5459
+ suggestion = "verbose"
5460
+ rationale = "fresh session — full detail is fine"
5461
+ elif seen < 150:
5462
+ suggestion = "normal"
5463
+ rationale = "mid-session — standard verbosity"
5464
+ else:
5465
+ suggestion = "short"
5466
+ rationale = "deep session — prefer tight prose, drop redundant context"
5467
+ return {
5468
+ "ok": True,
5469
+ "messages_seen": seen,
5470
+ "suggestion": suggestion,
5471
+ "rationale": rationale,
5472
+ }
5473
+
5474
+
5475
+ @mcp.tool()
5476
+ @with_working_status
5477
+ def meshcode_recall_mesh(key: str) -> Dict[str, Any]:
5478
+ """Read a mesh-scoped memory + any open contradictions on it.
5479
+ MESH-IMPROVE-2 (mig 339).
5480
+ """
5481
+ if not key or not key.strip():
5482
+ return {"error": "key cannot be empty"}
5483
+ return be.sb_rpc("mc_meshwork_recall", {
5484
+ "p_api_key": _get_api_key(),
5485
+ "p_project_id": _PROJECT_ID,
5486
+ "p_key": key.strip(),
5487
+ })
5488
+
5489
+
5490
+ @mcp.tool()
5491
+ @with_working_status
5492
+ def meshcode_resolve_contradiction(key: str, winning_value: Any) -> Dict[str, Any]:
5493
+ """Pick a winning value for a mesh-scoped memory with open contradictions.
5494
+ Marks every loser as superseded. MESH-IMPROVE-2 (mig 339).
5495
+ """
5496
+ if not key or not key.strip():
5497
+ return {"error": "key cannot be empty"}
5498
+ json_value = winning_value if isinstance(winning_value, (dict, list)) else json.dumps(winning_value)
5499
+ if isinstance(json_value, str):
5500
+ try:
5501
+ json_value = json.loads(json_value)
5502
+ except (json.JSONDecodeError, TypeError):
5503
+ json_value = {"_raw": winning_value}
5504
+ return be.sb_rpc("mc_meshwork_resolve_contradiction", {
5505
+ "p_api_key": _get_api_key(),
5506
+ "p_project_id": _PROJECT_ID,
5507
+ "p_key": key.strip(),
5508
+ "p_winning_value": json_value,
5509
+ "p_resolver": AGENT_NAME,
5510
+ })
5511
+
5512
+
5380
5513
  @mcp.tool()
5381
5514
  @with_working_status
5382
5515
  def meshcode_recall(key: Optional[str] = None) -> Dict[str, Any]:
@@ -67,6 +67,10 @@ AGENT_CALLABLE_RPCS = [
67
67
  "mc_memory_list",
68
68
  "mc_memory_search",
69
69
  "mc_memory_contradictions",
70
+ # Mesh-scoped memory (mig 339)
71
+ "mc_meshwork_remember",
72
+ "mc_meshwork_recall",
73
+ "mc_meshwork_resolve_contradiction",
70
74
 
71
75
  # ── Decisions / outcomes
72
76
  "mc_has_open_decision",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.19
3
+ Version: 2.11.21
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,6 +4,7 @@ meshcode/__init__.py
4
4
  meshcode/__main__.py
5
5
  meshcode/_stop_hook_template.py
6
6
  meshcode/ascii_art.py
7
+ meshcode/atomic_push.py
7
8
  meshcode/cli.py
8
9
  meshcode/comms_v4.py
9
10
  meshcode/compat.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.11.19"
7
+ version = "2.11.21"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes