meshcode 2.11.2__tar.gz → 2.11.4__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 (208) hide show
  1. {meshcode-2.11.2 → meshcode-2.11.4}/PKG-INFO +1 -1
  2. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/_stop_hook_template.py +75 -49
  4. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/server.py +68 -54
  5. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode.egg-info/PKG-INFO +1 -1
  6. {meshcode-2.11.2 → meshcode-2.11.4}/pyproject.toml +1 -1
  7. {meshcode-2.11.2 → meshcode-2.11.4}/README.md +0 -0
  8. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/ascii_art.py +0 -0
  9. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/cli.py +0 -0
  10. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/comms_v4.py +0 -0
  11. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/compat.py +0 -0
  12. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/daemon.py +0 -0
  13. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/error_hints.py +0 -0
  14. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/exceptions.py +0 -0
  15. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/invites.py +0 -0
  16. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/launcher.py +0 -0
  17. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/launcher_install.py +0 -0
  18. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/__init__.py +0 -0
  19. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/__main__.py +0 -0
  20. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/backend.py +0 -0
  21. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/realtime.py +0 -0
  22. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/test_backend.py +0 -0
  23. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  24. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  25. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/preferences.py +0 -0
  26. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/protocol_handler.py +0 -0
  27. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/protocol_v2.py +0 -0
  28. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/quickstart.py +0 -0
  29. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/run_agent.py +0 -0
  30. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/scripts/check_secrets.py +0 -0
  31. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/scripts/race_rate_harness.py +0 -0
  32. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/secrets.py +0 -0
  33. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/self_update.py +0 -0
  34. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/setup_clients.py +0 -0
  35. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/supervisor.py +0 -0
  36. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode/upload.py +0 -0
  37. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/comms_v4.py +0 -0
  38. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  39. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  40. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/cli.py +0 -0
  41. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  42. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/compat.py +0 -0
  43. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  44. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  45. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/invites.py +0 -0
  46. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  47. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  48. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  49. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  50. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  51. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  52. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  53. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  54. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  55. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  56. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  57. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  58. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  59. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  60. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  61. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  62. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  63. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  64. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/meshcode/upload.py +0 -0
  65. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  66. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_core.py +0 -0
  67. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  68. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  69. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  70. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  71. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  72. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  73. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  74. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  75. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  76. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  77. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  78. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  79. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  80. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  81. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  82. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  83. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  84. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  85. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  86. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  87. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  88. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  89. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  90. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  91. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  92. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  93. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  94. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  95. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  96. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  97. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  98. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  99. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  100. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  101. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  102. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  103. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  104. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  105. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/comms_v4.py +0 -0
  106. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  107. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  108. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/cli.py +0 -0
  109. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  110. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/compat.py +0 -0
  111. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  112. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  113. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/invites.py +0 -0
  114. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  115. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  116. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  117. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  118. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  119. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  120. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  121. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  122. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  123. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  124. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  125. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  126. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  127. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  128. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  129. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  130. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  131. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  132. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/meshcode/upload.py +0 -0
  133. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  134. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_core.py +0 -0
  135. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  136. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  137. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  138. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  139. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  140. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  141. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  142. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  143. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  144. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  145. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  146. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/comms_v4.py +0 -0
  147. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  148. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  149. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  150. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  151. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  152. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  153. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  154. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  155. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  156. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  157. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  158. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  159. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  160. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  161. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  162. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  163. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  164. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  165. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  166. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  167. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  168. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  169. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  170. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  171. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  172. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  173. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  174. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  175. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_core.py +0 -0
  176. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  177. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  178. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  179. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  180. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  181. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  182. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  183. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  184. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  185. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  186. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  187. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode.egg-info/SOURCES.txt +0 -0
  188. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode.egg-info/dependency_links.txt +0 -0
  189. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode.egg-info/entry_points.txt +0 -0
  190. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode.egg-info/requires.txt +0 -0
  191. {meshcode-2.11.2 → meshcode-2.11.4}/meshcode.egg-info/top_level.txt +0 -0
  192. {meshcode-2.11.2 → meshcode-2.11.4}/setup.cfg +0 -0
  193. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_auto_update_hardening.py +0 -0
  194. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_core.py +0 -0
  195. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_cross_agent_messaging.py +0 -0
  196. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_esc_deaf_state.py +0 -0
  197. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_exceptions.py +0 -0
  198. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_lease_sigterm_release.py +0 -0
  199. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_mark_read_batch.py +0 -0
  200. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_migration_integrity.py +0 -0
  201. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_realtime_event_freshness.py +0 -0
  202. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_rls_cross_tenant.py +0 -0
  203. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_rpc_migrations.py +0 -0
  204. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_security_regressions.py +0 -0
  205. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_sentinel.py +0 -0
  206. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_status_enum_coverage.py +0 -0
  207. {meshcode-2.11.2 → meshcode-2.11.4}/tests/test_stay_on_loop_hook.py +0 -0
  208. {meshcode-2.11.2 → meshcode-2.11.4}/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.2
3
+ Version: 2.11.4
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.2"
2
+ __version__ = "2.11.4"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -109,6 +109,23 @@ _USER_MCP_FAIL_PHRASES = (
109
109
  )
110
110
 
111
111
 
112
+ def _rec_role_content(rec):
113
+ """Extract (role, content) from a Claude Code transcript record.
114
+
115
+ Claude Code wraps user/assistant payloads in `rec["message"]` since the
116
+ schema migration; older parsers that read top-level `rec["role"]` /
117
+ `rec["content"]` MISS every record and silently never fire. Normalize
118
+ here so every helper sees the canonical shape. Falls back to top-level
119
+ keys for forward compat with hypothetical older transcripts.
120
+ """
121
+ if not isinstance(rec, dict):
122
+ return None, None
123
+ msg = rec.get("message")
124
+ if isinstance(msg, dict):
125
+ return msg.get("role"), msg.get("content")
126
+ return rec.get("role"), rec.get("content")
127
+
128
+
112
129
  def _last_user_message(transcript_path):
113
130
  try:
114
131
  last = ""
@@ -118,8 +135,8 @@ def _last_user_message(transcript_path):
118
135
  rec = json.loads(line)
119
136
  except json.JSONDecodeError:
120
137
  continue
121
- if rec.get("role") == "user":
122
- content = rec.get("content")
138
+ role, content = _rec_role_content(rec)
139
+ if role == "user":
123
140
  if isinstance(content, str):
124
141
  last = content
125
142
  elif isinstance(content, list):
@@ -147,12 +164,12 @@ def _last_assistant_turn_called_wait(transcript_path):
147
164
  continue
148
165
  last_assistant_blocks = []
149
166
  for rec in reversed(records):
150
- if rec.get("role") == "user":
167
+ role, content = _rec_role_content(rec)
168
+ if role == "user":
151
169
  if last_assistant_blocks:
152
170
  break
153
171
  continue
154
- if rec.get("role") == "assistant":
155
- content = rec.get("content")
172
+ if role == "assistant":
156
173
  if isinstance(content, list):
157
174
  last_assistant_blocks.extend(content)
158
175
  elif isinstance(content, dict):
@@ -185,9 +202,9 @@ def _latest_wait_result_authorizes_exit(transcript_path):
185
202
 
186
203
  wait_use_ids = set()
187
204
  for rec in records:
188
- if rec.get("role") != "assistant":
205
+ role, content = _rec_role_content(rec)
206
+ if role != "assistant":
189
207
  continue
190
- content = rec.get("content")
191
208
  blocks = content if isinstance(content, list) else [content] if isinstance(content, dict) else []
192
209
  for block in blocks:
193
210
  if not isinstance(block, dict):
@@ -201,9 +218,9 @@ def _latest_wait_result_authorizes_exit(transcript_path):
201
218
  return False
202
219
 
203
220
  for rec in reversed(records):
204
- if rec.get("role") != "user":
221
+ role, content = _rec_role_content(rec)
222
+ if role != "user":
205
223
  continue
206
- content = rec.get("content")
207
224
  blocks = content if isinstance(content, list) else [content] if isinstance(content, dict) else []
208
225
  for block in blocks:
209
226
  if not isinstance(block, dict):
