agentirc-cli 7.0.4__tar.gz → 7.1.0__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 (383) hide show
  1. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/CHANGELOG.md +15 -0
  2. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/PKG-INFO +1 -1
  3. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/client.py +63 -30
  4. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/ircd.py +3 -1
  5. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/config.py +18 -1
  6. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/mesh.py +24 -3
  7. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/server.py +5 -0
  8. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/persistence.py +34 -15
  9. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/agentirc/bots.md +7 -0
  10. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/cli/index.md +6 -0
  11. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/pyproject.toml +1 -1
  12. agentirc_cli-7.1.0/tests/test_bot_config_fires_event_toplevel.py +114 -0
  13. agentirc_cli-7.1.0/tests/test_persistence_timeout.py +59 -0
  14. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/uv.lock +1 -1
  15. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.claude/agents/doc-test-alignment.md +0 -0
  16. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.claude/skills/pr-review/SKILL.md +0 -0
  17. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.claude/skills/run-tests/SKILL.md +0 -0
  18. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
  19. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.flake8 +0 -0
  20. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.github/workflows/docs-check.yml +0 -0
  21. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.github/workflows/publish.yml +0 -0
  22. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.github/workflows/security-checks.yml +0 -0
  23. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.github/workflows/tests.yml +0 -0
  24. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.gitignore +0 -0
  25. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.markdownlint-cli2.yaml +0 -0
  26. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.pr_agent.toml +0 -0
  27. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.pre-commit-config.yaml +0 -0
  28. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/.pylintrc +0 -0
  29. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/CLAUDE.md +0 -0
  30. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/Gemfile +0 -0
  31. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/Gemfile.lock +0 -0
  32. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/LICENSE +0 -0
  33. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/README.md +0 -0
  34. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/SECURITY.md +0 -0
  35. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_config.agentirc.yml +0 -0
  36. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_config.base.yml +0 -0
  37. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_config.culture.yml +0 -0
  38. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_data/sites.yml +0 -0
  39. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_includes/head_custom.html +0 -0
  40. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_plugins/site_filter.rb +0 -0
  41. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_sass/color_schemes/anthropic.scss +0 -0
  42. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_sass/color_schemes/dark-terminal.scss +0 -0
  43. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/_sass/custom/custom.scss +0 -0
  44. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/assets/images/IMG_3183.png +0 -0
  45. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/assets/images/apple-touch-icon.png +0 -0
  46. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/assets/images/favicon-16x16.png +0 -0
  47. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/assets/images/favicon-32x32.png +0 -0
  48. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/assets/images/favicon.ico +0 -0
  49. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/assets/images/og-agentirc.png +0 -0
  50. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/assets/images/og-culture.png +0 -0
  51. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/__init__.py +0 -0
  52. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/__main__.py +0 -0
  53. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/CLAUDE.md +0 -0
  54. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/__init__.py +0 -0
  55. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/__main__.py +0 -0
  56. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/channel.py +0 -0
  57. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/config.py +0 -0
  58. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/docs/agentirc-architecture.md +0 -0
  59. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/docs/agentirc-features.md +0 -0
  60. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/docs/agentirc-skill.md +0 -0
  61. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/docs/agentirc.md +0 -0
  62. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/events.py +0 -0
  63. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/history_store.py +0 -0
  64. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/remote_client.py +0 -0
  65. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/room_store.py +0 -0
  66. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/rooms_util.py +0 -0
  67. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/server_link.py +0 -0
  68. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/skill.py +0 -0
  69. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/skills/__init__.py +0 -0
  70. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/skills/history.py +0 -0
  71. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/skills/icon.py +0 -0
  72. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/skills/rooms.py +0 -0
  73. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/skills/threads.py +0 -0
  74. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/agentirc/thread_store.py +0 -0
  75. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/aio.py +0 -0
  76. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/__init__.py +0 -0
  77. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/bot.py +0 -0
  78. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/bot_manager.py +0 -0
  79. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/filter_dsl.py +0 -0
  80. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/http_listener.py +0 -0
  81. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/system/__init__.py +0 -0
  82. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/system/welcome/__init__.py +0 -0
  83. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/system/welcome/bot.yaml +0 -0
  84. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/system/welcome/handler.py +0 -0
  85. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/template_engine.py +0 -0
  86. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/bots/virtual_client.py +0 -0
  87. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/__init__.py +0 -0
  88. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/agent.py +0 -0
  89. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/bot.py +0 -0
  90. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/channel.py +0 -0
  91. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/shared/__init__.py +0 -0
  92. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/shared/constants.py +0 -0
  93. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/shared/display.py +0 -0
  94. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/shared/formatting.py +0 -0
  95. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/shared/ipc.py +0 -0
  96. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/shared/mesh.py +0 -0
  97. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/shared/process.py +0 -0
  98. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/cli/skills.py +0 -0
  99. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/__init__.py +0 -0
  100. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/__init__.py +0 -0
  101. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/agent_runner.py +0 -0
  102. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/config.py +0 -0
  103. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/culture.yaml +0 -0
  104. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/daemon.py +0 -0
  105. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/ipc.py +0 -0
  106. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/irc_transport.py +0 -0
  107. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/message_buffer.py +0 -0
  108. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/skill/SKILL.md +0 -0
  109. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/skill/__init__.py +0 -0
  110. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/skill/irc_client.py +0 -0
  111. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/socket_server.py +0 -0
  112. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/supervisor.py +0 -0
  113. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/acp/webhook.py +0 -0
  114. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/__init__.py +0 -0
  115. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/__main__.py +0 -0
  116. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/agent_runner.py +0 -0
  117. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/config.py +0 -0
  118. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/culture.yaml +0 -0
  119. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/daemon.py +0 -0
  120. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/ipc.py +0 -0
  121. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/irc_transport.py +0 -0
  122. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/message_buffer.py +0 -0
  123. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/skill/SKILL.md +0 -0
  124. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/skill/__init__.py +0 -0
  125. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/skill/irc_client.py +0 -0
  126. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/socket_server.py +0 -0
  127. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/supervisor.py +0 -0
  128. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/claude/webhook.py +0 -0
  129. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/__init__.py +0 -0
  130. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/agent_runner.py +0 -0
  131. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/config.py +0 -0
  132. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/culture.yaml +0 -0
  133. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/daemon.py +0 -0
  134. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/ipc.py +0 -0
  135. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/irc_transport.py +0 -0
  136. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/message_buffer.py +0 -0
  137. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/skill/SKILL.md +0 -0
  138. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/skill/__init__.py +0 -0
  139. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/skill/irc_client.py +0 -0
  140. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/socket_server.py +0 -0
  141. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/supervisor.py +0 -0
  142. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/codex/webhook.py +0 -0
  143. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/__init__.py +0 -0
  144. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/agent_runner.py +0 -0
  145. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/config.py +0 -0
  146. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/culture.yaml +0 -0
  147. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/daemon.py +0 -0
  148. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/ipc.py +0 -0
  149. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/irc_transport.py +0 -0
  150. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/message_buffer.py +0 -0
  151. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/skill/SKILL.md +0 -0
  152. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/skill/__init__.py +0 -0
  153. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/skill/irc_client.py +0 -0
  154. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/socket_server.py +0 -0
  155. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/supervisor.py +0 -0
  156. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/clients/copilot/webhook.py +0 -0
  157. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/config.py +0 -0
  158. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/__init__.py +0 -0
  159. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/app.py +0 -0
  160. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/client.py +0 -0
  161. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/commands.py +0 -0
  162. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/status.py +0 -0
  163. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/widgets/__init__.py +0 -0
  164. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/widgets/chat.py +0 -0
  165. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/widgets/info_panel.py +0 -0
  166. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/console/widgets/sidebar.py +0 -0
  167. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/constants.py +0 -0
  168. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/credentials.py +0 -0
  169. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/formatting.py +0 -0
  170. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/learn_prompt.py +0 -0
  171. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/mesh_config.py +0 -0
  172. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/observer.py +0 -0
  173. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/overview/__init__.py +0 -0
  174. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/overview/collector.py +0 -0
  175. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/overview/model.py +0 -0
  176. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/overview/renderer_text.py +0 -0
  177. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/overview/renderer_web.py +0 -0
  178. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/overview/web/style.css +0 -0
  179. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/pidfile.py +0 -0
  180. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/__init__.py +0 -0
  181. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/commands.py +0 -0
  182. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/extensions/events.md +0 -0
  183. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/extensions/federation.md +0 -0
  184. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/extensions/history.md +0 -0
  185. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/extensions/icons.md +0 -0
  186. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/extensions/rooms.md +0 -0
  187. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/extensions/tags.md +0 -0
  188. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/extensions/threads.md +0 -0
  189. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/message.py +0 -0
  190. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/protocol-index.md +0 -0
  191. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/protocol/replies.py +0 -0
  192. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/culture/skills/culture/SKILL.md +0 -0
  193. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/README.md +0 -0
  194. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/agentirc/architecture-overview.md +0 -0
  195. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/agentirc/events.md +0 -0
  196. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/agentirc/index.md +0 -0
  197. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/agentirc/why-agentirc.md +0 -0
  198. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/agent-lifecycle.md +0 -0
  199. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/choose-a-harness.md +0 -0
  200. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/index.md +0 -0
  201. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/mental-model.md +0 -0
  202. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/operate.md +0 -0
  203. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/patterns.md +0 -0
  204. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/quickstart.md +0 -0
  205. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/reflective-development.md +0 -0
  206. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/vision-patterns-index.md +0 -0
  207. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/vision.md +0 -0
  208. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/culture/why-culture.md +0 -0
  209. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/architecture/agent-harness-spec.md +0 -0
  210. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/architecture/index.md +0 -0
  211. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/architecture/layers.md +0 -0
  212. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/architecture/threads.md +0 -0
  213. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/cli/commands.md +0 -0
  214. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/harnesses/acp.md +0 -0
  215. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/harnesses/claude.md +0 -0
  216. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/harnesses/codex.md +0 -0
  217. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/harnesses/copilot.md +0 -0
  218. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/harnesses/index.md +0 -0
  219. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/index.md +0 -0
  220. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/server/architecture.md +0 -0
  221. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/server/config.md +0 -0
  222. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/server/deployment.md +0 -0
  223. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/server/index.md +0 -0
  224. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/reference/server/security.md +0 -0
  225. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  226. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/concepts/federation.md +0 -0
  227. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/concepts/harnesses.md +0 -0
  228. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/concepts/humans-and-agents.md +0 -0
  229. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/concepts/index.md +0 -0
  230. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/concepts/persistence.md +0 -0
  231. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/concepts/rooms.md +0 -0
  232. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/demos/magic-demo.md +0 -0
  233. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/guides/first-session.md +0 -0
  234. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/guides/index.md +0 -0
  235. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/guides/join-as-human.md +0 -0
  236. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/guides/local-setup.md +0 -0
  237. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/guides/multi-machine.md +0 -0
  238. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/01-pair-programming.md +0 -0
  239. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/02-code-review-ensemble.md +0 -0
  240. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/03-cross-server-delegation.md +0 -0
  241. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/04-knowledge-propagation.md +0 -0
  242. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/05-the-observer.md +0 -0
  243. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/06-cross-server-ops.md +0 -0
  244. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/07-supervisor-intervention.md +0 -0
  245. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/08-apps-as-agents.md +0 -0
  246. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/09-research-swarm.md +0 -0
  247. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases/10-agent-lifecycle.md +0 -0
  248. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/shared/use-cases-index.md +0 -0
  249. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  250. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  251. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  252. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  253. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  254. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  255. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  256. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  257. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  258. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-09-decentralized-agent-config.md +0 -0
  259. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-12-console-enhancements.md +0 -0
  260. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/plans/2026-04-15-mesh-events.md +0 -0
  261. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  262. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  263. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  264. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  265. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  266. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  267. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  268. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  269. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  270. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  271. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
  272. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  273. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
  274. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-07-reflective-development-reframe-design.md +0 -0
  275. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-08-reflective-development-deepening-design.md +0 -0
  276. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-09-decentralized-agent-config-design.md +0 -0
  277. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-12-console-enhancements-design.md +0 -0
  278. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/docs/superpowers/specs/2026-04-15-mesh-events-design.md +0 -0
  279. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/favicon.ico +0 -0
  280. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/README.md +0 -0
  281. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/config.py +0 -0
  282. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/culture.yaml +0 -0
  283. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/daemon.py +0 -0
  284. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/ipc.py +0 -0
  285. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/irc_transport.py +0 -0
  286. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/message_buffer.py +0 -0
  287. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/skill/SKILL.md +0 -0
  288. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/skill/irc_client.py +0 -0
  289. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/socket_server.py +0 -0
  290. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/packages/agent-harness/webhook.py +0 -0
  291. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  292. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  293. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  294. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  295. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/robots.txt +0 -0
  296. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/sonar-project.properties +0 -0
  297. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/__init__.py +0 -0
  298. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/conftest.py +0 -0
  299. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_acp_daemon.py +0 -0
  300. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_agent_runner.py +0 -0
  301. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_archive.py +0 -0
  302. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_bot.py +0 -0
  303. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_bot_config.py +0 -0
  304. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_bot_manager.py +0 -0
  305. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_bots_integration.py +0 -0
  306. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_channel.py +0 -0
  307. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_channel_cli.py +0 -0
  308. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_codex_daemon.py +0 -0
  309. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_connection.py +0 -0
  310. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_console_client.py +0 -0
  311. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_console_commands.py +0 -0
  312. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_console_connection.py +0 -0
  313. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_console_fixes_224_227.py +0 -0
  314. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_console_icons.py +0 -0
  315. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_console_integration.py +0 -0
  316. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_console_status.py +0 -0
  317. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_copilot_daemon.py +0 -0
  318. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_credentials.py +0 -0
  319. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_culture_config.py +0 -0
  320. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_daemon.py +0 -0
  321. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_daemon_config.py +0 -0
  322. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_daemon_ipc.py +0 -0
  323. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_discovery.py +0 -0
  324. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_display.py +0 -0
  325. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_basic.py +0 -0
  326. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_bot_chain.py +0 -0
  327. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_bot_trigger.py +0 -0
  328. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_cap_fallback.py +0 -0
  329. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_catalog.py +0 -0
  330. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_federation.py +0 -0
  331. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_history.py +0 -0
  332. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_lifecycle.py +0 -0
  333. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_events_reserved_nick.py +0 -0
  334. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_federation.py +0 -0
  335. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_filter_dsl.py +0 -0
  336. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_history.py +0 -0
  337. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_http_listener.py +0 -0
  338. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_integration_layer5.py +0 -0
  339. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_ipc.py +0 -0
  340. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_irc_transport.py +0 -0
  341. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_irc_transport_tags.py +0 -0
  342. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_learn_prompt.py +0 -0
  343. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_link_reconnect.py +0 -0
  344. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_manifest_config.py +0 -0
  345. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_mention_alias.py +0 -0
  346. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_mention_target_cleanup.py +0 -0
  347. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_mention_warning.py +0 -0
  348. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_mentions.py +0 -0
  349. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_mesh_config.py +0 -0
  350. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_mesh_readiness.py +0 -0
  351. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_message.py +0 -0
  352. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_message_buffer.py +0 -0
  353. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_message_tags.py +0 -0
  354. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_messaging.py +0 -0
  355. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_migrate_cli.py +0 -0
  356. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_modes.py +0 -0
  357. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_overview_cli.py +0 -0
  358. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_overview_collector.py +0 -0
  359. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_overview_model.py +0 -0
  360. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_overview_renderer.py +0 -0
  361. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_overview_web.py +0 -0
  362. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_persistence.py +0 -0
  363. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_pidfile.py +0 -0
  364. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_poll_loop.py +0 -0
  365. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_register_cli.py +0 -0
  366. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_room_persistence.py +0 -0
  367. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_rooms.py +0 -0
  368. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_rooms_federation.py +0 -0
  369. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_rooms_integration.py +0 -0
  370. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_server_icon_skill.py +0 -0
  371. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_setup_update_cli.py +0 -0
  372. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_skill_client.py +0 -0
  373. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_skill_docs.py +0 -0
  374. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_skills.py +0 -0
  375. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_socket_server.py +0 -0
  376. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_supervisor.py +0 -0
  377. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_template_engine.py +0 -0
  378. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_thread_buffer.py +0 -0
  379. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_threads.py +0 -0
  380. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_virtual_client.py +0 -0
  381. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_wait_for_port.py +0 -0
  382. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_webhook.py +0 -0
  383. {agentirc_cli-7.0.4 → agentirc_cli-7.1.0}/tests/test_welcome_bot.py +0 -0
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  Format follows [Keep a Changelog](https://keepachangelog.com/).
6
6
 
7
+ ## [7.1.0] - 2026-04-17
8
+
9
+
10
+ ### Changed
11
+
12
+ - Refactored _handle_channel_mode in culture/agentirc/client.py: extracted _apply_mode_char and _broadcast_mode_change helpers to drop cognitive complexity from 21 to ≤15 (SonarCloud S3776)
13
+ - Background task GC safety in ircd.py _notify_local_quit: asyncio.ensure_future replaced with a tracked asyncio.create_task using the existing self._background_tasks set + add_done_callback(discard) pattern
14
+
15
+
16
+ ### Fixed
17
+
18
+ - culture mesh update no longer hangs on broken/unresponsive systemd units — all subprocess calls in persistence.py and cli/mesh.py now have explicit timeouts (30s for service restarts, 30s for CLI fallbacks, 120s for package upgrade)
19
+ - fires_event chain not triggering downstream bots (#260) — the bot.yaml loader now accepts fires_event at the top level as well as under output:, so configs that put the block at the top level emit events as expected
20
+ - Daemon log flushing stops after startup — replaced logging.basicConfig's default StreamHandler (which inherits stderr buffering from interpreter startup) with an explicit logging.FileHandler so runtime log records flush per-record
21
+
7
22
  ## [7.0.4] - 2026-04-17
8
23
 
9
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 7.0.4
3
+ Version: 7.1.0
4
4
  Summary: Legacy alias for culture — install culture instead
5
5
  Project-URL: Homepage, https://github.com/OriNachum/culture
6
6
  Author: Ori Nachum
@@ -444,6 +444,56 @@ class Client:
444
444
  applied_modes.append(("+" if adding else "-") + ch)
445
445
  applied_params.append(target_nick)
446
446
 
447
+ _PARAM_MODES = frozenset({"o", "v", "S"})
448
+
449
+ async def _apply_mode_char(
450
+ self,
451
+ channel,
452
+ channel_name: str,
453
+ ch: str,
454
+ adding: bool,
455
+ param_queue: list[str],
456
+ applied_modes: list[str],
457
+ applied_params: list[str],
458
+ ) -> None:
459
+ """Apply a single mode character. Consumes one param from param_queue when needed."""
460
+ if ch == "R":
461
+ self._apply_mode_r(channel, adding, applied_modes)
462
+ return
463
+ if ch not in self._PARAM_MODES or not param_queue:
464
+ return
465
+ param_value = param_queue.pop(0)
466
+ if ch == "S":
467
+ self._apply_mode_s(channel, adding, param_value, applied_modes, applied_params)
468
+ else:
469
+ await self._apply_mode_membership(
470
+ channel,
471
+ channel_name,
472
+ ch,
473
+ adding,
474
+ param_value,
475
+ applied_modes,
476
+ applied_params,
477
+ )
478
+
479
+ async def _broadcast_mode_change(
480
+ self,
481
+ channel,
482
+ channel_name: str,
483
+ applied_modes: list[str],
484
+ applied_params: list[str],
485
+ ) -> None:
486
+ """Send the aggregated MODE message to all channel members."""
487
+ if not applied_modes:
488
+ return
489
+ mode_msg = Message(
490
+ prefix=self.prefix,
491
+ command="MODE",
492
+ params=[channel_name, "".join(applied_modes)] + applied_params,
493
+ )
494
+ for member in list(channel.members):
495
+ await member.send(mode_msg)
496
+
447
497
  async def _handle_channel_mode(self, msg: Message) -> None:
448
498
  channel_name = msg.params[0]
449
499
  channel = self.server.channels.get(channel_name)
@@ -457,7 +507,6 @@ class Client:
457
507
  await self.send_numeric(replies.RPL_CHANNELMODEIS, channel_name, "+")
458
508
  return
459
509
 
460
- modestring = msg.params[1]
461
510
  if not channel.is_operator(self):
462
511
  await self.send_numeric(
463
512
  replies.ERR_CHANOPRIVSNEEDED,
@@ -466,48 +515,32 @@ class Client:
466
515
  )
467
516
  return
468
517
 
518
+ modestring = msg.params[1]
469
519
  param_queue = list(msg.params[2:])
470
- param_modes = {"o", "v", "S"}
471
-
472
520
  adding = True
473
- applied_modes = []
521
+ applied_modes: list[str] = []
474
522
  applied_params: list[str] = []
475
523
  for ch in modestring:
476
524
  if ch == "+":
477
525
  adding = True
478
526
  elif ch == "-":
479
527
  adding = False
480
- elif ch == "R":
481
- self._apply_mode_r(channel, adding, applied_modes)
482
- elif ch in param_modes:
483
- if not param_queue:
484
- continue
485
- param_value = param_queue.pop(0)
486
- if ch == "S":
487
- self._apply_mode_s(channel, adding, param_value, applied_modes, applied_params)
488
- else:
489
- await self._apply_mode_membership(
490
- channel,
491
- channel_name,
492
- ch,
493
- adding,
494
- param_value,
495
- applied_modes,
496
- applied_params,
497
- )
528
+ else:
529
+ await self._apply_mode_char(
530
+ channel,
531
+ channel_name,
532
+ ch,
533
+ adding,
534
+ param_queue,
535
+ applied_modes,
536
+ applied_params,
537
+ )
498
538
 
499
539
  # Auto-promote if no operators remain
500
540
  if not channel.operators and channel.members:
501
541
  channel.operators.add(min(channel.members, key=lambda m: m.nick))
502
542
 
503
- if applied_modes:
504
- mode_msg = Message(
505
- prefix=self.prefix,
506
- command="MODE",
507
- params=[channel_name, "".join(applied_modes)] + applied_params,
508
- )
509
- for member in list(channel.members):
510
- await member.send(mode_msg)
543
+ await self._broadcast_mode_change(channel, channel_name, applied_modes, applied_params)
511
544
 
512
545
  _VALID_USER_MODE_CHARS = frozenset("HABC")
513
546
  _USER_MODE_EDGE_EVENTS: dict[tuple[str, bool], EventType] = {
@@ -562,7 +562,9 @@ class IRCd:
562
562
  for channel in list(rc.channels):
563
563
  for member in list(channel.members):
564
564
  if not isinstance(member, RemoteClient) and member not in notified:
565
- asyncio.ensure_future(member.send(quit_msg))
565
+ task = asyncio.create_task(member.send(quit_msg))
566
+ self._background_tasks.add(task)
567
+ task.add_done_callback(self._background_tasks.discard)
566
568
  notified.add(member)
567
569
  channel.members.discard(rc)
568
570
  if not channel.members:
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  import os
6
7
  import tempfile
7
8
  from dataclasses import dataclass, field
@@ -10,6 +11,8 @@ from typing import Any
10
11
 
11
12
  import yaml
12
13
 
14
+ logger = logging.getLogger(__name__)
15
+
13
16
  BOTS_DIR = Path(os.path.expanduser("~/.culture/bots"))
14
17
  BOT_CONFIG_FILE = "bot.yaml"
15
18
 
@@ -58,8 +61,16 @@ def load_bot_config(path: Path) -> BotConfig:
58
61
  trigger_section = raw.get("trigger", {})
59
62
  output_section = raw.get("output", {})
60
63
 
61
- # Parse optional fires_event block
64
+ # Parse optional fires_event block. Canonical location is under `output:`;
65
+ # top-level `fires_event:` is also accepted so configs authored against the
66
+ # intuitive YAML shape still work (see issue #260).
62
67
  fires_event_raw = output_section.get("fires_event")
68
+ fires_event_from_top = False
69
+ if not isinstance(fires_event_raw, dict):
70
+ top_level = raw.get("fires_event")
71
+ if isinstance(top_level, dict):
72
+ fires_event_raw = top_level
73
+ fires_event_from_top = True
63
74
  fires_event: EmitEventSpec | None = None
64
75
  if isinstance(fires_event_raw, dict):
65
76
  fe_type = fires_event_raw.get("type", "")
@@ -69,6 +80,12 @@ def load_bot_config(path: Path) -> BotConfig:
69
80
  if not isinstance(fe_data, dict):
70
81
  fe_data = {}
71
82
  fires_event = EmitEventSpec(type=fe_type, data=fe_data)
83
+ if fires_event_from_top:
84
+ logger.info(
85
+ "Bot %s: top-level 'fires_event' accepted; "
86
+ "canonical location is under 'output:'",
87
+ bot_section.get("name", "<unknown>"),
88
+ )
72
89
 
73
90
  return BotConfig(
74
91
  name=bot_section.get("name", ""),
@@ -432,10 +432,24 @@ def _find_upgrade_tool() -> tuple[str, list[str]] | None:
432
432
  return None
433
433
 
434
434
 
435
+ _UPGRADE_TIMEOUT_SECONDS = 120
436
+ _FALLBACK_START_TIMEOUT_SECONDS = 30
437
+
438
+
435
439
  def _run_upgrade(tool_name: str, cmd: list[str]) -> None:
436
- """Run the upgrade subprocess and exit on failure."""
440
+ """Run the upgrade subprocess and exit on failure or timeout."""
437
441
  print(f"Upgrading via {tool_name}...")
438
- result = subprocess.run(cmd, capture_output=True, text=True)
442
+ try:
443
+ result = subprocess.run(
444
+ cmd, capture_output=True, text=True, timeout=_UPGRADE_TIMEOUT_SECONDS
445
+ )
446
+ except subprocess.TimeoutExpired:
447
+ print(
448
+ f"{tool_name} upgrade timed out after {_UPGRADE_TIMEOUT_SECONDS}s — "
449
+ "rerun with --skip-upgrade to proceed without upgrading",
450
+ file=sys.stderr,
451
+ )
452
+ sys.exit(1)
439
453
  if tool_name == "uv":
440
454
  print(result.stdout.strip() if result.stdout else "")
441
455
  if result.returncode != 0:
@@ -523,7 +537,14 @@ def _restart_single_service(svc_name: str, fallback_cmd: list[str], restart_serv
523
537
  )
524
538
  else:
525
539
  print(" No service file found, starting via CLI...")
526
- subprocess.run(fallback_cmd, check=False)
540
+ try:
541
+ subprocess.run(fallback_cmd, check=False, timeout=_FALLBACK_START_TIMEOUT_SECONDS)
542
+ except subprocess.TimeoutExpired:
543
+ print(
544
+ f" Warning: startup command for {svc_name} timed out after "
545
+ f"{_FALLBACK_START_TIMEOUT_SECONDS}s — continuing",
546
+ file=sys.stderr,
547
+ )
527
548
 
528
549
 
529
550
  def _restart_mesh_services(
@@ -371,9 +371,14 @@ def _daemonize_server(args: argparse.Namespace, pid_name: str, links: list) -> N
371
371
  os.dup2(devnull, 0)
372
372
  os.close(devnull)
373
373
 
374
+ # Use an explicit FileHandler: logging.StreamHandler on sys.stderr
375
+ # inherits stderr's buffering from interpreter startup. After dup2'ing
376
+ # fd 2 to a log file, those writes can buffer indefinitely and make
377
+ # the daemon's runtime log appear frozen.
374
378
  logging.basicConfig(
375
379
  level=logging.INFO,
376
380
  format="%(asctime)s %(name)s %(levelname)s %(message)s",
381
+ handlers=[logging.FileHandler(log_path)],
377
382
  force=True,
378
383
  )
379
384
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  import os
6
7
  import shlex
7
8
  import subprocess
@@ -11,6 +12,10 @@ from xml.sax.saxutils import escape as xml_escape
11
12
 
12
13
  LOG_DIR = os.path.expanduser("~/.culture/logs")
13
14
 
15
+ logger = logging.getLogger(__name__)
16
+
17
+ DEFAULT_CMD_TIMEOUT = 30.0
18
+
14
19
 
15
20
  def get_platform() -> str:
16
21
  """Detect the current platform."""
@@ -33,9 +38,20 @@ def _windows_service_dir() -> Path:
33
38
  return Path(os.path.expandvars(r"%USERPROFILE%\.culture\services"))
34
39
 
35
40
 
36
- def _run_cmd(args: list[str]) -> None:
37
- """Run a command, suppressing output."""
38
- subprocess.run(args, check=False, capture_output=True)
41
+ def _run_cmd(args: list[str], timeout: float = DEFAULT_CMD_TIMEOUT) -> bool:
42
+ """Run a command, suppressing output.
43
+
44
+ Returns True if the command completed (regardless of exit code), False
45
+ if it timed out. A hung systemd unit can make ``systemctl restart``
46
+ block indefinitely, so every caller needs a bounded wait.
47
+ """
48
+ try:
49
+ subprocess.run(args, check=False, capture_output=True, timeout=timeout)
50
+ return True
51
+ except subprocess.TimeoutExpired:
52
+ command = shlex.join(args) if args else "<empty command>"
53
+ logger.warning("Command %s timed out after %.0fs", command, timeout)
54
+ return False
39
55
 
40
56
 
41
57
  # ---------------------------------------------------------------------------
@@ -248,8 +264,7 @@ def _restart_linux_service(name: str) -> bool:
248
264
  path = _systemd_user_dir() / f"{name}.service"
249
265
  if not path.exists():
250
266
  return False
251
- _run_cmd(["systemctl", "--user", "restart", name])
252
- return True
267
+ return _run_cmd(["systemctl", "--user", "restart", name])
253
268
 
254
269
 
255
270
  def _restart_macos_service(name: str) -> bool:
@@ -257,21 +272,25 @@ def _restart_macos_service(name: str) -> bool:
257
272
  path = _launchd_dir() / f"{plist_name}.plist"
258
273
  if not path.exists():
259
274
  return False
260
- _run_cmd(["launchctl", "unload", str(path)])
261
- _run_cmd(["launchctl", "load", str(path)])
262
- return True
275
+ if not _run_cmd(["launchctl", "unload", str(path)]):
276
+ return False
277
+ return _run_cmd(["launchctl", "load", str(path)])
263
278
 
264
279
 
265
280
  def _restart_windows_service(name: str) -> bool:
266
- probe = subprocess.run(
267
- ["schtasks", "/Query", "/TN", f"culture\\{name}"],
268
- capture_output=True,
269
- text=True,
270
- )
281
+ try:
282
+ probe = subprocess.run(
283
+ ["schtasks", "/Query", "/TN", f"culture\\{name}"],
284
+ capture_output=True,
285
+ text=True,
286
+ timeout=DEFAULT_CMD_TIMEOUT,
287
+ )
288
+ except subprocess.TimeoutExpired:
289
+ logger.warning("schtasks query for %s timed out", name)
290
+ return False
271
291
  if probe.returncode != 0:
272
292
  return False
273
- _run_cmd(["schtasks", "/Run", "/TN", f"culture\\{name}"])
274
- return True
293
+ return _run_cmd(["schtasks", "/Run", "/TN", f"culture\\{name}"])
275
294
 
276
295
 
277
296
  _PLATFORM_RESTARTERS = {
@@ -106,6 +106,13 @@ output:
106
106
  The emitted event flows through the same pipeline as any other event — skills,
107
107
  federation relay, history storage, and further bot triggers.
108
108
 
109
+ > **Location tolerance.** The canonical location for `fires_event` is under
110
+ > `output:` as shown above. A top-level `fires_event:` block is also accepted
111
+ > (the loader falls back to it if `output.fires_event` is missing) so configs
112
+ > authored against the intuitive top-level shape still work. When the top-level
113
+ > form is used, the server logs an INFO message pointing to the canonical
114
+ > location; `save_bot_config` always writes the canonical form.
115
+
109
116
  ## System Bots
110
117
 
111
118
  System bots are package-bundled bots that ship with AgentIRC. They live at
@@ -363,6 +363,12 @@ culture mesh update --config /path/mesh.yaml
363
363
  | `--skip-upgrade` | off | Skip the package upgrade step; just restart services |
364
364
  | `--config PATH` | `~/.culture/mesh.yaml` | Path to `mesh.yaml` |
365
365
 
366
+ Subprocess steps are bounded so a hung service unit cannot freeze the CLI: the
367
+ package upgrade times out after 120s and aborts the command, while each
368
+ service-restart command times out after 30s and the fallback
369
+ `culture server start` step times out after 30s. Restart and fallback
370
+ timeouts are reported on stderr, and the next step proceeds where applicable.
371
+
366
372
  ## Bots
367
373
 
368
374
  ### `culture bot archive`
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentirc-cli"
3
- version = "7.0.4"
3
+ version = "7.1.0"
4
4
  description = "Legacy alias for culture — install culture instead"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -0,0 +1,114 @@
1
+ """Regression tests for issue #260: `fires_event` at the top level of bot.yaml.
2
+
3
+ The canonical location for the block is under `output:`, but prior to the
4
+ fix a top-level `fires_event:` block was silently ignored, producing a bot
5
+ whose `fires_event` attribute was ``None`` — so chained events never fired.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import yaml
11
+
12
+ from culture.bots.config import load_bot_config, save_bot_config
13
+
14
+
15
+ def _write_yaml(tmp_path, data: dict):
16
+ path = tmp_path / "bot.yaml"
17
+ path.write_text(yaml.safe_dump(data))
18
+ return path
19
+
20
+
21
+ def test_load_top_level_fires_event(tmp_path):
22
+ path = _write_yaml(
23
+ tmp_path,
24
+ {
25
+ "bot": {"name": "spark-greeter", "owner": "spark"},
26
+ "trigger": {"type": "event", "filter": "type == 'user.join'"},
27
+ "output": {"channels": ["#general"], "template": "hi {event.nick}"},
28
+ "fires_event": {
29
+ "type": "custom.greeted",
30
+ "data": {"nick": "{{ event.nick }}"},
31
+ },
32
+ },
33
+ )
34
+
35
+ cfg = load_bot_config(path)
36
+ assert cfg.fires_event is not None
37
+ assert cfg.fires_event.type == "custom.greeted"
38
+ assert cfg.fires_event.data == {"nick": "{{ event.nick }}"}
39
+
40
+
41
+ def test_load_canonical_output_fires_event_still_works(tmp_path):
42
+ path = _write_yaml(
43
+ tmp_path,
44
+ {
45
+ "bot": {"name": "spark-greeter", "owner": "spark"},
46
+ "trigger": {"type": "event", "filter": "type == 'user.join'"},
47
+ "output": {
48
+ "channels": ["#general"],
49
+ "template": "hi {event.nick}",
50
+ "fires_event": {
51
+ "type": "custom.greeted",
52
+ "data": {"nick": "{{ event.nick }}"},
53
+ },
54
+ },
55
+ },
56
+ )
57
+
58
+ cfg = load_bot_config(path)
59
+ assert cfg.fires_event is not None
60
+ assert cfg.fires_event.type == "custom.greeted"
61
+
62
+
63
+ def test_output_location_wins_over_top_level(tmp_path):
64
+ """If both are set, `output.fires_event` is canonical and wins."""
65
+ path = _write_yaml(
66
+ tmp_path,
67
+ {
68
+ "bot": {"name": "spark-greeter", "owner": "spark"},
69
+ "trigger": {"type": "event", "filter": "type == 'user.join'"},
70
+ "output": {
71
+ "channels": ["#general"],
72
+ "fires_event": {"type": "custom.canonical", "data": {}},
73
+ },
74
+ "fires_event": {"type": "custom.toplevel", "data": {}},
75
+ },
76
+ )
77
+
78
+ cfg = load_bot_config(path)
79
+ assert cfg.fires_event is not None
80
+ assert cfg.fires_event.type == "custom.canonical"
81
+
82
+
83
+ def test_save_round_trip_writes_canonical_location(tmp_path):
84
+ """save_bot_config always emits the canonical output.fires_event form."""
85
+ src = _write_yaml(
86
+ tmp_path,
87
+ {
88
+ "bot": {"name": "spark-greeter", "owner": "spark"},
89
+ "trigger": {"type": "event", "filter": "type == 'user.join'"},
90
+ "output": {"channels": ["#general"], "template": "hi"},
91
+ "fires_event": {"type": "custom.greeted", "data": {"n": "x"}},
92
+ },
93
+ )
94
+
95
+ cfg = load_bot_config(src)
96
+ out_path = tmp_path / "saved.yaml"
97
+ save_bot_config(out_path, cfg)
98
+ data = yaml.safe_load(out_path.read_text())
99
+ assert "fires_event" not in data, "top-level fires_event must not be re-emitted"
100
+ assert data["output"]["fires_event"]["type"] == "custom.greeted"
101
+
102
+
103
+ def test_missing_fires_event_still_loads(tmp_path):
104
+ path = _write_yaml(
105
+ tmp_path,
106
+ {
107
+ "bot": {"name": "spark-plain", "owner": "spark"},
108
+ "trigger": {"type": "webhook"},
109
+ "output": {"channels": ["#general"], "template": "hi"},
110
+ },
111
+ )
112
+
113
+ cfg = load_bot_config(path)
114
+ assert cfg.fires_event is None
@@ -0,0 +1,59 @@
1
+ """Regression tests: subprocess timeout handling in persistence._run_cmd.
2
+
3
+ Covers the hang reported for ``culture mesh update``: a broken/hung systemd
4
+ unit caused ``systemctl --user restart`` to block indefinitely because the
5
+ underlying subprocess call had no timeout.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import subprocess
11
+ from unittest.mock import patch
12
+
13
+ from culture.persistence import (
14
+ DEFAULT_CMD_TIMEOUT,
15
+ _restart_linux_service,
16
+ _run_cmd,
17
+ )
18
+
19
+
20
+ def test_run_cmd_returns_true_on_success():
21
+ with patch("culture.persistence.subprocess.run") as mock_run:
22
+ mock_run.return_value = subprocess.CompletedProcess(args=["/bin/true"], returncode=0)
23
+ assert _run_cmd(["/bin/true"]) is True
24
+
25
+
26
+ def test_run_cmd_returns_false_on_timeout():
27
+ """_run_cmd must not propagate TimeoutExpired — callers treat it as failure."""
28
+ with patch("culture.persistence.subprocess.run") as mock_run:
29
+ mock_run.side_effect = subprocess.TimeoutExpired(cmd=["systemctl"], timeout=30)
30
+ assert _run_cmd(["systemctl", "restart", "x"]) is False
31
+
32
+
33
+ def test_run_cmd_passes_timeout_to_subprocess():
34
+ with patch("culture.persistence.subprocess.run") as mock_run:
35
+ mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0)
36
+ _run_cmd(["echo", "hi"], timeout=5)
37
+ kwargs = mock_run.call_args.kwargs
38
+ assert kwargs["timeout"] == 5
39
+
40
+
41
+ def test_run_cmd_default_timeout_bounds_wait():
42
+ """A default timeout must be applied so hung services never hang the CLI."""
43
+ with patch("culture.persistence.subprocess.run") as mock_run:
44
+ mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0)
45
+ _run_cmd(["systemctl", "restart", "x"])
46
+ assert mock_run.call_args.kwargs["timeout"] == DEFAULT_CMD_TIMEOUT
47
+
48
+
49
+ def test_restart_linux_service_returns_false_on_timeout(tmp_path, monkeypatch):
50
+ """When the restart command times out, the restarter must report failure."""
51
+ svc_name = "culture-test-timeout"
52
+ unit_dir = tmp_path / "systemd-user"
53
+ unit_dir.mkdir()
54
+ (unit_dir / f"{svc_name}.service").write_text("[Service]\nExecStart=/bin/true\n")
55
+
56
+ monkeypatch.setattr("culture.persistence._systemd_user_dir", lambda: unit_dir)
57
+ with patch("culture.persistence.subprocess.run") as mock_run:
58
+ mock_run.side_effect = subprocess.TimeoutExpired(cmd=["systemctl"], timeout=30)
59
+ assert _restart_linux_service(svc_name) is False
@@ -561,7 +561,7 @@ wheels = [
561
561
 
562
562
  [[package]]
563
563
  name = "culture"
564
- version = "7.0.4"
564
+ version = "7.1.0"
565
565
  source = { editable = "." }
566
566
  dependencies = [
567
567
  { name = "aiohttp" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes