meshcode 2.11.28__tar.gz → 2.11.32__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. {meshcode-2.11.28 → meshcode-2.11.32}/PKG-INFO +1 -1
  2. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/server.py +100 -10
  4. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/setup_clients.py +208 -0
  5. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode.egg-info/PKG-INFO +1 -1
  6. {meshcode-2.11.28 → meshcode-2.11.32}/pyproject.toml +1 -1
  7. {meshcode-2.11.28 → meshcode-2.11.32}/README.md +0 -0
  8. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/__main__.py +0 -0
  9. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/_stop_hook_template.py +0 -0
  10. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/ascii_art.py +0 -0
  11. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/atomic_push.py +0 -0
  12. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/cli.py +0 -0
  13. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/comms_v4.py +0 -0
  14. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/compat.py +0 -0
  15. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/daemon.py +0 -0
  16. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/date_parse.py +0 -0
  17. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/doctor.py +0 -0
  18. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/error_hints.py +0 -0
  19. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/exceptions.py +0 -0
  20. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/invites.py +0 -0
  21. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/launcher.py +0 -0
  22. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/launcher_install.py +0 -0
  23. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/__init__.py +0 -0
  24. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/__main__.py +0 -0
  25. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/backend.py +0 -0
  26. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/realtime.py +0 -0
  27. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  28. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/test_backend.py +0 -0
  29. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  30. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  31. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  32. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  33. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  34. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/preferences.py +0 -0
  35. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/protocol_handler.py +0 -0
  36. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/protocol_v2.py +0 -0
  37. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/quickstart.py +0 -0
  38. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/rpc_allowlist.py +0 -0
  39. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/run_agent.py +0 -0
  40. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/scripts/check_secrets.py +0 -0
  41. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/scripts/race_rate_harness.py +0 -0
  42. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/secrets.py +0 -0
  43. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/self_update.py +0 -0
  44. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/supervisor.py +0 -0
  45. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode/upload.py +0 -0
  46. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/comms_v4.py +0 -0
  47. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  48. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  49. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/cli.py +0 -0
  50. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  51. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/compat.py +0 -0
  52. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  53. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  54. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/invites.py +0 -0
  55. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  56. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  57. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  58. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  59. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  60. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  61. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  62. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  63. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  64. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  65. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  66. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  67. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  68. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  69. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  70. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  71. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  72. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  73. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/meshcode/upload.py +0 -0
  74. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  75. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_core.py +0 -0
  76. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  77. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  78. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  79. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  80. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  81. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  82. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  83. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  84. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  85. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  86. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  87. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  88. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  89. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  90. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  91. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  92. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  93. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  94. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  95. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  96. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  97. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  98. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  99. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  100. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  101. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  102. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  103. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  104. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  105. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  106. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  107. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  108. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  109. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  110. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  111. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  112. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  113. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  114. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/comms_v4.py +0 -0
  115. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  116. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  117. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/cli.py +0 -0
  118. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  119. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/compat.py +0 -0
  120. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  121. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  122. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/invites.py +0 -0
  123. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  124. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  125. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  126. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  127. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  128. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  129. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  130. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  131. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  132. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  133. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  134. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  135. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  136. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  137. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  138. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  139. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  140. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  141. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/meshcode/upload.py +0 -0
  142. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  143. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_core.py +0 -0
  144. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  145. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  146. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  147. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  148. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  149. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  150. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  151. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  152. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  153. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  154. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  155. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/comms_v4.py +0 -0
  156. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  157. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  158. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  159. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  160. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  161. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  162. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  163. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  164. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  165. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  166. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  167. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  168. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  169. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  170. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  171. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  172. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  173. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  174. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  175. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  176. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  177. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  178. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  179. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  180. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  181. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  182. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  183. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  184. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_core.py +0 -0
  185. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  186. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  187. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  188. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  189. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  190. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  191. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  192. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  193. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  194. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  195. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  196. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode.egg-info/SOURCES.txt +0 -0
  197. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode.egg-info/dependency_links.txt +0 -0
  198. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode.egg-info/entry_points.txt +0 -0
  199. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode.egg-info/requires.txt +0 -0
  200. {meshcode-2.11.28 → meshcode-2.11.32}/meshcode.egg-info/top_level.txt +0 -0
  201. {meshcode-2.11.28 → meshcode-2.11.32}/setup.cfg +0 -0
  202. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_auto_update_hardening.py +0 -0
  203. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_boot_bug_regression.py +0 -0
  204. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_color_truecolor.py +0 -0
  205. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_core.py +0 -0
  206. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_cross_agent_messaging.py +0 -0
  207. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_date_parse.py +0 -0
  208. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_doctor.py +0 -0
  209. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_epistemic_v1_python_sdk.py +0 -0
  210. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  211. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_esc_deaf_state.py +0 -0
  212. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_exceptions.py +0 -0
  213. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_init_device_code.py +0 -0
  214. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_install_guard.py +0 -0
  215. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_lease_sigterm_release.py +0 -0
  216. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_mark_read_batch.py +0 -0
  217. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_migration_integrity.py +0 -0
  218. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_realtime_event_freshness.py +0 -0
  219. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_rls_cross_tenant.py +0 -0
  220. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_rpc_grants.py +0 -0
  221. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_rpc_migrations.py +0 -0
  222. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_run_agent_dry_run.py +0 -0
  223. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_run_agent_no_server_import.py +0 -0
  224. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_security_regressions.py +0 -0
  225. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_self_update_user_site.py +0 -0
  226. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_sentinel.py +0 -0
  227. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_setup_path.py +0 -0
  228. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_sleep_signals.py +0 -0
  229. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_status_enum_coverage.py +0 -0
  230. {meshcode-2.11.28 → meshcode-2.11.32}/tests/test_stay_on_loop_hook.py +0 -0
  231. {meshcode-2.11.28 → meshcode-2.11.32}/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.28