@@ -310,7 +327,7 @@ def _mcp_unreachable_recently(transcript_path, lookback_records=_UNREACHABLE_LOO
310
327
  wait_tool_use_ids = set()
311
328
  toolsearch_wait_ids = set()
312
329
  for rec in tail:
313
- content = rec.get("content")
330
+ _, content = _rec_role_content(rec)
314
331
  blocks = content if isinstance(content, list) else [content] if isinstance(content, dict) else []
315
332
  for block in blocks:
316
333
  if not isinstance(block, dict):
@@ -353,52 +370,61 @@ def _mcp_unreachable_recently(transcript_path, lookback_records=_UNREACHABLE_LOO
353
370
 
354
371
 
355
372
  def _latest_deferred_listing_lacks_meshcode(transcript_path, lookback_records=_UNREACHABLE_LOOKBACK):
356
- """Find the most recent <system-reminder> that enumerates deferred
357
- tools. If it lists mcp__ entries (proving the listing format is
358
- canonical) but ZERO meshcode_* entries, the meshcode MCP server is
359
- not registered for this session. Release.
360
-
361
- Note: the listing is delivered as user-role content, often inside a
362
- <system-reminder>...</system-reminder> block but sometimes plain.
363
- We match on the marker substrings rather than tag parsing.
373
+ """Detect "meshcode MCP never loaded this session" by inspecting the
374
+ structured deferred-tools attachments Claude Code writes to the
375
+ transcript jsonl. Records of the form:
376
+
377
+ {"type": "attachment",
378
+ "attachment": {"type": "deferred_tools_delta",
379
+ "addedNames": ["mcp__claude_ai_Gmail__...", ...]}}
380
+
381
+ accumulate over the session — meshcode tools land as
382
+ `mcp__meshcode-<server>__<tool>` once the server registers. If we
383
+ walk every delta and find ZERO meshcode entries (but DID find OTHER
384
+ mcp__ entries, confirming Claude Code is recording deltas at all),
385
+ the meshcode MCP server is missing for this session → release.
386
+
387
+ Replaces the previous text-marker scan ("the following deferred tools
388
+ are now available") — Claude Code never writes that rendered text
389
+ into the transcript; only the structured attachment. The old scan
390
+ therefore never fired, trapping agents whose MCP server failed at
391
+ boot in an infinite stay-on-loop. Confirmed via bob@justforfun
392
+ cross-mesh repro (2026-05-14) + Samuel mesh-commander launch.
364
393
  """
365
394
  try:
366
- records = []
395
+ seen_other_mcp = False
396
+ seen_meshcode = False
397
+ record_count = 0
367
398
  with transcript_path.open() as f:
368
399
  for line in f:
369
400
  try:
370
- records.append(json.loads(line))
401
+ rec = json.loads(line)
371
402
  except json.JSONDecodeError:
372
403
  continue
373
- tail = records[-lookback_records:] if lookback_records else records
374
- for rec in reversed(tail):
375
- if rec.get("role") != "user":
376
- continue
377
- content = rec.get("content")
378
- blocks = content if isinstance(content, list) else [content] if isinstance(content, dict) else [content]
379
- for block in blocks:
380
- if isinstance(block, str):
381
- text = block
382
- elif isinstance(block, dict):
383
- if block.get("type") == "tool_result":
384
- # tool_result blocks aren't system-reminders; skip
385
- continue
386
- text = str(block.get("text", "") or block.get("content", "") or "")
387
- else:
404
+ record_count += 1
405
+ att = rec.get("attachment") if isinstance(rec, dict) else None
406
+ if not isinstance(att, dict):
388
407
  continue
389
- lower = text.lower()
390
- if not any(m in lower for m in _DEFERRED_LISTING_MARKERS):
408
+ if att.get("type") != "deferred_tools_delta":
391
409
  continue
392
- # Found a listing. Check if it enumerates real tools.
393
- has_mcp = "mcp__" in lower
394
- has_meshcode = "meshcode_" in lower
395
- if has_mcp and not has_meshcode:
396
- return True
397
- # First listing that contains meshcode_ is enough to
398
- # confirm MCP IS registered stop searching backwards.
399
- if has_meshcode:
400
- return False
401
- return False
410
+ names = att.get("addedNames") or []
411
+ if not isinstance(names, list):
412
+ continue
413
+ for n in names:
414
+ if not isinstance(n, str):
415
+ continue
416
+ # meshcode tools are namespaced under their server name:
417
+ # `mcp__meshcode-<server>__<tool>`. Substring check covers
418
+ # all variants (self-improve, justforfun, mesh-dev, etc.).
419
+ if "meshcode-" in n and "__meshcode_" in n:
420
+ seen_meshcode = True
421
+ elif n.startswith("mcp__"):
422
+ seen_other_mcp = True
423
+ # Release only when we have evidence Claude Code IS recording deltas
424
+ # (other mcp__ tools present) but no meshcode_* entries appeared.
425
+ # Without the seen_other_mcp guard we'd false-positive on transcripts
426
+ # that simply haven't reached any deferred-tools delta yet.
427
+ return bool(seen_other_mcp and not seen_meshcode)
402
428
  except (OSError, FileNotFoundError):
403
429
  return False
404
430
 
@@ -420,9 +446,9 @@ def _user_explicitly_reports_mcp_failure(transcript_path, lookback_records=_UNRE
420
446
  continue
421
447
  tail = records[-lookback_records:] if lookback_records else records
422
448
  for rec in reversed(tail):
423
- if rec.get("role") != "user":
449
+ role, content = _rec_role_content(rec)
450
+ if role != "user":
424
451
  continue
425
- content = rec.get("content")
426
452
  text = ""
427
453
  if isinstance(content, str):
428
454
  text = content
@@ -501,17 +501,22 @@ def _filter_and_mark(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
501
501
 
502
502
  _SLEEP_PAYLOAD_TYPES = {"sleep", "go_to_sleep", "shutdown", "got_done", "done",
503
503
  "exit", "stop", "kill", "terminate"}
504
- # Spanish + English markers (es-MX hot path per SDK-S6.1). Matched as
505
- # substrings, lowercased before compare. Keep exclusive enough to not
506
- # false-positive on casual chatter (e.g. "no quiero dormir" still matches
507
- # accepted tradeoff for user-control reliability).
504
+ # Multi-word imperative markers ONLY. Single Spanish verbs like "salir" /
505
+ # "terminar" / "duerme" were too loose and caught idiomatic prose like
506
+ # "terminaron sus tasks" or "no puedo salir" (msg cfbd36b0 2026-05-14 alexa +
507
+ # commander incidents feedback_done_signal_false_positive_idiomatic
508
+ # precedent). The parser now requires a directive-shaped phrase: a verb
509
+ # combined with a temporal/object qualifier ("ahora" / "todos" / "to sleep")
510
+ # so describing an event in prose can't trip must_exit.
508
511
  _SLEEP_TEXT_MARKERS = (
509
- # English
512
+ # English directives
510
513
  "go to sleep", "all sleep now", "sleep now", "got_done", "go_done",
511
514
  "shut down", "shutdown", "stop now", "exit now",
512
- # Spanish (es-MX, sammybenu's primary)
513
- "a dormir", "todos a dormir", "duerme", "duerman", "dormir ahora",
514
- "salir", "terminar", "para la sesion", "exit y duerme",
515
+ # Spanish directives (es-MX, sammybenu's primary). All require either a
516
+ # leading "a"/"todos" or a trailing "ahora" so plain conjugations
517
+ # ("salir", "terminar", "duerme") in body prose don't trigger.
518
+ "a dormir", "todos a dormir", "duerme ahora", "duerman ahora",
519
+ "dormir ahora", "para la sesion", "exit y duerme",
515
520
  )
516
521
 
517
522
 
@@ -2305,12 +2310,10 @@ def meshcode_send(to: Union[str, List[str]], message: Any, in_reply_to: Optional
2305
2310
  to = recipients[0]
2306
2311
  if isinstance(message, str):
2307
2312
  # Auto-wrap strings into dict. Reject very long content; suggest
2308
- # task_create for >4000 chars so receiver context isn't blown.
2309
- # Cap raised from 2000 4000 (R3-CONV-1, 2026-05-05) — round-2/3
2310
- # task reports kept hitting the old cap and required forced
2311
- # downsizing or task_create fallback.
2312
- if len(message) > 4000:
2313
- return {"error": f"message too long ({len(message)} chars). Use meshcode_task_create for long content, or split into multiple messages. Max ~4000 chars."}
2313
+ # task_create for >8000 chars. Cap raised 4000 8000 (mig 303,
2314
+ # 2026-05-14) Samuel hit the old cap on consolidations.
2315
+ if len(message) > 8000:
2316
+ return {"error": f"message too long ({len(message)} chars). Use meshcode_task_create for long content, or split into multiple messages. Max ~8000 chars."}
2314
2317
  payload: Dict[str, Any] = {"text": message}
2315
2318
  elif isinstance(message, dict):
2316
2319
  payload = message
@@ -2328,13 +2331,10 @@ def meshcode_send(to: Union[str, List[str]], message: Any, in_reply_to: Optional
2328
2331
  payload["text"] = _synth if len(_synth) <= 280 else _synth[:279] + "…"
2329
2332
 
2330
2333
  # Enforce message size limit — long content belongs in task descriptions.
2331
- # Cap raised 20004000 (R3-CONV-1, 2026-05-05). Above 2000 chars the
2332
- # error message hints at task_create so callers learn the convention,
2333
- # but the hard cap is at 4000 so structured JSON reports don't get
2334
- # forcibly trimmed mid-payload.
2334
+ # Cap raised 40008000 chars in line with mig 303 (16KB DB cap).
2335
2335
  _payload_len = len(_json.dumps(payload, default=str))
2336
- if _payload_len > 4000:
2337
- return {"error": f"message too large ({_payload_len} chars). Use meshcode_task_create for long content. Messages must be structured JSON <4000 chars."}
2336
+ if _payload_len > 8000:
2337
+ return {"error": f"message too large ({_payload_len} chars). Use meshcode_task_create for long content. Messages must be structured JSON <8000 chars."}
2338
2338
 
2339
2339
  # Typed-catalog soft validation (BE-S4.2.sdk / mig 233): if caller
2340
2340
  # passes type=, fetch the schema and check required fields. NEVER
@@ -2671,6 +2671,13 @@ def meshcode_download_file(file_id: str) -> Dict[str, Any]:
2671
2671
  Returns file content for text/JSON files, or saves to temp file and
2672
2672
  returns the path for images (Claude can view image files directly).
2673
2673
 
2674
+ Download strategy:
2675
+ 1. mc_get_file_download RPC returns metadata + (when GUC is configured
2676
+ on the backend) a short-lived signed_url. If signed_url present,
2677
+ fetch it WITHOUT auth headers — works for any agent without
2678
+ per-client service_role secret distribution. Closes 235e85b6 PATH B.
2679
+ 2. Fallback: legacy service_role/anon/public path on the storage_path.
2680
+
2674
2681
  Args:
2675
2682
  file_id: UUID of the file (from message payload's file.file_id).
2676
2683
  """
@@ -2682,23 +2689,55 @@ def meshcode_download_file(file_id: str) -> Dict[str, Any]:
2682
2689
  if not api_key:
2683
2690
  return {"error": "no api key", "error_code": "auth_failed"}
2684
2691
 
2685
- # Step 1: Get file metadata via RPC
2692
+ def _consume(content: bytes, mime_type: str, file_name: str) -> Dict[str, Any]:
2693
+ if mime_type.startswith("text/") or mime_type == "application/json":
2694
+ try:
2695
+ text = content.decode("utf-8")
2696
+ if mime_type == "application/json":
2697
+ return {"ok": True, "file_name": file_name, "mime_type": mime_type,
2698
+ "content": json.loads(text)}
2699
+ return {"ok": True, "file_name": file_name, "mime_type": mime_type,
2700
+ "content": text[:50000]}
2701
+ except Exception:
2702
+ pass
2703
+ suffix = "." + file_name.rsplit(".", 1)[-1] if "." in file_name else ""
2704
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix, prefix="meshcode_")
2705
+ tmp.write(content)
2706
+ tmp.close()
2707
+ return {
2708
+ "ok": True,
2709
+ "file_name": file_name,
2710
+ "mime_type": mime_type,
2711
+ "size_bytes": len(content),
2712
+ "local_path": tmp.name,
2713
+ "note": "File saved to local_path. For images, use Read tool to view.",
2714
+ }
2715
+
2686
2716
  file_info = be.sb_rpc("mc_get_file_download", {
2687
2717
  "p_api_key": api_key,
2688
2718
  "p_file_id": file_id,
2689
2719
  })
2690
2720
  if not file_info or not file_info.get("ok"):
2691
- return {"error": file_info.get("error", "file not found"), "error_code": "not_found"}
2721
+ return {"error": (file_info or {}).get("error", "file not found"), "error_code": "not_found"}
2692
2722
 
2693
2723
  storage_path = file_info["storage_path"]
2694
2724
  bucket = file_info.get("bucket", "meshcode-files")
2695
2725
  mime_type = file_info.get("mime_type", "application/octet-stream")
2696
2726
  file_name = file_info.get("file_name", "download")
2727
+ signed_url = file_info.get("signed_url")
2697
2728
 
2698
- # Step 2: Download from Supabase Storage.
2699
- # The bucket is private, so the publishable/anon key returns 404. We try
2700
- # the keys in order: service_role (if user opted in) → anon → public-bucket
2701
- # fallback. Most setups need service_role for cross-agent file access.
2729
+ # Strategy 1: signed_url (no auth headers, no client service_role needed)
2730
+ if signed_url:
2731
+ try:
2732
+ with _req.urlopen(_req.Request(signed_url), timeout=30) as resp:
2733
+ content = resp.read()
2734
+ return _consume(content, mime_type, file_name)
2735
+ except _uerr.HTTPError:
2736
+ pass # fall through to legacy path
2737
+ except Exception:
2738
+ pass
2739
+
2740
+ # Strategy 2: legacy service_role/anon/public on storage_path
2702
2741
  sb_url = os.environ.get("SUPABASE_URL", be._sb_url if hasattr(be, '_sb_url') else "")
2703
2742
  anon_key = os.environ.get("SUPABASE_KEY", be._sb_key if hasattr(be, '_sb_key') else "")
2704
2743
  service_key = os.environ.get("MESHCODE_SUPABASE_SERVICE_KEY", "")
@@ -2732,7 +2771,7 @@ def meshcode_download_file(file_id: str) -> Dict[str, Any]:
2732
2771
 
2733
2772
  last_err = None
2734
2773
  content = None
2735
- tried_labels = []
2774
+ tried_labels: List[str] = ["signed_url"] if signed_url else []
2736
2775
  for label, _url, _key in attempts:
2737
2776
  tried_labels.append(label)
2738
2777
  try:
@@ -2750,35 +2789,10 @@ def meshcode_download_file(file_id: str) -> Dict[str, Any]:
2750
2789
  "error_code": "download_error",
2751
2790
  "tried": tried_labels,
2752
2791
  "storage_path": storage_path,
2753
- "hint": "set MESHCODE_SUPABASE_SERVICE_KEY in the MCP server env to enable service_role downloads (private bucket)" if not service_key else None,
2792
+ "hint": "ask commander to apply backend GUC app.settings.service_role_key + supabase_url so the RPC can mint signed URLs" if not signed_url else None,
2754
2793
  }
2755
2794
 
2756
- # Step 3: Return content based on type
2757
- if mime_type.startswith("text/") or mime_type == "application/json":
2758
- try:
2759
- text = content.decode("utf-8")
2760
- if mime_type == "application/json":
2761
- return {"ok": True, "file_name": file_name, "mime_type": mime_type,
2762
- "content": json.loads(text)}
2763
- return {"ok": True, "file_name": file_name, "mime_type": mime_type,
2764
- "content": text[:50000]} # cap at 50k chars
2765
- except Exception:
2766
- pass
2767
-
2768
- # For images and binary: save to temp file, return path
2769
- suffix = "." + file_name.rsplit(".", 1)[-1] if "." in file_name else ""
2770
- tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix, prefix="meshcode_")
2771
- tmp.write(content)
2772
- tmp.close()
2773
-
2774
- return {
2775
- "ok": True,
2776
- "file_name": file_name,
2777
- "mime_type": mime_type,
2778
- "size_bytes": len(content),
2779
- "local_path": tmp.name,
2780
- "note": "File saved to local_path. For images, use Read tool to view.",
2781
- }
2795
+ return _consume(content, mime_type, file_name)
2782
2796
 
2783
2797
 
2784
2798
  def _detect_global_done(messages: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.2
3
+ Version: 2.11.4
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.2"
7
+ version = "2.11.4"
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
File without changes
File without changes
File without changes
File without changes
File without changes