agentirc-cli 4.3.2__tar.gz → 4.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/CHANGELOG.md +15 -0
  2. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/PKG-INFO +1 -1
  3. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/bots/bot_manager.py +5 -3
  4. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/cli/agent.py +14 -16
  5. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/cli/bot.py +12 -12
  6. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/cli/channel.py +2 -1
  7. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/cli/mesh.py +7 -11
  8. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/cli/server.py +22 -15
  9. agentirc_cli-4.3.4/culture/cli/shared/constants.py +16 -0
  10. agentirc_cli-4.3.4/culture/cli/shared/display.py +131 -0
  11. agentirc_cli-4.3.4/culture/cli/shared/ipc.py +68 -0
  12. agentirc_cli-4.3.4/culture/cli/shared/mesh.py +102 -0
  13. agentirc_cli-4.3.4/culture/cli/shared/process.py +144 -0
  14. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/cli/skills.py +18 -10
  15. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/agent_runner.py +46 -36
  16. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/daemon.py +31 -22
  17. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/skill/irc_client.py +98 -57
  18. {agentirc_cli-4.3.2/culture/clients/claude → agentirc_cli-4.3.4/culture/clients/acp}/supervisor.py +8 -4
  19. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/agent_runner.py +14 -6
  20. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/daemon.py +9 -6
  21. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/skill/irc_client.py +98 -57
  22. {agentirc_cli-4.3.2/culture/clients/acp → agentirc_cli-4.3.4/culture/clients/claude}/supervisor.py +8 -4
  23. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/agent_runner.py +41 -31
  24. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/daemon.py +31 -22
  25. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/skill/irc_client.py +98 -57
  26. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/supervisor.py +22 -14
  27. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/agent_runner.py +26 -17
  28. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/daemon.py +31 -22
  29. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/skill/irc_client.py +98 -57
  30. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/supervisor.py +25 -15
  31. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/observer.py +55 -90
  32. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/overview/collector.py +64 -41
  33. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/overview/renderer_text.py +67 -39
  34. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/overview/renderer_web.py +22 -14
  35. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/persistence.py +34 -19
  36. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/replies.py +8 -0
  37. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/client.py +166 -168
  38. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/ircd.py +16 -11
  39. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/server_link.py +125 -133
  40. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/skills/history.py +3 -3
  41. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/skills/rooms.py +57 -37
  42. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/skills/threads.py +15 -13
  43. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/skill/irc_client.py +98 -57
  44. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/pyproject.toml +1 -1
  45. agentirc_cli-4.3.4/tests/__init__.py +0 -0
  46. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/uv.lock +1 -1
  47. agentirc_cli-4.3.2/culture/cli/_helpers.py +0 -456
  48. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.claude/skills/pr-review/SKILL.md +0 -0
  49. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.claude/skills/run-tests/SKILL.md +0 -0
  50. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.claude/skills/run-tests/scripts/test.sh +0 -0
  51. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.flake8 +0 -0
  52. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.github/workflows/pages.yml +0 -0
  53. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.github/workflows/publish.yml +0 -0
  54. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.github/workflows/security-checks.yml +0 -0
  55. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.github/workflows/tests.yml +0 -0
  56. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.gitignore +0 -0
  57. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.markdownlint-cli2.yaml +0 -0
  58. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.pr_agent.toml +0 -0
  59. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.pre-commit-config.yaml +0 -0
  60. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/.pylintrc +0 -0
  61. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/CLAUDE.md +0 -0
  62. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/CNAME +0 -0
  63. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/Gemfile +0 -0
  64. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/Gemfile.lock +0 -0
  65. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/LICENSE +0 -0
  66. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/README.md +0 -0
  67. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/SECURITY.md +0 -0
  68. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/_config.yml +0 -0
  69. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/_sass/color_schemes/anthropic.scss +0 -0
  70. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/_sass/custom/custom.scss +0 -0
  71. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/__init__.py +0 -0
  72. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/__main__.py +0 -0
  73. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/aio.py +0 -0
  74. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/bots/__init__.py +0 -0
  75. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/bots/bot.py +0 -0
  76. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/bots/config.py +0 -0
  77. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/bots/http_listener.py +0 -0
  78. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/bots/template_engine.py +0 -0
  79. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/bots/virtual_client.py +0 -0
  80. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/cli/__init__.py +0 -0
  81. {agentirc_cli-4.3.2/culture/clients → agentirc_cli-4.3.4/culture/cli/shared}/__init__.py +0 -0
  82. {agentirc_cli-4.3.2/culture/clients/acp → agentirc_cli-4.3.4/culture/clients}/__init__.py +0 -0
  83. {agentirc_cli-4.3.2/culture/clients/acp/skill → agentirc_cli-4.3.4/culture/clients/acp}/__init__.py +0 -0
  84. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/config.py +0 -0
  85. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/ipc.py +0 -0
  86. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/irc_transport.py +0 -0
  87. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/message_buffer.py +0 -0
  88. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/skill/SKILL.md +0 -0
  89. {agentirc_cli-4.3.2/culture/clients/claude → agentirc_cli-4.3.4/culture/clients/acp/skill}/__init__.py +0 -0
  90. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/socket_server.py +0 -0
  91. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/acp/webhook.py +0 -0
  92. {agentirc_cli-4.3.2/culture/clients/claude/skill → agentirc_cli-4.3.4/culture/clients/claude}/__init__.py +0 -0
  93. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/__main__.py +0 -0
  94. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/config.py +0 -0
  95. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/ipc.py +0 -0
  96. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/irc_transport.py +0 -0
  97. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/message_buffer.py +0 -0
  98. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/skill/SKILL.md +0 -0
  99. {agentirc_cli-4.3.2/culture/clients/codex → agentirc_cli-4.3.4/culture/clients/claude/skill}/__init__.py +0 -0
  100. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/socket_server.py +0 -0
  101. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/claude/webhook.py +0 -0
  102. {agentirc_cli-4.3.2/culture/clients/codex/skill → agentirc_cli-4.3.4/culture/clients/codex}/__init__.py +0 -0
  103. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/config.py +0 -0
  104. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/ipc.py +0 -0
  105. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/irc_transport.py +0 -0
  106. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/message_buffer.py +0 -0
  107. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/skill/SKILL.md +0 -0
  108. {agentirc_cli-4.3.2/culture/clients/copilot → agentirc_cli-4.3.4/culture/clients/codex/skill}/__init__.py +0 -0
  109. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/socket_server.py +0 -0
  110. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/codex/webhook.py +0 -0
  111. {agentirc_cli-4.3.2/culture/clients/copilot/skill → agentirc_cli-4.3.4/culture/clients/copilot}/__init__.py +0 -0
  112. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/config.py +0 -0
  113. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/ipc.py +0 -0
  114. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/irc_transport.py +0 -0
  115. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/message_buffer.py +0 -0
  116. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/skill/SKILL.md +0 -0
  117. {agentirc_cli-4.3.2/culture/protocol → agentirc_cli-4.3.4/culture/clients/copilot/skill}/__init__.py +0 -0
  118. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/socket_server.py +0 -0
  119. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/clients/copilot/webhook.py +0 -0
  120. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/__init__.py +0 -0
  121. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/app.py +0 -0
  122. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/client.py +0 -0
  123. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/commands.py +0 -0
  124. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/widgets/__init__.py +0 -0
  125. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/widgets/chat.py +0 -0
  126. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/widgets/info_panel.py +0 -0
  127. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/console/widgets/sidebar.py +0 -0
  128. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/credentials.py +0 -0
  129. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/learn_prompt.py +0 -0
  130. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/mesh_config.py +0 -0
  131. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/overview/__init__.py +0 -0
  132. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/overview/model.py +0 -0
  133. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/overview/web/style.css +0 -0
  134. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/pidfile.py +0 -0
  135. {agentirc_cli-4.3.2/culture/server → agentirc_cli-4.3.4/culture/protocol}/__init__.py +0 -0
  136. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/commands.py +0 -0
  137. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/extensions/federation.md +0 -0
  138. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/extensions/history.md +0 -0
  139. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/extensions/icons.md +0 -0
  140. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/extensions/rooms.md +0 -0
  141. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/extensions/tags.md +0 -0
  142. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/extensions/threads.md +0 -0
  143. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/message.py +0 -0
  144. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/protocol/protocol-index.md +0 -0
  145. {agentirc_cli-4.3.2/culture/server/skills → agentirc_cli-4.3.4/culture/server}/__init__.py +0 -0
  146. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/__main__.py +0 -0
  147. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/channel.py +0 -0
  148. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/config.py +0 -0
  149. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/remote_client.py +0 -0
  150. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/room_store.py +0 -0
  151. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/rooms_util.py +0 -0
  152. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/skill.py +0 -0
  153. {agentirc_cli-4.3.2/tests → agentirc_cli-4.3.4/culture/server/skills}/__init__.py +0 -0
  154. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/skills/icon.py +0 -0
  155. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/server/thread_store.py +0 -0
  156. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/culture/skills/culture/SKILL.md +0 -0
  157. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/agent-lifecycle.md +0 -0
  158. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/agentic-self-learn.md +0 -0
  159. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/agent-client.md +0 -0
  160. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/agent-harness-spec.md +0 -0
  161. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/design.md +0 -0
  162. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/harness-conformance.md +0 -0
  163. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/index.md +0 -0
  164. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/layer1-core-irc.md +0 -0
  165. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/layer2-attention.md +0 -0
  166. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/layer3-skills.md +0 -0
  167. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/layer4-federation.md +0 -0
  168. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/layer5-agent-harness.md +0 -0
  169. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/server-architecture.md +0 -0
  170. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/architecture/threads.md +0 -0
  171. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/channel-polling.md +0 -0
  172. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/acp/overview.md +0 -0
  173. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/claude/configuration.md +0 -0
  174. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/claude/context-management.md +0 -0
  175. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/claude/irc-tools.md +0 -0
  176. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/claude/overview.md +0 -0
  177. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/claude/setup.md +0 -0
  178. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/claude/supervisor.md +0 -0
  179. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/claude/webhooks.md +0 -0
  180. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/codex/configuration.md +0 -0
  181. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/codex/context-management.md +0 -0
  182. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/codex/irc-tools.md +0 -0
  183. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/codex/overview.md +0 -0
  184. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/codex/setup.md +0 -0
  185. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/codex/supervisor.md +0 -0
  186. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/codex/webhooks.md +0 -0
  187. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/copilot/configuration.md +0 -0
  188. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/copilot/context-management.md +0 -0
  189. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/copilot/irc-tools.md +0 -0
  190. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/copilot/overview.md +0 -0
  191. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/copilot/setup.md +0 -0
  192. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/copilot/supervisor.md +0 -0
  193. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/clients/copilot/webhooks.md +0 -0
  194. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/culture-cli.md +0 -0
  195. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/getting-started.md +0 -0
  196. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/index.md +0 -0
  197. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/SECURITY.md +0 -0
  198. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/bots.md +0 -0
  199. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/ci.md +0 -0
  200. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/cli.md +0 -0
  201. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/docs-site.md +0 -0
  202. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/index.md +0 -0
  203. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/ops-tooling.md +0 -0
  204. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/overview.md +0 -0
  205. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/operations/publishing.md +0 -0
  206. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  207. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/rooms.md +0 -0
  208. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/server-rename.md +0 -0
  209. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  210. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  211. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  212. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  213. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  214. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  215. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  216. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  217. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  218. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  219. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  220. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  221. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  222. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  223. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  224. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  225. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  226. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  227. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  228. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
  229. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  230. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
  231. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/01-pair-programming.md +0 -0
  232. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/02-code-review-ensemble.md +0 -0
  233. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/03-cross-server-delegation.md +0 -0
  234. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/04-knowledge-propagation.md +0 -0
  235. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/05-the-observer.md +0 -0
  236. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/06-cross-server-ops.md +0 -0
  237. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/07-supervisor-intervention.md +0 -0
  238. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/08-apps-as-agents.md +0 -0
  239. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/09-research-swarm.md +0 -0
  240. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases/10-agent-lifecycle.md +0 -0
  241. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/use-cases-index.md +0 -0
  242. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/docs/what-is-culture.md +0 -0
  243. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/README.md +0 -0
  244. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/config.py +0 -0
  245. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/daemon.py +0 -0
  246. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/ipc.py +0 -0
  247. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/irc_transport.py +0 -0
  248. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/message_buffer.py +0 -0
  249. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/skill/SKILL.md +0 -0
  250. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/socket_server.py +0 -0
  251. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/packages/agent-harness/webhook.py +0 -0
  252. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  253. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  254. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  255. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  256. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/sonar-project.properties +0 -0
  257. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/conftest.py +0 -0
  258. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_acp_daemon.py +0 -0
  259. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_agent_runner.py +0 -0
  260. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_archive.py +0 -0
  261. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_bot.py +0 -0
  262. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_bot_config.py +0 -0
  263. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_bot_manager.py +0 -0
  264. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_bots_integration.py +0 -0
  265. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_channel.py +0 -0
  266. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_codex_daemon.py +0 -0
  267. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_connection.py +0 -0
  268. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_console_client.py +0 -0
  269. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_console_commands.py +0 -0
  270. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_console_connection.py +0 -0
  271. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_console_icons.py +0 -0
  272. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_console_integration.py +0 -0
  273. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_copilot_daemon.py +0 -0
  274. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_daemon.py +0 -0
  275. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_daemon_config.py +0 -0
  276. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_daemon_ipc.py +0 -0
  277. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_discovery.py +0 -0
  278. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_federation.py +0 -0
  279. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_history.py +0 -0
  280. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_http_listener.py +0 -0
  281. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_integration_layer5.py +0 -0
  282. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_ipc.py +0 -0
  283. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_irc_transport.py +0 -0
  284. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_link_reconnect.py +0 -0
  285. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_mention_alias.py +0 -0
  286. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_mention_target_cleanup.py +0 -0
  287. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_mentions.py +0 -0
  288. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_mesh_config.py +0 -0
  289. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_message.py +0 -0
  290. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_message_buffer.py +0 -0
  291. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_messaging.py +0 -0
  292. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_modes.py +0 -0
  293. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_overview_cli.py +0 -0
  294. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_overview_collector.py +0 -0
  295. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_overview_model.py +0 -0
  296. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_overview_renderer.py +0 -0
  297. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_overview_web.py +0 -0
  298. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_persistence.py +0 -0
  299. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_pidfile.py +0 -0
  300. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_poll_loop.py +0 -0
  301. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_room_persistence.py +0 -0
  302. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_rooms.py +0 -0
  303. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_rooms_federation.py +0 -0
  304. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_rooms_integration.py +0 -0
  305. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_server_icon_skill.py +0 -0
  306. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_setup_update_cli.py +0 -0
  307. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_skill_client.py +0 -0
  308. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_skills.py +0 -0
  309. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_socket_server.py +0 -0
  310. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_supervisor.py +0 -0
  311. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_template_engine.py +0 -0
  312. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_thread_buffer.py +0 -0
  313. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_threads.py +0 -0
  314. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_virtual_client.py +0 -0
  315. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_wait_for_port.py +0 -0
  316. {agentirc_cli-4.3.2 → agentirc_cli-4.3.4}/tests/test_webhook.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
