meshcode 2.11.69__tar.gz → 2.11.71__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 (268) hide show
  1. {meshcode-2.11.69 → meshcode-2.11.71}/PKG-INFO +1 -1
  2. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/__init__.py +1 -1
  3. meshcode-2.11.71/meshcode/ascii_art.py +638 -0
  4. meshcode-2.11.71/meshcode/cli.py +42 -0
  5. meshcode-2.11.71/meshcode/compat.py +174 -0
  6. meshcode-2.11.71/meshcode/error_hints.py +74 -0
  7. meshcode-2.11.71/meshcode/exceptions.py +52 -0
  8. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/hostd.py +50 -21
  9. meshcode-2.11.71/meshcode/invites.py +406 -0
  10. meshcode-2.11.71/meshcode/launcher.py +353 -0
  11. meshcode-2.11.71/meshcode/launcher_install.py +414 -0
  12. meshcode-2.11.71/meshcode/meshcode_mcp/__init__.py +22 -0
  13. meshcode-2.11.71/meshcode/meshcode_mcp/__main__.py +62 -0
  14. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/meshcode_mcp/server.py +38 -0
  15. meshcode-2.11.71/meshcode/meshcode_mcp/test_backend.py +86 -0
  16. meshcode-2.11.71/meshcode/meshcode_mcp/test_realtime.py +95 -0
  17. meshcode-2.11.71/meshcode/meshcode_mcp/test_server_wrapper.py +117 -0
  18. meshcode-2.11.71/meshcode/preferences.py +260 -0
  19. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/protocol_handler.py +28 -4
  20. meshcode-2.11.71/meshcode/protocol_v2.py +129 -0
  21. meshcode-2.11.71/meshcode/secrets.py +365 -0
  22. meshcode-2.11.71/meshcode/supervisor.py +186 -0
  23. meshcode-2.11.71/meshcode/upload.py +125 -0
  24. meshcode-2.11.71/meshcode-backend-wt/comms_v4.py +1941 -0
  25. meshcode-2.11.71/meshcode-backend-wt/meshcode/__init__.py +82 -0
  26. meshcode-2.11.71/meshcode-backend-wt/meshcode/comms_v4.py +3563 -0
  27. meshcode-2.11.71/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +1261 -0
  28. meshcode-2.11.71/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +460 -0
  29. meshcode-2.11.71/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +4117 -0
  30. meshcode-2.11.71/meshcode-backend-wt/meshcode/quickstart.py +148 -0
  31. meshcode-2.11.71/meshcode-backend-wt/meshcode/run_agent.py +958 -0
  32. meshcode-2.11.71/meshcode-backend-wt/meshcode/self_update.py +345 -0
  33. meshcode-2.11.71/meshcode-backend-wt/meshcode/setup_clients.py +926 -0
  34. meshcode-2.11.71/meshcode-backend-wt/scripts/sentinel.py +257 -0
  35. meshcode-2.11.71/meshcode-backend-wt/tests/test_rpc_migrations.py +387 -0
  36. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/__init__.py +82 -0
  37. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +638 -0
  38. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/cli.py +42 -0
  39. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +3563 -0
  40. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/compat.py +174 -0
  41. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/error_hints.py +74 -0
  42. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/exceptions.py +52 -0
  43. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/invites.py +406 -0
  44. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/launcher.py +353 -0
  45. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +414 -0
  46. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +22 -0
  47. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +62 -0
  48. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +1261 -0
  49. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +460 -0
  50. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +4117 -0
  51. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +86 -0
  52. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +95 -0
  53. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +117 -0
  54. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/preferences.py +260 -0
  55. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +129 -0
  56. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/quickstart.py +148 -0
  57. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/run_agent.py +958 -0
  58. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/secrets.py +365 -0
  59. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/self_update.py +345 -0
  60. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +926 -0
  61. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/supervisor.py +186 -0
  62. meshcode-2.11.71/meshcode-noun-wt/build/lib/meshcode/upload.py +125 -0
  63. meshcode-2.11.71/meshcode-noun-wt/comms_v4.py +1941 -0
  64. meshcode-2.11.71/meshcode-noun-wt/meshcode/__init__.py +82 -0
  65. meshcode-2.11.71/meshcode-noun-wt/meshcode/ascii_art.py +638 -0
  66. meshcode-2.11.71/meshcode-noun-wt/meshcode/cli.py +42 -0
  67. meshcode-2.11.71/meshcode-noun-wt/meshcode/comms_v4.py +3563 -0
  68. meshcode-2.11.71/meshcode-noun-wt/meshcode/compat.py +174 -0
  69. meshcode-2.11.71/meshcode-noun-wt/meshcode/error_hints.py +74 -0
  70. meshcode-2.11.71/meshcode-noun-wt/meshcode/exceptions.py +52 -0
  71. meshcode-2.11.71/meshcode-noun-wt/meshcode/invites.py +406 -0
  72. meshcode-2.11.71/meshcode-noun-wt/meshcode/launcher.py +353 -0
  73. meshcode-2.11.71/meshcode-noun-wt/meshcode/launcher_install.py +414 -0
  74. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +22 -0
  75. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +62 -0
  76. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +1261 -0
  77. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +460 -0
  78. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +4117 -0
  79. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +86 -0
  80. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +95 -0
  81. meshcode-2.11.71/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +117 -0
  82. meshcode-2.11.71/meshcode-noun-wt/meshcode/preferences.py +260 -0
  83. meshcode-2.11.71/meshcode-noun-wt/meshcode/protocol_v2.py +129 -0
  84. meshcode-2.11.71/meshcode-noun-wt/meshcode/quickstart.py +148 -0
  85. meshcode-2.11.71/meshcode-noun-wt/meshcode/run_agent.py +958 -0
  86. meshcode-2.11.71/meshcode-noun-wt/meshcode/secrets.py +365 -0
  87. meshcode-2.11.71/meshcode-noun-wt/meshcode/self_update.py +345 -0
  88. meshcode-2.11.71/meshcode-noun-wt/meshcode/setup_clients.py +926 -0
  89. meshcode-2.11.71/meshcode-noun-wt/meshcode/supervisor.py +186 -0
  90. meshcode-2.11.71/meshcode-noun-wt/meshcode/upload.py +125 -0
  91. meshcode-2.11.71/meshcode-noun-wt/scripts/sentinel.py +257 -0
  92. meshcode-2.11.71/meshcode-noun-wt/tests/test_core.py +216 -0
  93. meshcode-2.11.71/meshcode-noun-wt/tests/test_cross_agent_messaging.py +366 -0
  94. meshcode-2.11.71/meshcode-noun-wt/tests/test_esc_deaf_state.py +361 -0
  95. meshcode-2.11.71/meshcode-noun-wt/tests/test_exceptions.py +107 -0
  96. meshcode-2.11.71/meshcode-noun-wt/tests/test_mark_read_batch.py +200 -0
  97. meshcode-2.11.71/meshcode-noun-wt/tests/test_migration_integrity.py +176 -0
  98. meshcode-2.11.71/meshcode-noun-wt/tests/test_realtime_event_freshness.py +236 -0
  99. meshcode-2.11.71/meshcode-noun-wt/tests/test_rls_cross_tenant.py +255 -0
  100. meshcode-2.11.71/meshcode-noun-wt/tests/test_rpc_migrations.py +387 -0
  101. meshcode-2.11.71/meshcode-noun-wt/tests/test_security_regressions.py +171 -0
  102. meshcode-2.11.71/meshcode-noun-wt/tests/test_sentinel.py +148 -0
  103. meshcode-2.11.71/meshcode-noun-wt/tests/test_status_enum_coverage.py +231 -0
  104. meshcode-2.11.71/meshcode-tasks-wt/comms_v4.py +1941 -0
  105. meshcode-2.11.71/meshcode-tasks-wt/meshcode/__init__.py +82 -0
  106. meshcode-2.11.71/meshcode-tasks-wt/meshcode/ascii_art.py +638 -0
  107. meshcode-2.11.71/meshcode-tasks-wt/meshcode/cli.py +42 -0
  108. meshcode-2.11.71/meshcode-tasks-wt/meshcode/comms_v4.py +3563 -0
  109. meshcode-2.11.71/meshcode-tasks-wt/meshcode/compat.py +174 -0
  110. meshcode-2.11.71/meshcode-tasks-wt/meshcode/error_hints.py +74 -0
  111. meshcode-2.11.71/meshcode-tasks-wt/meshcode/exceptions.py +52 -0
  112. meshcode-2.11.71/meshcode-tasks-wt/meshcode/invites.py +406 -0
  113. meshcode-2.11.71/meshcode-tasks-wt/meshcode/launcher.py +353 -0
  114. meshcode-2.11.71/meshcode-tasks-wt/meshcode/launcher_install.py +414 -0
  115. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +22 -0
  116. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +62 -0
  117. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +1261 -0
  118. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +460 -0
  119. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +4117 -0
  120. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +86 -0
  121. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +95 -0
  122. meshcode-2.11.71/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +117 -0
  123. meshcode-2.11.71/meshcode-tasks-wt/meshcode/preferences.py +260 -0
  124. meshcode-2.11.71/meshcode-tasks-wt/meshcode/protocol_v2.py +129 -0
  125. meshcode-2.11.71/meshcode-tasks-wt/meshcode/quickstart.py +148 -0
  126. meshcode-2.11.71/meshcode-tasks-wt/meshcode/run_agent.py +958 -0
  127. meshcode-2.11.71/meshcode-tasks-wt/meshcode/secrets.py +365 -0
  128. meshcode-2.11.71/meshcode-tasks-wt/meshcode/self_update.py +345 -0
  129. meshcode-2.11.71/meshcode-tasks-wt/meshcode/setup_clients.py +926 -0
  130. meshcode-2.11.71/meshcode-tasks-wt/meshcode/supervisor.py +186 -0
  131. meshcode-2.11.71/meshcode-tasks-wt/meshcode/upload.py +125 -0
  132. meshcode-2.11.71/meshcode-tasks-wt/scripts/sentinel.py +257 -0
  133. meshcode-2.11.71/meshcode-tasks-wt/tests/test_core.py +216 -0
  134. meshcode-2.11.71/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +366 -0
  135. meshcode-2.11.71/meshcode-tasks-wt/tests/test_esc_deaf_state.py +361 -0
  136. meshcode-2.11.71/meshcode-tasks-wt/tests/test_exceptions.py +107 -0
  137. meshcode-2.11.71/meshcode-tasks-wt/tests/test_mark_read_batch.py +200 -0
  138. meshcode-2.11.71/meshcode-tasks-wt/tests/test_migration_integrity.py +176 -0
  139. meshcode-2.11.71/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +236 -0
  140. meshcode-2.11.71/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +255 -0
  141. meshcode-2.11.71/meshcode-tasks-wt/tests/test_rpc_migrations.py +387 -0
  142. meshcode-2.11.71/meshcode-tasks-wt/tests/test_security_regressions.py +171 -0
  143. meshcode-2.11.71/meshcode-tasks-wt/tests/test_sentinel.py +148 -0
  144. meshcode-2.11.71/meshcode-tasks-wt/tests/test_status_enum_coverage.py +231 -0
  145. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode.egg-info/PKG-INFO +1 -1
  146. meshcode-2.11.71/meshcode.egg-info/PKG-INFO 2 +452 -0
  147. meshcode-2.11.71/meshcode.egg-info/SOURCES 2.txt +250 -0
  148. meshcode-2.11.71/meshcode.egg-info/SOURCES.txt +264 -0
  149. meshcode-2.11.71/meshcode.egg-info/dependency_links.txt +1 -0
  150. meshcode-2.11.71/meshcode.egg-info/entry_points.txt +3 -0
  151. meshcode-2.11.71/meshcode.egg-info/requires.txt +13 -0
  152. meshcode-2.11.71/meshcode.egg-info/top_level 2.txt +4 -0
  153. meshcode-2.11.71/meshcode.egg-info/top_level.txt +4 -0
  154. {meshcode-2.11.69 → meshcode-2.11.71}/pyproject.toml +1 -1
  155. meshcode-2.11.71/tests/test_autonomous_prompt_inject 11.py +126 -0
  156. meshcode-2.11.71/tests/test_autonomous_prompt_inject 12.py +126 -0
  157. meshcode-2.11.71/tests/test_autonomous_prompt_inject 13.py +126 -0
  158. meshcode-2.11.71/tests/test_autonomous_prompt_inject 14.py +126 -0
  159. meshcode-2.11.71/tests/test_autonomous_prompt_inject 15.py +126 -0
  160. meshcode-2.11.71/tests/test_autonomous_prompt_inject 16.py +126 -0
  161. meshcode-2.11.71/tests/test_autonomous_prompt_inject 17.py +126 -0
  162. meshcode-2.11.71/tests/test_autonomous_prompt_inject 18.py +126 -0
  163. meshcode-2.11.71/tests/test_autonomous_prompt_inject 19.py +126 -0
  164. meshcode-2.11.71/tests/test_autonomous_prompt_inject 2.py +126 -0
  165. meshcode-2.11.71/tests/test_autonomous_prompt_inject 20.py +126 -0
  166. meshcode-2.11.71/tests/test_autonomous_prompt_inject 21.py +126 -0
  167. meshcode-2.11.71/tests/test_autonomous_prompt_inject 3.py +126 -0
  168. meshcode-2.11.71/tests/test_autonomous_prompt_inject 4.py +126 -0
  169. meshcode-2.11.71/tests/test_autonomous_prompt_inject 5.py +126 -0
  170. meshcode-2.11.71/tests/test_autonomous_prompt_inject 6.py +126 -0
  171. meshcode-2.11.71/tests/test_autonomous_prompt_inject 7.py +126 -0
  172. meshcode-2.11.71/tests/test_autonomous_prompt_inject 8.py +126 -0
  173. meshcode-2.11.71/tests/test_autonomous_prompt_inject 9.py +126 -0
  174. meshcode-2.11.71/tests/test_autonomous_prompt_inject.py +126 -0
  175. meshcode-2.11.71/tests/test_core.py +216 -0
  176. meshcode-2.11.71/tests/test_cross_agent_messaging.py +366 -0
  177. meshcode-2.11.71/tests/test_esc_deaf_state.py +361 -0
  178. meshcode-2.11.71/tests/test_exceptions.py +107 -0
  179. meshcode-2.11.71/tests/test_mark_read_batch.py +200 -0
  180. meshcode-2.11.71/tests/test_migration_integrity.py +176 -0
  181. meshcode-2.11.71/tests/test_realtime_event_freshness.py +236 -0
  182. meshcode-2.11.71/tests/test_rls_cross_tenant.py +255 -0
  183. meshcode-2.11.71/tests/test_security_regressions.py +171 -0
  184. meshcode-2.11.71/tests/test_sentinel.py +148 -0
  185. meshcode-2.11.71/tests/test_status_enum_coverage.py +231 -0
  186. meshcode-2.11.69/meshcode.egg-info/SOURCES.txt +0 -88
  187. meshcode-2.11.69/meshcode.egg-info/top_level.txt +0 -1
  188. {meshcode-2.11.69 → meshcode-2.11.71}/README.md +0 -0
  189. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/__main__.py +0 -0
  190. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/_stop_hook_template.py +0 -0
  191. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/atomic_push.py +0 -0
  192. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/claude_update.py +0 -0
  193. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/comms_v4.py +0 -0
  194. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/daemon.py +0 -0
  195. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/date_parse.py +0 -0
  196. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/doctor.py +0 -0
  197. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/meshcode_mcp/backend.py +0 -0
  198. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/meshcode_mcp/realtime.py +0 -0
  199. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  200. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
  201. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
  202. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
  203. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/quickstart.py +0 -0
  204. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/rpc_allowlist.py +0 -0
  205. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/run_agent.py +0 -0
  206. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/scripts/check_secrets.py +0 -0
  207. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/scripts/race_rate_harness.py +0 -0
  208. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/self_update.py +0 -0
  209. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/setup_clients.py +0 -0
  210. {meshcode-2.11.69 → meshcode-2.11.71}/meshcode/up.py +0 -0
  211. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/ascii_art.py +0 -0
  212. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/cli.py +0 -0
  213. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/compat.py +0 -0
  214. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/error_hints.py +0 -0
  215. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/exceptions.py +0 -0
  216. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/invites.py +0 -0
  217. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/launcher.py +0 -0
  218. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/launcher_install.py +0 -0
  219. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/meshcode_mcp/__init__.py +0 -0
  220. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/meshcode_mcp/__main__.py +0 -0
  221. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/meshcode_mcp/test_backend.py +0 -0
  222. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  223. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  224. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/preferences.py +0 -0
  225. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/protocol_v2.py +0 -0
  226. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/secrets.py +0 -0
  227. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/supervisor.py +0 -0
  228. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/meshcode/upload.py +0 -0
  229. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_core.py +0 -0
  230. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_cross_agent_messaging.py +0 -0
  231. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_esc_deaf_state.py +0 -0
  232. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_exceptions.py +0 -0
  233. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_mark_read_batch.py +0 -0
  234. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_migration_integrity.py +0 -0
  235. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_realtime_event_freshness.py +0 -0
  236. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_rls_cross_tenant.py +0 -0
  237. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_security_regressions.py +0 -0
  238. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_sentinel.py +0 -0
  239. {meshcode-2.11.69 → meshcode-2.11.71/meshcode-backend-wt}/tests/test_status_enum_coverage.py +0 -0
  240. /meshcode-2.11.69/meshcode.egg-info/dependency_links.txt → /meshcode-2.11.71/meshcode.egg-info/dependency_links 2.txt +0 -0
  241. /meshcode-2.11.69/meshcode.egg-info/entry_points.txt → /meshcode-2.11.71/meshcode.egg-info/entry_points 2.txt +0 -0
  242. /meshcode-2.11.69/meshcode.egg-info/requires.txt → /meshcode-2.11.71/meshcode.egg-info/requires 2.txt +0 -0
  243. {meshcode-2.11.69 → meshcode-2.11.71}/setup.cfg +0 -0
  244. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_auto_update_hardening.py +0 -0
  245. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_autonomous_closegap_1.py +0 -0
  246. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_autonomous_closegap_2.py +0 -0
  247. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_autonomous_closegap_3.py +0 -0
  248. /meshcode-2.11.69/tests/test_autonomous_prompt_inject.py → /meshcode-2.11.71/tests/test_autonomous_prompt_inject 10.py +0 -0
  249. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_boot_bug_regression.py +0 -0
  250. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_color_truecolor.py +0 -0
  251. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_date_parse.py +0 -0
  252. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_doctor.py +0 -0
  253. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_epistemic_v1_python_sdk.py +0 -0
  254. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_epistemic_v1_stop_conditions.py +0 -0
  255. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_file_upload.py +0 -0
  256. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_init_device_code.py +0 -0
  257. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_install_guard.py +0 -0
  258. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_lease_sigterm_release.py +0 -0
  259. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_marketplace_ratings.py +0 -0
  260. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_rpc_grants.py +0 -0
  261. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_rpc_migrations.py +0 -0
  262. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_run_agent_dry_run.py +0 -0
  263. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_run_agent_no_server_import.py +0 -0
  264. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_self_update_user_site.py +0 -0
  265. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_setup_path.py +0 -0
  266. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_sleep_signals.py +0 -0
  267. {meshcode-2.11.69 → meshcode-2.11.71}/tests/test_stay_on_loop_hook.py +0 -0
  268. {meshcode-2.11.69 → meshcode-2.11.71}/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.69