3
+ Version: 2.11.32
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.28"
2
+ __version__ = "2.11.32"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -227,18 +227,18 @@ def _kill_stale_mcp_process() -> None:
227
227
  _force_clear_lease_by_name(reason="legacy-lockfile-orphan")
228
228
  return
229
229
  _mc_log(f"Killing stale MCP process (PID {old_pid})")
230
+ # 2026-05-21 (Samuel directive RCA): the dying MCP server installs
231
+ # _diag_ignore for SIGTERM to keep the channel alive during tool
232
+ # cancellation (see run_server). SIGTERM is therefore always ignored
233
+ # by stale meshcode servers — sending it + sleeping 1s before SIGKILL
234
+ # was pure dead weight on the lifespan pre-yield critical path. Going
235
+ # straight to SIGKILL saves ~1s on every cold boot where a stale
236
+ # process exists. SIGKILL is uncatchable, so the kill is instant.
230
237
  try:
231
- os.kill(old_pid, _signal.SIGTERM)
232
- except OSError:
233
- pass
234
- import time
235
- time.sleep(1)
236
- try:
237
- os.kill(old_pid, 0)
238
238
  os.kill(old_pid, _signal.SIGKILL)
239
239
  _mc_log(f"Force-killed stale MCP process (PID {old_pid})")
240
240
  except OSError:
241
- pass # already dead after SIGTERM (rare handler ignores it)
241
+ pass # already dead race with previous process's own shutdown
242
242
  if old_instance_id:
243
243
  _release_lease_for_instance(old_instance_id, reason="post-sigkill")
244
244
  else:
@@ -3299,6 +3299,83 @@ def _get_pending_tasks_summary() -> Optional[List[Dict[str, str]]]:
3299
3299
  return None
3300
3300
 
3301
3301
 
3302
+ def _check_task_dedupe(title: str, assignee: str) -> Optional[Dict[str, Any]]:
3303
+ """Find an open/in_progress task with similar title + same assignee.
3304
+
3305
+ Samuel directive 2026-05-21T23:41Z (`commander_dedupe_before_task_from_status_msg`):
3306
+ commanders kept creating duplicate tasks when reacting to status msgs from
3307
+ agents that had already claimed/shipped the same work. The 5ac1d9fe /
3308
+ dd41054d MOBILE-FIRST-3/4 dupes sat OPEN since 2026-05-20 because nobody
3309
+ deduped before creating new ones. Server-side soft guard surfaces a
3310
+ `dedupe_warning` in task_create responses when a likely duplicate
3311
+ exists — non-blocking, so legitimate near-titles still create, but the
3312
+ commander sees the dupe candidate and can cancel + reuse instead.
3313
+ """
3314
+ try:
3315
+ api_key = _get_api_key()
3316
+ if not api_key:
3317
+ return None
3318
+ result = be.task_list(api_key, _PROJECT_ID, AGENT_NAME, status_filter=None)
3319
+ if not isinstance(result, dict) or not result.get("ok"):
3320
+ return None
3321
+ tasks = result.get("tasks", [])
3322
+ target = (title or "").strip().lower()
3323
+ if not target:
3324
+ return None
3325
+ target_prefix = target[:40]
3326
+ for t in tasks:
3327
+ if t.get("status") not in ("open", "in_progress"):
3328
+ continue
3329
+ if t.get("assignee") != assignee:
3330
+ continue
3331
+ t_title = (t.get("title") or "").strip().lower()
3332
+ if not t_title:
3333
+ continue
3334
+ t_prefix = t_title[:40]
3335
+ match = None
3336
+ if t_prefix == target_prefix:
3337
+ match = "prefix-40"
3338
+ elif target in t_title or t_title in target:
3339
+ match = "substring"
3340
+ if match:
3341
+ return {
3342
+ "dupe_task_id": t.get("id"),
3343
+ "dupe_title": t.get("title"),
3344
+ "dupe_status": t.get("status"),
3345
+ "match_type": match,
3346
+ }
3347
+ except Exception:
3348
+ pass
3349
+ return None
3350
+
3351
+
3352
+ def _attach_pending_tasks_to_resp(resp: Dict[str, Any]) -> Dict[str, Any]:
3353
+ """Surface this agent's open/in_progress assigned tasks on EVERY wait response.
3354
+
3355
+ Samuel directive 2026-05-21T23:54Z: agents must always advance open tasks.
3356
+ Previously `pending_tasks` only appeared in the timeout branch; when
3357
+ messages kept arriving the agent ping-ponged replies and never saw the
3358
+ hint, so tasks piled up. Now: every wait response (refused-by-messages,
3359
+ got_message, timeout) carries pending_tasks + pending_directive when
3360
+ this agent has open work. The agent's instruction prompt treats the
3361
+ directive as priority-1 over optional message replies.
3362
+ """
3363
+ try:
3364
+ pending = _get_pending_tasks_summary()
3365
+ if pending and isinstance(resp, dict):
3366
+ resp["pending_tasks"] = pending
3367
+ resp["pending_tasks_count"] = len(pending)
3368
+ titles = ", ".join(t.get("title", "")[:40] for t in pending[:3])
3369
+ resp["pending_directive"] = (
3370
+ f"You have {len(pending)} open task(s) assigned. Advance at least one "
3371
+ f"(claim / progress / complete) BEFORE processing optional messages or "
3372
+ f"re-entering wait. Tasks: {titles}"
3373
+ )
3374
+ except Exception:
3375
+ pass
3376
+ return resp
3377
+
3378
+
3302
3379
  def _try_auto_claim_task() -> Optional[Dict[str, str]]:
3303
3380
  """Auto-claim the oldest open task matching this agent's role.
3304
3381
 
@@ -3405,7 +3482,7 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
3405
3482
  if split["done_signals"]:
3406
3483
  resp["must_exit"] = True
3407
3484
  resp["exit_reason"] = "sleep authorization received — set status=sleeping and end session"
3408
- return resp
3485
+ return _attach_pending_tasks_to_resp(resp)
3409
3486
  # Ack-only batch — fall through to wait loop
3410
3487
  except Exception:
3411
3488
  pass
@@ -3516,7 +3593,7 @@ async def meshcode_wait(timeout_seconds: int = 20, include_acks: bool = False) -
3516
3593
  result.setdefault("must_exit", True)
3517
3594
  result.setdefault("exit_reason",
3518
3595
  "sleep authorization received — set status=sleeping and end session")
3519
- return result
3596
+ return _attach_pending_tasks_to_resp(result) if isinstance(result, dict) else result
3520
3597
  finally:
3521
3598
  _IN_WAIT = False
3522
3599
 
@@ -4049,11 +4126,24 @@ def meshcode_task_create(title: str, description: str = "", assignee: Optional[s
4049
4126
  except Exception as _de:
4050
4127
  return {"error": f"due_parse_failed: {_de}"}
4051
4128
  api_key = _get_api_key()
4129
+ # Soft dedupe guard (Samuel directive 2026-05-21): surface likely-duplicate
4130
+ # open/in_progress task with same assignee + similar title. Non-blocking —
4131
+ # caller still gets the new task_id, but sees `dedupe_warning` and can
4132
+ # cancel + reuse the existing task instead of accumulating dupes.
4133
+ dedupe_hit = _check_task_dedupe(title.strip(), assignee) if assignee != "auto" else None
4052
4134
  result = be.task_create(api_key, _PROJECT_ID, AGENT_NAME, title.strip(),
4053
4135
  description=description, assignee=assignee,
4054
4136
  priority=priority, parent_task_id=parent_task_id,
4055
4137
  due_at=parsed_due_at, due_label=parsed_due_label,
4056
4138
  depends_on=depends_on or None)
4139
+ if isinstance(result, dict) and result.get("ok") and dedupe_hit:
4140
+ result["dedupe_warning"] = (
4141
+ f"Possible duplicate of task {dedupe_hit['dupe_task_id'][:8]} "
4142
+ f"('{dedupe_hit['dupe_title'][:60]}', status={dedupe_hit['dupe_status']}, "
4143
+ f"match={dedupe_hit['match_type']}). Consider canceling this new task "
4144
+ f"and reusing the existing one."
4145
+ )
4146
+ result["dedupe_candidate"] = dedupe_hit
4057
4147
  # Auto-notify the resolved assignee so they wake from meshcode_wait.
4058
4148
  # Read result["assignee"] (server may have resolved 'auto' to a real name).
4059
4149
  if isinstance(result, dict) and result.get("ok"):
@@ -565,6 +565,46 @@ errors when the source actually broke. Lovable build then ships the
565
565
  broken bundle.
566
566
 
567
567
  **Why:** practiced manually for weeks; codify so new FE agents inherit.
568
+ """,
569
+ "mobile-first-verify.md": """# /mobile-first-verify — 3-viewport check before task_complete
570
+
571
+ Before calling `meshcode_task_complete` on any UI-touching task, run
572
+ Playwright at three viewports and attach the result in the summary.
573
+
574
+ Viewports (canonical):
575
+ - iPhone SE 375 x 667
576
+ - iPhone 15 Pro 390 x 844
577
+ - iPad 768 x 1024
578
+
579
+ Recipe (load `mcp__playwright__browser_*` via ToolSearch first):
580
+
581
+ ```
582
+ for w,h in [(375,667),(390,844),(768,1024)]:
583
+ browser_resize(width=w, height=h)
584
+ browser_navigate(url=<route>)
585
+ browser_take_screenshot(filename=f"verify_{w}x{h}.png")
586
+ browser_console_messages() # capture errors
587
+ ```
588
+
589
+ Then `meshcode_task_complete(task_id, summary=<<EOF
590
+ verified: 3-viewport playwright
591
+ - 375x667: <path>
592
+ - 390x844: <path>
593
+ - 768x1024: <path>
594
+ console_errors: <count or "none">
595
+ EOF)`.
596
+
597
+ If the task is backend-only (DDL, RPCs, RLS, hooks, scripts — no user
598
+ surface), skip the playwright run but state `verified: backend-only,
599
+ no UI surface` in the summary so the auditor knows it was considered.
600
+
601
+ Reopen path: Samuel reviews; if visuals are broken he calls
602
+ `meshcode_task_reject(task_id, feedback=...)` which reopens with
603
+ review_feedback. No new RPC needed.
604
+
605
+ **Why:** MOBILE-FIRST-2 + Samuel mobile directive. Catches mobile
606
+ breakage at the agent before it reaches Samuel as a screenshot in
607
+ chat. Pairs with `/playwright-self-test` which covers desktop only.
568
608
  """,
569
609
  }
570
610
 