+ ## [4.3.4] - 2026-04-07
8
+
9
+
10
+ ### Changed
11
+
12
+ - Extract duplicated string literals into named constants (SonarCloud S1192)
13
+ - Refactor cli/_helpers.py into modular cli/shared/ package (constants, ipc, process, mesh, display)
14
+
15
+ ## [4.3.3] - 2026-04-07
16
+
17
+
18
+ ### Changed
19
+
20
+ - Reduced cognitive complexity in 40 functions across 25 files to meet SonarCloud threshold (≤15)
21
+
7
22
  ## [4.3.2] - 2026-04-07
8
23
 
9
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 4.3.2
3
+ Version: 4.3.4
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
@@ -13,6 +13,8 @@ if TYPE_CHECKING:
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
+ BOT_CONFIG_FILE = "bot.yaml"
17
+
16
18
 
17
19
  class BotManager:
18
20
  """Loads, starts, stops, and dispatches webhooks to bots."""
@@ -27,7 +29,7 @@ class BotManager:
27
29
  return
28
30
 
29
31
  for bot_dir in sorted(BOTS_DIR.iterdir()):
30
- yaml_path = bot_dir / "bot.yaml"
32
+ yaml_path = bot_dir / BOT_CONFIG_FILE
31
33
  if not yaml_path.is_file():
32
34
  continue
33
35
  try:
@@ -45,7 +47,7 @@ class BotManager:
45
47
  async def create_bot(self, config: BotConfig) -> Bot:
46
48
  """Create a new bot: write config to disk and start it."""
47
49
  bot_dir = BOTS_DIR / config.name
48
- save_bot_config(bot_dir / "bot.yaml", config)
50
+ save_bot_config(bot_dir / BOT_CONFIG_FILE, config)
49
51
 
50
52
  bot = Bot(config, self.server)
51
53
  self.bots[config.name] = bot
@@ -57,7 +59,7 @@ class BotManager:
57
59
  bot = self.bots.get(name)
58
60
  if not bot:
59
61
  # Try loading from disk
60
- yaml_path = BOTS_DIR / name / "bot.yaml"
62
+ yaml_path = BOTS_DIR / name / BOT_CONFIG_FILE
61
63
  if not yaml_path.is_file():
62
64
  raise ValueError(f"Bot {name!r} not found")
63
65
  config = load_bot_config(yaml_path)
@@ -27,18 +27,16 @@ from culture.pidfile import (
27
27
  write_pid,
28
28
  )
29
29
 
30
- from ._helpers import (
30
+ from .shared.constants import (
31
31
  _CONFIG_HELP,
32
+ DEFAULT_CHANNEL,
32
33
  DEFAULT_CONFIG,
33
34
  LOG_DIR,
34
- agent_socket_path,
35
- get_observer,
36
- ipc_request,
37
- print_agent_detail,
38
- print_agents_overview,
39
- print_bot_listing,
40
- stop_agent,
35
+ NO_AGENTS_MSG,
41
36
  )
37
+ from .shared.display import print_agent_detail, print_agents_overview, print_bot_listing
38
+ from .shared.ipc import agent_socket_path, get_observer, ipc_request
39
+ from .shared.process import stop_agent
42
40
 
43
41
  logger = logging.getLogger("culture")
44
42
 
@@ -212,7 +210,7 @@ def _create_agent_config(args: argparse.Namespace, full_nick: str) -> AgentConfi
212
210
  nick=full_nick,
213
211
  agent="codex",
214
212
  directory=os.getcwd(),
215
- channels=["#general"],
213
+ channels=[DEFAULT_CHANNEL],
216
214
  )
217
215
  if args.agent == "copilot":
218
216
  from culture.clients.copilot.config import AgentConfig as CopilotAgentConfig
@@ -221,7 +219,7 @@ def _create_agent_config(args: argparse.Namespace, full_nick: str) -> AgentConfi
221
219
  nick=full_nick,
222
220
  agent="copilot",
223
221
  directory=os.getcwd(),
224
- channels=["#general"],
222
+ channels=[DEFAULT_CHANNEL],
225
223
  )
226
224
  if args.agent == "acp":
227
225
  import json as _json
@@ -246,13 +244,13 @@ def _create_agent_config(args: argparse.Namespace, full_nick: str) -> AgentConfi
246
244
  agent="acp",
247
245
  acp_command=acp_cmd,
248
246
  directory=os.getcwd(),
249
- channels=["#general"],
247
+ channels=[DEFAULT_CHANNEL],
250
248
  )
251
249
  return AgentConfig(
252
250
  nick=full_nick,
253
251
  agent=args.agent,
254
252
  directory=os.getcwd(),
255
- channels=["#general"],
253
+ channels=[DEFAULT_CHANNEL],
256
254
  )
257
255
 
258
256
 
@@ -365,7 +363,7 @@ def _resolve_agents_to_start(config, args) -> list:
365
363
  agents = _resolve_auto(config)
366
364
 
367
365
  if not agents:
368
- print("No agents configured", file=sys.stderr)
366
+ print(NO_AGENTS_MSG, file=sys.stderr)
369
367
  sys.exit(1)
370
368
  return agents
371
369
 
@@ -541,7 +539,7 @@ def _cmd_stop(args: argparse.Namespace) -> None:
541
539
  if len(config.agents) == 1:
542
540
  agents = config.agents
543
541
  elif len(config.agents) == 0:
544
- print("No agents configured", file=sys.stderr)
542
+ print(NO_AGENTS_MSG, file=sys.stderr)
545
543
  sys.exit(1)
546
544
  else:
547
545
  print(
@@ -574,14 +572,14 @@ def _no_agents_message(config, show_all: bool) -> str:
574
572
  archived_count = sum(1 for a in config.agents if a.archived)
575
573
  if archived_count:
576
574
  return f"No active agents ({archived_count} archived, use --all to show)"
577
- return "No agents configured"
575
+ return NO_AGENTS_MSG
578
576
 
579
577
 
580
578
  def _cmd_status(args: argparse.Namespace) -> None:
581
579
  config = load_config_or_default(args.config)
582
580
 
583
581
  if not config.agents:
584
- print("No agents configured")
582
+ print(NO_AGENTS_MSG)
585
583
  return
586
584
 
587
585
  if args.nick:
@@ -8,7 +8,7 @@ import time
8
8
 
9
9
  from culture.clients.claude.config import load_config_or_default
10
10
 
11
- from ._helpers import _CONFIG_HELP, DEFAULT_CONFIG
11
+ from .shared.constants import _BOT_NAME_HELP, _CONFIG_HELP, BOT_CONFIG_FILE, DEFAULT_CONFIG
12
12
 
13
13
  NAME = "bot"
14
14
 
@@ -31,11 +31,11 @@ def register(subparsers: argparse._SubParsersAction) -> None:
31
31
  bot_create.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
32
32
 
33
33
  bot_start = bot_sub.add_parser("start", help="Start a bot")
34
- bot_start.add_argument("name", help="Bot name")
34
+ bot_start.add_argument("name", help=_BOT_NAME_HELP)
35
35
  bot_start.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
36
36
 
37
37
  bot_stop = bot_sub.add_parser("stop", help="Stop a bot")
38
- bot_stop.add_argument("name", help="Bot name")
38
+ bot_stop.add_argument("name", help=_BOT_NAME_HELP)
39
39
  bot_stop.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
40
40
 
41
41
  bot_list = bot_sub.add_parser("list", help="List bots")
@@ -43,7 +43,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
43
43
  bot_list.add_argument("--all", action="store_true", help="Include archived bots")
44
44
 
45
45
  bot_inspect = bot_sub.add_parser("inspect", help="Show bot details")
46
- bot_inspect.add_argument("name", help="Bot name")
46
+ bot_inspect.add_argument("name", help=_BOT_NAME_HELP)
47
47
  bot_inspect.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
48
48
 
49
49
  bot_archive = bot_sub.add_parser("archive", help="Archive a bot")
@@ -113,11 +113,11 @@ def _bot_create(args: argparse.Namespace) -> None:
113
113
  )
114
114
 
115
115
  bot_dir = BOTS_DIR / name
116
- if (bot_dir / "bot.yaml").exists():
116
+ if (bot_dir / BOT_CONFIG_FILE).exists():
117
117
  print(f"Bot '{name}' already exists at {bot_dir}", file=sys.stderr)
118
118
  sys.exit(1)
119
119
 
120
- save_bot_config(bot_dir / "bot.yaml", bot_config)
120
+ save_bot_config(bot_dir / BOT_CONFIG_FILE, bot_config)
121
121
  print(f"Bot '{name}' created at {bot_dir}")
122
122
  print(f" Owner: {args.owner}")
123
123
  print(f" Trigger: {args.trigger}")
@@ -132,7 +132,7 @@ def _bot_start(args: argparse.Namespace) -> None:
132
132
  from culture.bots.config import BOTS_DIR
133
133
 
134
134
  bot_dir = BOTS_DIR / args.name
135
- if not (bot_dir / "bot.yaml").exists():
135
+ if not (bot_dir / BOT_CONFIG_FILE).exists():
136
136
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
137
137
  sys.exit(1)
138
138
 
@@ -144,7 +144,7 @@ def _bot_stop(args: argparse.Namespace) -> None:
144
144
  from culture.bots.config import BOTS_DIR
145
145
 
146
146
  bot_dir = BOTS_DIR / args.name
147
- if not (bot_dir / "bot.yaml").exists():
147
+ if not (bot_dir / BOT_CONFIG_FILE).exists():
148
148
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
149
149
  sys.exit(1)
150
150
 
@@ -161,7 +161,7 @@ def _load_and_filter_bots(args) -> list:
161
161
  show_all = getattr(args, "all", False)
162
162
  bots = []
163
163
  for bot_dir in sorted(BOTS_DIR.iterdir()):
164
- yaml_path = bot_dir / "bot.yaml"
164
+ yaml_path = bot_dir / BOT_CONFIG_FILE
165
165
  if not yaml_path.is_file():
166
166
  continue
167
167
  try:
@@ -203,7 +203,7 @@ def _bot_inspect(args: argparse.Namespace) -> None:
203
203
  from culture.bots.config import BOTS_DIR, load_bot_config
204
204
 
205
205
  bot_dir = BOTS_DIR / args.name
206
- yaml_path = bot_dir / "bot.yaml"
206
+ yaml_path = bot_dir / BOT_CONFIG_FILE
207
207
  if not yaml_path.is_file():
208
208
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
209
209
  sys.exit(1)
@@ -245,7 +245,7 @@ def _bot_archive(args: argparse.Namespace) -> None:
245
245
  from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
246
246
 
247
247
  bot_dir = BOTS_DIR / args.name
248
- yaml_path = bot_dir / "bot.yaml"
248
+ yaml_path = bot_dir / BOT_CONFIG_FILE
249
249
  if not yaml_path.is_file():
250
250
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
251
251
  sys.exit(1)
@@ -270,7 +270,7 @@ def _bot_unarchive(args: argparse.Namespace) -> None:
270
270
  from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
271
271
 
272
272
  bot_dir = BOTS_DIR / args.name
273
- yaml_path = bot_dir / "bot.yaml"
273
+ yaml_path = bot_dir / BOT_CONFIG_FILE
274
274
  if not yaml_path.is_file():
275
275
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
276
276
  sys.exit(1)
@@ -6,7 +6,8 @@ import argparse
6
6
  import asyncio
7
7
  import sys
8
8
 
9
- from ._helpers import _CONFIG_HELP, DEFAULT_CONFIG, get_observer
9
+ from .shared.constants import _CONFIG_HELP, DEFAULT_CONFIG
10
+ from .shared.ipc import get_observer
10
11
 
11
12
  NAME = "channel"
12
13
 
@@ -17,13 +17,9 @@ from culture.clients.claude.config import (
17
17
  )
18
18
  from culture.pidfile import is_process_alive, read_pid
19
19
 
20
- from ._helpers import (
21
- DEFAULT_CONFIG,
22
- build_server_start_cmd,
23
- generate_mesh_from_agents,
24
- server_stop_by_name,
25
- stop_agent,
26
- )
20
+ from .shared.constants import AGENTS_YAML, CULTURE_DIR, DEFAULT_CONFIG
21
+ from .shared.mesh import build_server_start_cmd, generate_mesh_from_agents
22
+ from .shared.process import server_stop_by_name, stop_agent
27
23
 
28
24
  logger = logging.getLogger("culture")
29
25
 
@@ -313,7 +309,7 @@ def _generate_agent_configs(mesh, server_name: str) -> None:
313
309
 
314
310
  for workdir, agents in workdir_agents.items():
315
311
  os.makedirs(workdir, exist_ok=True)
316
- config_path = os.path.join(workdir, ".culture", "agents.yaml")
312
+ config_path = os.path.join(workdir, CULTURE_DIR, AGENTS_YAML)
317
313
  os.makedirs(os.path.dirname(config_path), exist_ok=True)
318
314
 
319
315
  agent_configs = []
@@ -348,7 +344,7 @@ def _install_mesh_services(mesh, server_name: str, culture_bin: str, config_path
348
344
  for agent in mesh.agents:
349
345
  full_nick = f"{server_name}-{agent.nick}"
350
346
  workdir = os.path.expanduser(agent.workdir)
351
- agent_config_path = os.path.join(workdir, ".culture", "agents.yaml")
347
+ agent_config_path = os.path.join(workdir, CULTURE_DIR, AGENTS_YAML)
352
348
  agent_cmd = [
353
349
  culture_bin,
354
350
  "agent",
@@ -502,7 +498,7 @@ def _restart_mesh_services(
502
498
  for agent in mesh.agents:
503
499
  full_nick = f"{server_name}-{agent.nick}"
504
500
  workdir = os.path.expanduser(agent.workdir)
505
- agent_config_path = os.path.join(workdir, ".culture", "agents.yaml")
501
+ agent_config_path = os.path.join(workdir, CULTURE_DIR, AGENTS_YAML)
506
502
  agent_cmd = [
507
503
  culture_bin,
508
504
  "agent",
@@ -549,7 +545,7 @@ def _restart_mesh_services(
549
545
  print(f" Restarting {agent_svc}...")
550
546
  if not restart_service(agent_svc):
551
547
  workdir = os.path.expanduser(agent.workdir)
552
- agent_config_path = os.path.join(workdir, ".culture", "agents.yaml")
548
+ agent_config_path = os.path.join(workdir, CULTURE_DIR, AGENTS_YAML)
553
549
  subprocess.run(
554
550
  [culture_bin, "agent", "start", full_nick, "--config", agent_config_path],
555
551
  check=False,
@@ -19,7 +19,14 @@ from culture.pidfile import (
19
19
  write_pid,
20
20
  )
21
21
 
22
- from ._helpers import LOG_DIR, parse_link, resolve_links_from_mesh
22
+ from .shared.constants import (
23
+ _CONFIG_HELP,
24
+ _SERVER_NAME_HELP,
25
+ BOT_CONFIG_FILE,
26
+ DEFAULT_CONFIG,
27
+ LOG_DIR,
28
+ )
29
+ from .shared.mesh import parse_link, resolve_links_from_mesh
23
30
 
24
31
  logger = logging.getLogger("culture")
25
32
 
@@ -31,7 +38,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
31
38
  server_sub = server_parser.add_subparsers(dest="server_command")
32
39
 
33
40
  srv_start = server_sub.add_parser("start", help="Start the IRC server daemon")
34
- srv_start.add_argument("--name", default="culture", help="Server name")
41
+ srv_start.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
35
42
  srv_start.add_argument("--host", default="0.0.0.0", help="Listen address")
36
43
  srv_start.add_argument("--port", type=int, default=6667, help="Listen port")
37
44
  srv_start.add_argument(
@@ -59,10 +66,10 @@ def register(subparsers: argparse._SubParsersAction) -> None:
59
66
  )
60
67
 
61
68
  srv_stop = server_sub.add_parser("stop", help="Stop the IRC server daemon")
62
- srv_stop.add_argument("--name", default="culture", help="Server name")
69
+ srv_stop.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
63
70
 
64
71
  srv_status = server_sub.add_parser("status", help="Check server daemon status")
65
- srv_status.add_argument("--name", default="culture", help="Server name")
72
+ srv_status.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
66
73
 
67
74
  srv_default = server_sub.add_parser("default", help="Set default server")
68
75
  srv_default.add_argument("name", help="Server name to set as default")
@@ -73,29 +80,29 @@ def register(subparsers: argparse._SubParsersAction) -> None:
73
80
  srv_rename.add_argument("new_name", help="New server name")
74
81
  srv_rename.add_argument(
75
82
  "--config",
76
- default=os.path.expanduser("~/.culture/agents.yaml"),
77
- help="Config file path",
83
+ default=DEFAULT_CONFIG,
84
+ help=_CONFIG_HELP,
78
85
  )
79
86
 
80
87
  srv_archive = server_sub.add_parser(
81
88
  "archive", help="Archive the server and all its agents/bots"
82
89
  )
83
- srv_archive.add_argument("--name", default="culture", help="Server name")
90
+ srv_archive.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
84
91
  srv_archive.add_argument("--reason", default="", help="Reason for archiving")
85
92
  srv_archive.add_argument(
86
93
  "--config",
87
- default=os.path.expanduser("~/.culture/agents.yaml"),
88
- help="Config file path",
94
+ default=DEFAULT_CONFIG,
95
+ help=_CONFIG_HELP,
89
96
  )
90
97
 
91
98
  srv_unarchive = server_sub.add_parser(
92
99
  "unarchive", help="Restore an archived server and all its agents/bots"
93
100
  )
94
- srv_unarchive.add_argument("--name", default="culture", help="Server name")
101
+ srv_unarchive.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
95
102
  srv_unarchive.add_argument(
96
103
  "--config",
97
- default=os.path.expanduser("~/.culture/agents.yaml"),
98
- help="Config file path",
104
+ default=DEFAULT_CONFIG,
105
+ help=_CONFIG_HELP,
99
106
  )
100
107
 
101
108
 
@@ -256,7 +263,7 @@ def _server_start(args: argparse.Namespace) -> None:
256
263
  # Check if server is archived
257
264
  from culture.clients.claude.config import load_config_or_default
258
265
 
259
- config_path = getattr(args, "config", os.path.expanduser("~/.culture/agents.yaml"))
266
+ config_path = getattr(args, "config", DEFAULT_CONFIG)
260
267
  config = load_config_or_default(config_path)
261
268
  if config.server.name == args.name and config.server.archived:
262
269
  print(
@@ -439,7 +446,7 @@ def _set_bots_archive_state(agent_nicks: set, *, archive: bool, reason: str = ""
439
446
  return changed
440
447
  today = time.strftime("%Y-%m-%d")
441
448
  for bot_dir in BOTS_DIR.iterdir():
442
- yaml_path = bot_dir / "bot.yaml"
449
+ yaml_path = bot_dir / BOT_CONFIG_FILE
443
450
  if not yaml_path.is_file():
444
451
  continue
445
452
  try:
@@ -486,7 +493,7 @@ def _server_archive(args: argparse.Namespace) -> None:
486
493
  _server_stop(args)
487
494
 
488
495
  # Stop all running agents
489
- from culture.cli._helpers import stop_agent
496
+ from culture.cli.shared.process import stop_agent
490
497
 
491
498
  for agent in config.agents:
492
499
  agent_pid = read_pid(f"agent-{agent.nick}")
@@ -0,0 +1,16 @@
1
+ """Shared constants for culture CLI modules."""
2
+
3
+ import os
4
+
5
+ DEFAULT_CONFIG = os.path.expanduser("~/.culture/agents.yaml")
6
+ LOG_DIR = os.path.expanduser("~/.culture/logs")
7
+
8
+ _CONFIG_HELP = "Config file path"
9
+ _SERVER_NAME_HELP = "Server name"
10
+ _BOT_NAME_HELP = "Bot name"
11
+
12
+ BOT_CONFIG_FILE = "bot.yaml"
13
+ DEFAULT_CHANNEL = "#general"
14
+ NO_AGENTS_MSG = "No agents configured"
15
+ CULTURE_DIR = ".culture"
16
+ AGENTS_YAML = "agents.yaml"
@@ -0,0 +1,131 @@
1
+ """Agent and bot status display helpers for culture CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import asyncio
7
+ import logging
8
+ import os
9
+
10
+ from culture.pidfile import is_process_alive, read_pid, remove_pid
11
+
12
+ from .constants import BOT_CONFIG_FILE
13
+ from .ipc import agent_socket_path, ipc_request
14
+
15
+ logger = logging.getLogger("culture")
16
+
17
+
18
+ def agent_process_status(agent) -> tuple[str, int | None]:
19
+ """Return (status_str, pid_or_none) for an agent."""
20
+ pid_name = f"agent-{agent.nick}"
21
+ pid = read_pid(pid_name)
22
+ if pid and is_process_alive(pid):
23
+ socket_path = agent_socket_path(agent.nick)
24
+ if os.path.exists(socket_path):
25
+ return "running", pid
26
+ return "starting", pid
27
+ if pid:
28
+ remove_pid(pid_name)
29
+ return "stopped", None
30
+
31
+
32
+ def print_agent_detail(agent, config_path: str, args: argparse.Namespace) -> None:
33
+ """Print detailed status for a single agent, including live IPC activity query."""
34
+ status, pid = agent_process_status(agent)
35
+ print(agent.nick)
36
+ print(f" Status: {status}")
37
+ print(f" PID: {pid or '-'}")
38
+
39
+ if status == "running":
40
+ resp = asyncio.run(ipc_request(agent_socket_path(agent.nick), "status", query=True))
41
+ if resp and resp.get("ok"):
42
+ data = resp.get("data", {})
43
+ print(f" Activity: {data.get('description', 'nothing')}")
44
+ print(f" Turns: {data.get('turn_count', 0)}")
45
+ print(f" Paused: {'yes' if data.get('paused') else 'no'}")
46
+ else:
47
+ print(" Activity: unknown (daemon may need restart)")
48
+ else:
49
+ print(" Activity: -")
50
+
51
+ channels = agent.channels if isinstance(agent.channels, list) else []
52
+ print(f" Directory: {agent.directory}")
53
+ print(f" Backend: {agent.agent}")
54
+ print(f" Channels: {', '.join(channels)}")
55
+ print(f" Model: {agent.model}")
56
+ print(f" Config: {config_path}")
57
+
58
+
59
+ def _format_agent_status(base_status: str, archived: bool, show_archived_marker: bool) -> str:
60
+ """Format the display status string for an agent."""
61
+ if not archived:
62
+ return base_status
63
+ if show_archived_marker:
64
+ return f"{base_status} (archived)"
65
+ if base_status == "stopped":
66
+ return "archived"
67
+ return base_status
68
+
69
+
70
+ def _fetch_agent_activity(agent) -> str:
71
+ """Fetch activity description from a running agent via IPC."""
72
+ resp = asyncio.run(ipc_request(agent_socket_path(agent.nick), "status"))
73
+ if resp and resp.get("ok"):
74
+ return resp.get("data", {}).get("description", "nothing")
75
+ return "-"
76
+
77
+
78
+ def print_agents_overview(
79
+ agents: list, show_activity: bool, show_archived_marker: bool = False
80
+ ) -> None:
81
+ """Print a table of all agents with status, PID, and optionally activity."""
82
+ if show_activity:
83
+ print(f"{'NICK':<30} {'STATUS':<12} {'PID':<10} {'ACTIVITY'}")
84
+ print("-" * 72)
85
+ else:
86
+ print(f"{'NICK':<30} {'STATUS':<12} {'PID':<10}")
87
+ print("-" * 52)
88
+
89
+ for agent in agents:
90
+ base_status, pid = agent_process_status(agent)
91
+ status = _format_agent_status(
92
+ base_status, getattr(agent, "archived", False), show_archived_marker
93
+ )
94
+ activity = (
95
+ _fetch_agent_activity(agent) if show_activity and base_status == "running" else "-"
96
+ )
97
+ if show_activity:
98
+ print(f"{agent.nick:<30} {status:<12} {str(pid or '-'):<10} {activity}")
99
+ else:
100
+ print(f"{agent.nick:<30} {status:<12} {str(pid or '-'):<10}")
101
+
102
+
103
+ def _load_bot_configs() -> list:
104
+ """Load all valid bot configs from the bots directory."""
105
+ from culture.bots.config import BOTS_DIR, load_bot_config
106
+
107
+ if not BOTS_DIR.is_dir():
108
+ return []
109
+ configs = []
110
+ for bot_dir in sorted(BOTS_DIR.iterdir()):
111
+ yaml_path = bot_dir / BOT_CONFIG_FILE
112
+ if not yaml_path.is_file():
113
+ continue
114
+ try:
115
+ configs.append(load_bot_config(yaml_path))
116
+ except Exception as exc:
117
+ logger.warning("Failed to load bot config %s: %s", yaml_path, exc)
118
+ return configs
119
+
120
+
121
+ def print_bot_listing() -> None:
122
+ """Print a table of configured bots (if any exist)."""
123
+ bot_configs = _load_bot_configs()
124
+ if not bot_configs:
125
+ return
126
+ print()
127
+ print(f"{'BOT':<30} {'TRIGGER':<12} {'CHANNELS'}")
128
+ print("-" * 60)
129
+ for bc in bot_configs:
130
+ channels = ", ".join(bc.channels) if bc.channels else "-"
131
+ print(f"{bc.name:<30} {bc.trigger_type:<12} {channels}")
@@ -0,0 +1,68 @@
1
+ """IPC and observer helpers for culture CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import os
7
+
8
+ from culture.clients.claude.config import load_config_or_default
9
+
10
+
11
+ def agent_socket_path(nick: str) -> str:
12
+ return os.path.join(
13
+ os.environ.get("XDG_RUNTIME_DIR", "/tmp"),
14
+ f"culture-{nick}.sock",
15
+ )
16
+
17
+
18
+ async def ipc_request(socket_path: str, msg_type: str, **kwargs) -> dict | None:
19
+ """Send an IPC request via Unix socket and return the response."""
20
+ from culture.clients.claude.ipc import decode_message, encode_message, make_request
21
+
22
+ try:
23
+ reader, writer = await asyncio.wait_for(
24
+ asyncio.open_unix_connection(socket_path),
25
+ timeout=3.0,
26
+ )
27
+ except (ConnectionRefusedError, FileNotFoundError, OSError):
28
+ return None
29
+ try:
30
+ req = make_request(msg_type, **kwargs)
31
+ writer.write(encode_message(req))
32
+ await writer.drain()
33
+ loop = asyncio.get_running_loop()
34
+ deadline = loop.time() + 3.0
35
+ while True:
36
+ remaining = deadline - loop.time()
37
+ if remaining <= 0:
38
+ return None
39
+ data = await asyncio.wait_for(reader.readline(), timeout=remaining)
40
+ msg = decode_message(data)
41
+ if msg and msg.get("type") == "response":
42
+ return msg
43
+ except (asyncio.TimeoutError, ConnectionError, BrokenPipeError, OSError):
44
+ return None
45
+ finally:
46
+ writer.close()
47
+ try:
48
+ await writer.wait_closed()
49
+ except (ConnectionError, BrokenPipeError, OSError):
50
+ pass
51
+
52
+
53
+ async def ipc_shutdown(socket_path: str) -> bool:
54
+ """Send a shutdown command via Unix socket IPC."""
55
+ resp = await ipc_request(socket_path, "shutdown")
56
+ return resp is not None and resp.get("ok", False)
57
+
58
+
59
+ def get_observer(config_path: str):
60
+ """Create an IRCObserver from the config file."""
61
+ from culture.observer import IRCObserver
62
+
63
+ config = load_config_or_default(config_path)
64
+ return IRCObserver(
65
+ host=config.server.host,
66
+ port=config.server.port,
67
+ server_name=config.server.name,
68
+ )