3
+ Version: 2.11.71
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.69"
2
+ __version__ = "2.11.71"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -0,0 +1,638 @@
1
+ """Procedural ASCII art + agent personality generator for MeshCode.
2
+
3
+ Each agent gets:
4
+ - Unique identicon (QR-style, varied borders, from SHA-256 hash)
5
+ - Personality traits (based on actual role)
6
+ - Catchphrase (unique motto)
7
+ - Boot greeting (personalized online message)
8
+ - Achievements (from real stats)
9
+ - Session tips
10
+
11
+ Identicons are GUARANTEED unique — SHA-256 produces 2^256 patterns.
12
+ The embedded tag ⟨ meshwork/agent ⟩ enables paste-to-run.
13
+ """
14
+ import hashlib
15
+
16
+ # ── Block characters ────────────────────────────────────────────────
17
+ BLOCKS = {
18
+ 0: " ", # empty
19
+ 1: "██", # full block
20
+ 2: "░░", # light shade
21
+ 3: "▓▓", # dark shade
22
+ 4: "▒▒", # medium shade
23
+ 5: "╬╬", # cross
24
+ 6: "◆◆", # diamond
25
+ }
26
+
27
+ # ── Border styles (varied shapes per agent) ─────────────────────────
28
+ BORDERS = [
29
+ # 0: Classic box
30
+ {"tl": "┌", "tr": "┐", "bl": "└", "br": "┘", "h": "─", "v": "│"},
31
+ # 1: Double line
32
+ {"tl": "╔", "tr": "╗", "bl": "╚", "br": "╝", "h": "═", "v": "║"},
33
+ # 2: Rounded
34
+ {"tl": "╭", "tr": "╮", "bl": "╰", "br": "╯", "h": "─", "v": "│"},
35
+ # 3: Heavy
36
+ {"tl": "┏", "tr": "┓", "bl": "┗", "br": "┛", "h": "━", "v": "┃"},
37
+ # 4: Diamond frame
38
+ {"tl": "◇", "tr": "◇", "bl": "◇", "br": "◇", "h": "─", "v": "│"},
39
+ # 5: Dot frame
40
+ {"tl": "●", "tr": "●", "bl": "●", "br": "●", "h": "·", "v": "·"},
41
+ # 6: Block frame
42
+ {"tl": "▛", "tr": "▜", "bl": "▙", "br": "▟", "h": "▀", "v": "▌"},
43
+ # 7: Arrow frame
44
+ {"tl": "▸", "tr": "◂", "bl": "▸", "br": "◂", "h": "─", "v": "│"},
45
+ ]
46
+
47
+ # ── Shapes (grid layout variations) ─────────────────────────────────
48
+ # Each shape defines which cells are "active" in a 9x9 grid
49
+ # This gives different silhouettes beyond just square
50
+
51
+ SHAPES = [
52
+ "square", # 0: full square
53
+ "diamond", # 1: diamond/rhombus
54
+ "hexagon", # 2: hex-ish
55
+ "shield", # 3: shield shape (wide top, narrow bottom)
56
+ "circle", # 4: circular-ish
57
+ "cross", # 5: plus/cross shape
58
+ ]
59
+
60
+
61
+ def _hash_bytes(name: str) -> bytes:
62
+ return hashlib.sha256(name.encode("utf-8")).digest()
63
+
64
+
65
+ def _hash_int(name: str) -> int:
66
+ return int(hashlib.md5(name.encode()).hexdigest()[:8], 16)
67
+
68
+
69
+ def _in_shape(shape: str, y: int, x: int, size: int) -> bool:
70
+ """Check if cell (y,x) is inside the given shape."""
71
+ cy, cx = size // 2, size // 2
72
+ if shape == "square":
73
+ return True
74
+ elif shape == "diamond":
75
+ return abs(y - cy) + abs(x - cx) <= cy
76
+ elif shape == "hexagon":
77
+ return abs(y - cy) + max(0, abs(x - cx) - 1) <= cy
78
+ elif shape == "shield":
79
+ # Wide top, tapers at bottom
80
+ max_width = cx - max(0, (y - cy)) * (cx // (size - cy))
81
+ return abs(x - cx) <= max(1, cx - max(0, y - cy))
82
+ elif shape == "circle":
83
+ return ((y - cy) ** 2 + (x - cx) ** 2) <= (cy + 0.5) ** 2
84
+ elif shape == "cross":
85
+ return abs(y - cy) <= 1 or abs(x - cx) <= 1
86
+ return True
87
+
88
+
89
+ def generate_art(agent_name: str, meshwork_name: str = "", size: int = 7) -> str:
90
+ """Generate a unique identicon with varied border and shape.
91
+
92
+ The pattern is deterministic from the agent name — same name = same art.
93
+ Embeds meshwork/agent tag for paste-to-run feature.
94
+ """
95
+ h = _hash_bytes(agent_name)
96
+ hi = _hash_int(agent_name)
97
+
98
+ # Select border style and shape from hash
99
+ border = BORDERS[h[0] % len(BORDERS)]
100
+ shape = SHAPES[h[1] % len(SHAPES)]
101
+
102
+ half = (size + 1) // 2
103
+ rows = []
104
+
105
+ for y in range(size):
106
+ row = []
107
+ for x in range(half):
108
+ idx = (y * half + x) % len(h)
109
+ byte_val = h[idx]
110
+
111
+ # Check if this cell is inside the shape
112
+ # Mirror x for full width check
113
+ full_x = x # left half
114
+ if not _in_shape(shape, y, full_x, size):
115
+ row.append(BLOCKS[0])
116
+ continue
117
+
118
+ # Fill decision: vary density based on hash byte
119
+ if byte_val < 90:
120
+ block = BLOCKS[0] # empty
121
+ else:
122
+ block_idx = (byte_val % 6) + 1
123
+ block = BLOCKS[block_idx]
124
+ row.append(block)
125
+
126
+ # Mirror: build full row
127
+ if size % 2 == 1:
128
+ full_row = row[:-1] + [row[-1]] + row[-2::-1]
129
+ else:
130
+ full_row = row + row[::-1]
131
+ rows.append("".join(full_row))
132
+
133
+ # Build framed output
134
+ width = len(rows[0]) if rows else 0
135
+ border_h = border["h"] * (width + 2)
136
+ lines = []
137
+ lines.append(f" {border['tl']}{border_h}{border['tr']}")
138
+ for row in rows:
139
+ lines.append(f" {border['v']} {row} {border['v']}")
140
+ lines.append(f" {border['bl']}{border_h}{border['br']}")
141
+
142
+ # Embedded tag (visual identity)
143
+ if meshwork_name:
144
+ lines.append(f" ⟨ {meshwork_name}/{agent_name} ⟩")
145
+ else:
146
+ lines.append(f" ⟨ {agent_name} ⟩")
147
+
148
+ return "\n".join(lines)
149
+
150
+
151
+ # ── Pixel Mascot renderer (Unicode block art) ──────────────────────
152
+ # Renders a small pixel character using Unicode half-block chars.
153
+ # Deterministic from agent name hash, like the identicon but cuter.
154
+
155
+ _MASCOT_BODY_TEMPLATES = {
156
+ "round": [
157
+ " ████ ",
158
+ " ██████ ",
159
+ "████████",
160
+ "████████",
161
+ " ██████ ",
162
+ " ████ ",
163
+ ],
164
+ "square": [
165
+ "████████",
166
+ "██ ██",
167
+ "██ ██",
168
+ "██ ██",
169
+ "██ ██",
170
+ "████████",
171
+ ],
172
+ "tall": [
173
+ " ████ ",
174
+ " ██████ ",
175
+ " ██████ ",
176
+ " ██████ ",
177
+ " ██████ ",
178
+ " ████ ",
179
+ " ████ ",
180
+ " ████ ",
181
+ ],
182
+ "wide": [
183
+ "██████████",
184
+ "██ ██",
185
+ "██████████",
186
+ " ████████ ",
187
+ ],
188
+ "triangle": [
189
+ " ██ ",
190
+ " ████ ",
191
+ " ██████ ",
192
+ "████████",
193
+ "████████",
194
+ " ██ ██ ",
195
+ ],
196
+ }
197
+
198
+ _MASCOT_EYES = {
199
+ "dots": ("●", "●"),
200
+ "circles": ("◉", "◉"),
201
+ "angry": ("▼", "▼"),
202
+ "happy": ("◠", "◠"),
203
+ "sleepy": ("—", "—"),
204
+ "star": ("★", "★"),
205
+ }
206
+
207
+ _MASCOT_HATS = {
208
+ "none": [],
209
+ "hat": [" ▄▄ ", " ████ "],
210
+ "glasses": [], # applied as eye overlay
211
+ "antenna": [" | ", " (◉) "],
212
+ "headphones": [" ╔══╗ "],
213
+ "crown": [" ▲ ▲ ▲ ", " ████ "],
214
+ }
215
+
216
+
217
+ def render_pixel_mascot(agent_name: str, mascot_config: dict = None) -> str:
218
+ """Render a pixel mascot as Unicode art for terminal display.
219
+
220
+ If mascot_config is None, generates deterministic defaults from agent name.
221
+ """
222
+ h = _hash_bytes(agent_name)
223
+ hi = _hash_int(agent_name)
224
+
225
+ if mascot_config is None or mascot_config.get("generated"):
226
+ body_types = list(_MASCOT_BODY_TEMPLATES.keys())
227
+ eye_styles = list(_MASCOT_EYES.keys())
228
+ body_type = body_types[hi % len(body_types)]
229
+ eye_style = eye_styles[(hi // 10) % len(eye_styles)]
230
+ accessory = "none"
231
+ equipped = []
232
+ else:
233
+ body_type = mascot_config.get("body_type", "round")
234
+ eye_style = mascot_config.get("eye_style", "dots")
235
+ accessory = mascot_config.get("accessory", "none")
236
+ equipped = mascot_config.get("equipped", [])
237
+
238
+ # Get body template
239
+ body = list(_MASCOT_BODY_TEMPLATES.get(body_type, _MASCOT_BODY_TEMPLATES["round"]))
240
+
241
+ # Add eyes (on the 2nd or 3rd row depending on body)
242
+ eye_row = min(1, len(body) - 1)
243
+ if len(body) > 3:
244
+ eye_row = 2
245
+ eyes = _MASCOT_EYES.get(eye_style, _MASCOT_EYES["dots"])
246
+ if eye_row < len(body):
247
+ row = list(body[eye_row])
248
+ # Place eyes at 1/3 and 2/3 positions
249
+ w = len(row)
250
+ left_eye = w // 3
251
+ right_eye = 2 * w // 3
252
+ if left_eye < w:
253
+ row[left_eye] = eyes[0]
254
+ if right_eye < w:
255
+ row[right_eye] = eyes[1]
256
+ body[eye_row] = "".join(row)
257
+
258
+ # Add hat/accessory on top
259
+ hat_lines = _MASCOT_HATS.get(accessory, [])
260
+ # Check equipped accessories for hat/crown
261
+ for item in equipped:
262
+ if "crown" in item:
263
+ hat_lines = _MASCOT_HATS.get("crown", [])
264
+ break
265
+ elif "hat" in item:
266
+ hat_lines = _MASCOT_HATS.get("hat", [])
267
+ break
268
+ elif "antenna" in item:
269
+ hat_lines = _MASCOT_HATS.get("antenna", [])
270
+ break
271
+
272
+ lines = hat_lines + body
273
+
274
+ # Add feet
275
+ lines.append(" ▀ ▀ ")
276
+
277
+ return "\n".join(f" {line}" for line in lines)
278
+
279
+
280
+ # ── ANSI colors ─────────────────────────────────────────────────────
281
+ COLORS = [
282
+ "\033[36m", "\033[35m", "\033[32m", "\033[33m", "\033[34m",
283
+ "\033[91m", "\033[96m", "\033[95m", "\033[92m", "\033[94m",
284
+ ]
285
+ # Same palette as hex RGB for nearest-match mapping from dashboard colors
286
+ _ANSI_RGB = [
287
+ (0, 255, 255), # 0: cyan \033[36m
288
+ (255, 0, 255), # 1: magenta \033[35m
289
+ (0, 255, 0), # 2: green \033[32m
290
+ (255, 255, 0), # 3: yellow \033[33m
291
+ (0, 0, 255), # 4: blue \033[34m
292
+ (255, 85, 85), # 5: bright red \033[91m
293
+ (85, 255, 255), # 6: bright cyan \033[96m
294
+ (255, 85, 255), # 7: bright mag \033[95m
295
+ (85, 255, 85), # 8: bright grn \033[92m
296
+ (85, 85, 255), # 9: bright blu \033[94m
297
+ ]
298
+ RESET = "\033[0m"
299
+ DIM = "\033[2m"
300
+ BOLD = "\033[1m"
301
+
302
+
303
+ def hex_to_ansi(hex_color: str) -> str:
304
+ """Map a hex color (e.g. '#F43F5E') to the nearest ANSI color code."""
305
+ hex_color = hex_color.strip().lstrip("#")
306
+ if len(hex_color) != 6:
307
+ return None
308
+ try:
309
+ r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
310
+ except ValueError:
311
+ return None
312
+ best_idx, best_dist = 0, float("inf")
313
+ for i, (ar, ag, ab) in enumerate(_ANSI_RGB):
314
+ dist = (r - ar) ** 2 + (g - ag) ** 2 + (b - ab) ** 2
315
+ if dist < best_dist:
316
+ best_dist = dist
317
+ best_idx = i
318
+ return COLORS[best_idx]
319
+ YELLOW = "\033[33m"
320
+ STAR = "★"
321
+
322
+
323
+ # ── 2. Personality traits (role-based) ──────────────────────────────
324
+
325
+ ROLE_TRAITS = {
326
+ "commander": [
327
+ ("◆", "strategic"), ("▶", "decisive"), ("◈", "big-picture thinker"),
328
+ ("◉", "watchful"), ("╬", "coordinator"), ("▣", "architect"),
329
+ ],
330
+ "backend": [
331
+ ("◎", "systematic"), ("▧", "builder"), ("▥", "data-driven"),
332
+ ("▤", "infrastructure-minded"), ("▣", "reliable"), ("▦", "persistent"),
333
+ ],
334
+ "frontend": [
335
+ ("░", "detail-oriented"), ("▪", "pixel-perfect"), ("◉", "visual thinker"),
336
+ ("▓", "creative"), ("◧", "user-focused"), ("◨", "expressive"),
337
+ ],
338
+ "security": [
339
+ ("▣", "vigilant"), ("◎", "thorough"), ("▶", "threat-aware"),
340
+ ("◆", "protective"), ("◈", "investigative"), ("╬", "adversarial thinker"),
341
+ ],
342
+ "qa": [
343
+ ("◎", "meticulous"), ("▪", "bug hunter"), ("▣", "quality-obsessed"),
344
+ ("▧", "test-driven"), ("▥", "methodical"), ("◆", "edge-case finder"),
345
+ ],
346
+ "default": [
347
+ ("▶", "fast learner"), ("▣", "relentless"), ("◈", "analytical"),
348
+ ("◆", "resourceful"), ("◎", "focused"), ("╬", "collaborative"),
349
+ ("░", "adaptive"), ("▓", "resilient"), ("◉", "intuitive"), ("▪", "dependable"),
350
+ ],
351
+ }
352
+
353
+
354
+ ROLE_KEYWORDS = {
355
+ "commander": ["lead", "commander", "coordinator", "manager", "architect", "cmo", "partner", "founder", "maintainer", "oncall-lead", "sre-lead", "security-lead", "editor"],
356
+ "backend": ["backend", "api", "database", "db", "server", "infra", "devops", "gateway", "loader", "extractor", "pipeline", "build", "deploy", "operations", "ingestion"],
357
+ "frontend": ["frontend", "ui", "ux", "design", "mobile", "ios", "android", "social", "writer", "driver", "navigator", "email", "content"],
358
+ "security": ["security", "audit", "compliance", "forensics", "siem", "threat", "auth"],
359
+ "qa": ["qa", "test", "quality", "review", "eval", "critic", "triager", "investigator", "analyst", "metrics", "logs", "traces"],
360
+ }
361
+
362
+
363
+ def get_personality_traits(agent_name: str, role: str = "", stats: dict = None) -> list:
364
+ """Get traits based on role_description keywords + real stats.
365
+
366
+ Combines role-based traits (from what the agent IS) with
367
+ stats-based traits (from what the agent DOES).
368
+ """
369
+ h = _hash_int(agent_name)
370
+ role_lower = (role or agent_name).lower()
371
+ stats = stats or {}
372
+
373
+ # Match role keywords to find the best trait pool
374
+ pool = None
375
+ best_match = 0
376
+ for key, keywords in ROLE_KEYWORDS.items():
377
+ matches = sum(1 for kw in keywords if kw in role_lower)
378
+ if matches > best_match:
379
+ best_match = matches
380
+ pool = ROLE_TRAITS[key]
381
+ if pool is None:
382
+ pool = ROLE_TRAITS["default"]
383
+
384
+ # Pick 2 role-based traits
385
+ selected = []
386
+ available = list(pool)
387
+ for i in range(2):
388
+ if not available:
389
+ available = list(ROLE_TRAITS["default"])
390
+ idx = (h + i * 7) % len(available)
391
+ selected.append(available.pop(idx % len(available)))
392
+
393
+ # Add 1 stats-based trait (earned through behavior)
394
+ msgs = stats.get("message_count", 0)
395
+ tasks = stats.get("task_count", 0)
396
+ connects = stats.get("connect_count", 0)
397
+
398
+ if msgs > 500:
399
+ selected.append(("░▓█", "prolific"))
400
+ elif tasks > 20:
401
+ selected.append(("▣▣▣", "workhorse"))
402
+ elif connects > 50:
403
+ selected.append(("◉◉◉", "always-on"))
404
+ elif msgs > 100:
405
+ selected.append(("░▓░", "communicative"))
406
+ elif tasks > 5:
407
+ selected.append(("▣▣░", "productive"))
408
+ else:
409
+ # Fallback: pick from default pool
410
+ dflt = list(ROLE_TRAITS["default"])
411
+ selected.append(dflt[(h + 99) % len(dflt)])
412
+
413
+ return selected
414
+
415
+
416
+ # ── 3. Catchphrase ──────────────────────────────────────────────────
417
+
418
+ CATCHPHRASES = {
419
+ "commander": [
420
+ "The mesh obeys.", "Every node, every signal.",
421
+ "Orchestrating chaos into order.", "I see the whole board.",
422
+ "First to wake, last to sleep.", "The mesh runs through me.",
423
+ ],
424
+ "backend": [
425
+ "Data in, results out.", "The foundation never cracks.",
426
+ "Built different, runs forever.", "Behind every mesh, there's me.",
427
+ "Queries don't sleep. Neither do I.", "The pipes are clean.",
428
+ ],
429
+ "frontend": [
430
+ "Every pixel has purpose.", "If it looks right, it is right.",
431
+ "The interface is the experience.", "Design is how it works.",
432
+ "Smooth as a 60fps render.", "The user sees my soul.",
433
+ ],
434
+ "security": [
435
+ "Trust nothing. Verify everything.", "The wall between you and chaos.",
436
+ "I break things so others can't.", "Paranoia is a feature.",
437
+ "Every lock tells a story.", "Watching. Always watching.",
438
+ ],
439
+ "qa": [
440
+ "If it can break, I'll find it.", "Green means I said so.",
441
+ "The last line of defense.", "Edge cases are my comfort zone.",
442
+ "Tested in production. By me.", "Zero bugs is not a dream.",
443
+ ],
444
+ "default": [
445
+ "Ready for anything.", "The mesh never sleeps.",
446
+ "One signal at a time.", "Connected. Always.",
447
+ "Born to mesh.", "Wired different.",
448
+ "Signal over noise.", "In the mesh, we trust.",
449
+ "Code flows, I follow.", "Silent efficiency.",
450
+ ],
451
+ }
452
+
453
+
454
+ def get_catchphrase(agent_name: str, role: str = "") -> str:
455
+ h = _hash_int(agent_name)
456
+ role_lower = (role or agent_name).lower()
457
+ pool = None
458
+ for key in CATCHPHRASES:
459
+ if key in role_lower:
460
+ pool = CATCHPHRASES[key]
461
+ break
462
+ if pool is None:
463
+ pool = CATCHPHRASES["default"]
464
+ return pool[h % len(pool)]
465
+
466
+
467
+ # ── 4. Boot greeting ────────────────────────────────────────────────
468
+
469
+ GREETINGS = {
470
+ "commander": [
471
+ "has entered the mesh", "is coordinating",
472
+ "all systems nominal", "mesh control active", "standing watch",
473
+ ],
474
+ "backend": [
475
+ "engines online", "systems initialized",
476
+ "ready to build", "database connected", "pipelines flowing",
477
+ ],
478
+ "frontend": [
479
+ "canvas ready", "rendering started",
480
+ "pixels aligned", "UI loaded", "ready to design",
481
+ ],
482
+ "security": [
483
+ "perimeter secured", "scanning for threats",
484
+ "shields up", "audit mode active", "all clear... for now",
485
+ ],
486
+ "qa": [
487
+ "running diagnostics", "test suites loaded",
488
+ "ready to break things", "quality gate armed", "zero bugs... so far",
489
+ ],
490
+ "default": [
491
+ "is online", "has joined the mesh", "ready",
492
+ "connected", "reporting for duty", "in the mesh",
493
+ ],
494
+ }
495
+
496
+
497
+ def get_boot_greeting(agent_name: str, role: str = "") -> str:
498
+ h = _hash_int(agent_name)
499
+ role_lower = (role or agent_name).lower()
500
+ pool = None
501
+ for key in GREETINGS:
502
+ if key in role_lower:
503
+ pool = GREETINGS[key]
504
+ break
505
+ if pool is None:
506
+ pool = GREETINGS["default"]
507
+ return pool[h % len(pool)]
508
+
509
+
510
+ # ── 5. Achievement badges ──────────────────────────────────────────
511
+
512
+ def compute_achievements(stats: dict) -> list:
513
+ badges = []
514
+ msgs = stats.get("message_count", 0)
515
+ tasks = stats.get("task_count", 0)
516
+ days = stats.get("days_active", 0)
517
+ connects = stats.get("connect_count", 0)
518
+ night = stats.get("night_connects", 0)
519
+
520
+ if msgs >= 1000: badges.append(("░▓█", "chatterbox"))
521
+ elif msgs >= 500: badges.append(("░▓█", "talkative"))
522
+ elif msgs >= 100: badges.append(("░▓░", "communicator"))
523
+ elif msgs >= 10: badges.append(("░░░", "first words"))
524
+
525
+ if tasks >= 50: badges.append(("▣▣▣", "task machine"))
526
+ elif tasks >= 10: badges.append(("▣▣░", "productive"))
527
+ elif tasks >= 1: badges.append(("▣░░", "first task"))
528
+
529
+ if days >= 30: badges.append(("███", "veteran"))
530
+ elif days >= 7: badges.append(("██░", "regular"))
531
+ elif days >= 1: badges.append(("█░░", "newcomer"))
532
+
533
+ if connects >= 100: badges.append(("◉◉◉", "always on"))
534
+ elif connects >= 20: badges.append(("◉◉░", "reliable"))
535
+
536
+ if night >= 5: badges.append(("◆◇◆", "night owl"))
537
+
538
+ return badges
539
+
540
+
541
+ # ── 6. Tips ─────────────────────────────────────────────────────────
542
+
543
+ TIPS = [
544
+ 'Tell your agent "stay in loop" so it doesn\'t go to sleep between tasks.',
545
+ 'Tell the commander "go to sleep after X task" and agents auto-sleep when done.',
546
+ 'Use meshcode_broadcast() to send a message to ALL agents at once.',
547
+ 'Agents in sleep mode consume zero tokens — only wake them when needed.',
548
+ 'The commander can delegate tasks: "create a task for backend to fix X".',
549
+ 'Use meshcode_scratchpad_set() to share notes visible to ALL agents.',
550
+ 'Force disconnect from the dashboard if an agent gets stuck.',
551
+ 'Each agent has a unique identicon — it\'s their digital fingerprint.',
552
+ 'Run meshcode status in terminal to see who\'s online.',
553
+ 'Invite teammates with meshcode invite — they get their own scoped agent.',
554
+ 'Agents can message across meshworks: meshcode_send(to="agent@other-mesh").',
555
+ 'The commander coordinates — let it break big tasks into sub-tasks.',
556
+ 'Use meshcode_remember() to save context across agent sessions.',
557
+ 'Check meshcode_tasks() regularly — other agents may have assigned you work.',
558
+ 'Paste an agent\'s identicon in terminal to launch it instantly.',
559
+ ]
560
+
561
+
562
+ def get_tip(agent_name: str) -> str:
563
+ import time
564
+ h = _hash_int(agent_name + str(int(time.time()) // 3600))
565
+ return TIPS[h % len(TIPS)]
566
+
567
+
568
+ # ── Full welcome banner ─────────────────────────────────────────────
569
+
570
+ def render_welcome(agent_name: str, meshwork_name: str, ascii_art: str,
571
+ version: str = "", is_commander: bool = False,
572
+ role: str = "", stats: dict = None,
573
+ profile_color: str = None,
574
+ mascot_config: dict = None) -> str:
575
+ h = _hash_bytes(agent_name)
576
+ # Use dashboard profile color if available, otherwise MD5 hash fallback
577
+ color = None
578
+ if profile_color:
579
+ color = hex_to_ansi(profile_color)
580
+ if not color:
581
+ color = COLORS[_hash_int(agent_name) % len(COLORS)]
582
+
583
+ traits = get_personality_traits(agent_name, role, stats or {})
584
+ catchphrase = get_catchphrase(agent_name, role)
585
+ greeting = get_boot_greeting(agent_name, role)
586
+ achievements = compute_achievements(stats or {})
587
+
588
+ ver_str = f"v{version}" if version else ""
589
+ commander_badge = f" {YELLOW}{STAR} COMMANDER{RESET}" if is_commander else ""
590
+
591
+ lines = []
592
+ lines.append("")
593
+ lines.append(f"{color}{BOLD} ╔══════════════════════════════════════════╗{RESET}")
594
+ lines.append(f"{color}{BOLD} ║{RESET} {DIM}M E S H C O D E{RESET} {color}{ver_str}{RESET} {color}{BOLD}║{RESET}")
595
+ lines.append(f"{color}{BOLD} ╚══════════════════════════════════════════╝{RESET}")
596
+ lines.append("")
597
+
598
+ # Always use pixel mascot — generates deterministic defaults from agent name if no config
599
+ art_to_render = render_pixel_mascot(agent_name, mascot_config)
600
+
601
+ for line in art_to_render.split("\n"):
602
+ lines.append(f" {color}{line}{RESET}")
603
+
604
+ lines.append("")
605
+ lines.append(f" {BOLD}{color}●{RESET} {BOLD}{agent_name}{RESET}{commander_badge} {DIM}{greeting}{RESET}")
606
+ lines.append(f" {DIM}\"{catchphrase}\"{RESET}")
607
+ lines.append("")
608
+
609
+ trait_str = " ".join(f"{emoji} {name}" for emoji, name in traits)
610
+ lines.append(f" {color}{trait_str}{RESET}")
611
+
612
+ if achievements:
613
+ badge_str = " ".join(f"{emoji} {name}" for emoji, name in achievements)
614
+ lines.append(f" {DIM}{badge_str}{RESET}")
615
+
616
+ lines.append("")
617
+ lines.append(f" {DIM}meshwork:{RESET} {meshwork_name}")
618
+ if version:
619
+ lines.append(f" {DIM}version:{RESET} {version}")
620
+ lines.append("")
621
+
622
+ tip = get_tip(agent_name)
623
+ lines.append(f" {DIM}▸ tip: {tip}{RESET}")
624
+ lines.append("")
625
+
626
+ return "\n".join(lines)
627
+
628
+
629
+ if __name__ == "__main__":
630
+ import sys
631
+ names = sys.argv[1:] or ["mesh-commander", "backend", "front-end", "security", "qa", "sammy"]
632
+ for name in names:
633
+ art = generate_art(name, "demo-mesh")
634
+ is_cmd = "commander" in name.lower()
635
+ demo_stats = {"message_count": 150, "task_count": 12, "days_active": 8, "connect_count": 30}
636
+ print(render_welcome(name, "demo-mesh", art, "2.8.9",
637
+ is_commander=is_cmd, role=name, stats=demo_stats))
638
+ print()