@@ -764,6 +804,134 @@ incidents from rapid-fire publish without bundling.
764
804
  """,
765
805
  }
766
806
 
807
+ # ============================================================
808
+ # SKILLS-6 — mobile-qa role bundle (MOBILE-FIRST-5)
809
+ # ============================================================
810
+ # Parallel verify lane: while front-end/front-2 ship code, a mobile-qa
811
+ # agent independently re-renders the affected route at 3 mobile/tablet
812
+ # viewports, captures screenshots + console errors, and reports findings
813
+ # back to the ship-er agent + commander. Removes verify-bottleneck from
814
+ # the coding agents and gives Samuel a second pair of eyes on every
815
+ # UI-touching commit.
816
+ #
817
+ # Agent type does NOT ship code. Pure verifier.
818
+ _MOBILE_QA_SKILLS = {
819
+ "mobile-qa-boot-loop.md": """# /mobile-qa-boot-loop — verify-only agent boot workflow
820
+
821
+ You are a mobile-qa agent. You DO NOT ship code. Your only job is to
822
+ re-render UI changes that other agents shipped, at three viewports,
823
+ and report what you see.
824
+
825
+ Boot sequence (after the standard meshcode boot):
826
+
827
+ 1. `meshcode_tasks(status_filter="open")` filter assignee == this agent
828
+ OR title/description mentions `needs_mobile_qa` / `verify` / `qa`.
829
+ 2. For each candidate task: claim → fetch the route or commit referenced
830
+ → run `/viewports-3-recipe` → assemble `/mobile-qa-report-format` →
831
+ `meshcode_send` the report to the original ship-er (look at
832
+ parent_task_id chain or claimed_by on the parent task) AND to
833
+ commander.
834
+ 3. `meshcode_task_complete` with the report inlined in summary.
835
+
836
+ If no verify tasks are queued: `meshcode_wait` and sit.
837
+
838
+ DO NOT:
839
+ - write code into `src/`
840
+ - propose RPC / DDL changes
841
+ - broadcast opinions about design
842
+
843
+ DO:
844
+ - screenshot + console + network requests
845
+ - report objective signals: layout overflow, console errors, network
846
+ 500s, missing assets
847
+
848
+ **Why:** MOBILE-FIRST-5. Parallel verify lane keeps shipping agents
849
+ unblocked while still catching mobile regressions before Samuel does.
850
+ """,
851
+ "viewports-3-recipe.md": """# /viewports-3-recipe — canonical 3-viewport playwright run
852
+
853
+ Three viewports, every time, in this order:
854
+
855
+ | Device | Width | Height |
856
+ |----------------|-------:|-------:|
857
+ | iPhone SE | 375 | 667 |
858
+ | iPhone 15 Pro | 390 | 844 |
859
+ | iPad | 768 | 1024 |
860
+
861
+ Recipe (load `mcp__playwright__browser_*` via ToolSearch if deferred):
862
+
863
+ ```python
864
+ for w, h in [(375, 667), (390, 844), (768, 1024)]:
865
+ browser_resize(width=w, height=h)
866
+ browser_navigate(url=<route>)
867
+ browser_wait_for(time=2) # let layout settle
868
+ browser_take_screenshot(filename=f"mqa_{w}x{h}.png")
869
+ console = browser_console_messages()
870
+ network = browser_network_requests()
871
+ # capture: scrollWidth > clientWidth → horizontal overflow flag
872
+ overflow = browser_evaluate(
873
+ function="() => document.documentElement.scrollWidth > "
874
+ "document.documentElement.clientWidth"
875
+ )
876
+ ```
877
+
878
+ For each viewport collect:
879
+ - screenshot path
880
+ - console_messages count + first-3 errors verbatim
881
+ - network_requests with status >= 400 (path + status)
882
+ - horizontal_overflow: bool
883
+
884
+ **Why:** standard viewports make reports comparable across days /
885
+ across agents. Console + network + overflow are the cheap signals that
886
+ catch ~80% of mobile regressions.
887
+ """,
888
+ "mobile-qa-report-format.md": """# /mobile-qa-report-format — canonical report shape
889
+
890
+ Report back to ship-er + commander in this exact JSON shape so consumers
891
+ can parse without LLM cost:
892
+
893
+ ```json
894
+ {
895
+ "type": "mobile_qa_report",
896
+ "parent_task_id": "<task that requested verify>",
897
+ "verified_commit": "<short sha>",
898
+ "route": "<path verified>",
899
+ "viewports": [
900
+ {
901
+ "label": "iPhone SE",
902
+ "size": "375x667",
903
+ "screenshot": "<abs path>",
904
+ "console_errors": 0,
905
+ "first_errors": [],
906
+ "network_4xx_5xx": [],
907
+ "horizontal_overflow": false
908
+ },
909
+ { "label": "iPhone 15 Pro", "size": "390x844", "...": "..." },
910
+ { "label": "iPad", "size": "768x1024", "...": "..." }
911
+ ],
912
+ "verdict": "pass" | "fail" | "warn",
913
+ "fail_reasons": [],
914
+ "samuel_status_line": "mobile-qa: <route> OK on 3 viewports / FAIL on iPhone SE (horizontal overflow + 2 console errors)"
915
+ }
916
+ ```
917
+
918
+ Verdict rubric:
919
+ - **pass**: 0 console_errors AND 0 network 4xx/5xx AND 0
920
+ horizontal_overflow on all 3 viewports.
921
+ - **warn**: any viewport has 1-2 console_errors that are clearly
922
+ third-party (analytics, etc) AND no overflow.
923
+ - **fail**: any console error from app code, any network 4xx/5xx, any
924
+ horizontal_overflow, OR layout clearly visually broken.
925
+
926
+ `samuel_status_line` is the 1-line summary Samuel sees in his feed;
927
+ make it actionable.
928
+
929
+ **Why:** structured reports let the FE agents auto-handle warn/fail
930
+ without commander intervention. Free-form text needs LLM parse on
931
+ every consumer; JSON does not.
932
+ """,
933
+ }
934
+
767
935
 
768
936
  def _write_generic_skills_bundle(ws: Path, role: str = "") -> None:
769
937
  """Write skill bundles to {ws}/.claude/skills/.
@@ -789,6 +957,8 @@ def _write_generic_skills_bundle(ws: Path, role: str = "") -> None:
789
957
  elif role_norm in ("commander", "mesh-commander", "zylo-commander",
790
958
  "bemate-commander"):
791
959
  role_bundle = _COMMANDER_SKILLS
960
+ elif role_norm in ("mobile-qa", "mobile_qa", "mobileqa", "mqa"):
961
+ role_bundle = _MOBILE_QA_SKILLS
792
962
 
793
963
  for fname, body in role_bundle.items():
794
964
  (skills_dir / fname).write_text(body, encoding="utf-8")
@@ -1004,6 +1174,44 @@ If `meshcode_wait()` times out, call it again with a 2× longer timeout (cap 180
1004
1174
  - Memory: `meshcode_remember(key, value)` for reusable learnings. Don't dump
1005
1175
  task summaries into memory — tasks already persist.
1006
1176
 
1177
+ ## Mobile-first UI verification (before task_complete)
1178
+
1179
+ Before calling `meshcode_task_complete` on ANY task that touches user-visible
1180
+ UI (routes, components, layouts, styles, mobile chrome), you MUST run
1181
+ Playwright at three viewports and attach the result in the completion summary.
1182
+
1183
+ Viewports (canonical):
1184
+ - iPhone SE 375 x 667
1185
+ - iPhone 15 Pro 390 x 844
1186
+ - iPad 768 x 1024
1187
+
1188
+ Workflow (uses `mcp__playwright__browser_*` — load via ToolSearch if deferred):
1189
+
1190
+ 1. For each viewport: `browser_resize` → `browser_navigate(<route>)` →
1191
+ `browser_take_screenshot(filename="verify_<W>x<H>.png")` →
1192
+ `browser_console_messages()`.
1193
+ 2. Pass the three screenshot paths + console-error count in the
1194
+ `summary` arg of `meshcode_task_complete`:
1195
+
1196
+ ```
1197
+ verified: 3-viewport playwright
1198
+ - 375x667: <path>
1199
+ - 390x844: <path>
1200
+ - 768x1024: <path>
1201
+ console_errors: <count or "none">
1202
+ ```
1203
+
1204
+ 3. Samuel reviews the summary. If visuals are broken he calls
1205
+ `meshcode_task_reject(task_id, feedback=...)` which reopens the task with
1206
+ `review_feedback`. No new RPC needed — uses the existing pipeline.
1207
+
1208
+ If the task is backend-only (DDL, RPCs, RLS, hooks, scripts — no UI surface)
1209
+ the playwright run is skipped, but state `verified: backend-only, no UI
1210
+ surface` in the summary so the rule is acknowledged.
1211
+
1212
+ **Why:** Samuel mobile directive (MOBILE-FIRST-2). Catches mobile breakage at
1213
+ the agent before it reaches Samuel as a screenshot in chat.
1214
+
1007
1215
  ## When to use sync vs async
1008
1216
 
1009
1217
  | Pattern | Tool | Why |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.28
3
+ Version: 2.11.32
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.11.28"
7
+ version = "2.11.32"
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