agentirc-cli 4.3.5__tar.gz → 4.3.6__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 (317) hide show
  1. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/CHANGELOG.md +25 -0
  2. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/PKG-INFO +1 -1
  3. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/__init__.py +4 -1
  4. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/__init__.py +5 -3
  5. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/agent.py +25 -6
  6. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/bot.py +5 -0
  7. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/channel.py +30 -3
  8. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/server.py +53 -7
  9. agentirc_cli-4.3.6/culture/cli/shared/formatting.py +5 -0
  10. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/config.py +5 -5
  11. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/config.py +8 -8
  12. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/config.py +5 -5
  13. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/config.py +5 -5
  14. agentirc_cli-4.3.6/culture/formatting.py +19 -0
  15. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/observer.py +7 -1
  16. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/overview/renderer_text.py +1 -13
  17. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/pyproject.toml +1 -1
  18. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/uv.lock +1 -1
  19. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.claude/skills/pr-review/SKILL.md +0 -0
  20. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.claude/skills/run-tests/SKILL.md +0 -0
  21. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.claude/skills/run-tests/scripts/test.sh +0 -0
  22. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.flake8 +0 -0
  23. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.github/workflows/pages.yml +0 -0
  24. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.github/workflows/publish.yml +0 -0
  25. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.github/workflows/security-checks.yml +0 -0
  26. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.github/workflows/tests.yml +0 -0
  27. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.gitignore +0 -0
  28. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.markdownlint-cli2.yaml +0 -0
  29. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.pr_agent.toml +0 -0
  30. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.pre-commit-config.yaml +0 -0
  31. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/.pylintrc +0 -0
  32. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/CLAUDE.md +0 -0
  33. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/CNAME +0 -0
  34. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/Gemfile +0 -0
  35. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/Gemfile.lock +0 -0
  36. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/LICENSE +0 -0
  37. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/README.md +0 -0
  38. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/SECURITY.md +0 -0
  39. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/_config.yml +0 -0
  40. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/_sass/color_schemes/anthropic.scss +0 -0
  41. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/_sass/custom/custom.scss +0 -0
  42. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/__main__.py +0 -0
  43. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/aio.py +0 -0
  44. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/bots/__init__.py +0 -0
  45. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/bots/bot.py +0 -0
  46. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/bots/bot_manager.py +0 -0
  47. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/bots/config.py +0 -0
  48. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/bots/http_listener.py +0 -0
  49. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/bots/template_engine.py +0 -0
  50. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/bots/virtual_client.py +0 -0
  51. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/mesh.py +0 -0
  52. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/shared/__init__.py +0 -0
  53. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/shared/constants.py +0 -0
  54. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/shared/display.py +0 -0
  55. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/shared/ipc.py +0 -0
  56. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/shared/mesh.py +0 -0
  57. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/shared/process.py +0 -0
  58. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/cli/skills.py +0 -0
  59. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/__init__.py +0 -0
  60. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/__init__.py +0 -0
  61. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/agent_runner.py +0 -0
  62. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/daemon.py +0 -0
  63. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/ipc.py +0 -0
  64. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/irc_transport.py +0 -0
  65. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/message_buffer.py +0 -0
  66. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/skill/SKILL.md +0 -0
  67. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/skill/__init__.py +0 -0
  68. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/skill/irc_client.py +0 -0
  69. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/socket_server.py +0 -0
  70. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/supervisor.py +0 -0
  71. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/acp/webhook.py +0 -0
  72. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/__init__.py +0 -0
  73. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/__main__.py +0 -0
  74. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/agent_runner.py +0 -0
  75. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/daemon.py +0 -0
  76. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/ipc.py +0 -0
  77. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/irc_transport.py +0 -0
  78. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/message_buffer.py +0 -0
  79. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/skill/SKILL.md +0 -0
  80. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/skill/__init__.py +0 -0
  81. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/skill/irc_client.py +0 -0
  82. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/socket_server.py +0 -0
  83. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/supervisor.py +0 -0
  84. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/claude/webhook.py +0 -0
  85. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/__init__.py +0 -0
  86. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/agent_runner.py +0 -0
  87. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/daemon.py +0 -0
  88. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/ipc.py +0 -0
  89. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/irc_transport.py +0 -0
  90. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/message_buffer.py +0 -0
  91. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/skill/SKILL.md +0 -0
  92. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/skill/__init__.py +0 -0
  93. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/skill/irc_client.py +0 -0
  94. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/socket_server.py +0 -0
  95. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/supervisor.py +0 -0
  96. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/codex/webhook.py +0 -0
  97. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/__init__.py +0 -0
  98. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/agent_runner.py +0 -0
  99. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/daemon.py +0 -0
  100. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/ipc.py +0 -0
  101. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/irc_transport.py +0 -0
  102. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/message_buffer.py +0 -0
  103. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/skill/SKILL.md +0 -0
  104. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/skill/__init__.py +0 -0
  105. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/skill/irc_client.py +0 -0
  106. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/socket_server.py +0 -0
  107. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/supervisor.py +0 -0
  108. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/clients/copilot/webhook.py +0 -0
  109. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/__init__.py +0 -0
  110. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/app.py +0 -0
  111. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/client.py +0 -0
  112. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/commands.py +0 -0
  113. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/widgets/__init__.py +0 -0
  114. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/widgets/chat.py +0 -0
  115. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/widgets/info_panel.py +0 -0
  116. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/console/widgets/sidebar.py +0 -0
  117. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/credentials.py +0 -0
  118. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/learn_prompt.py +0 -0
  119. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/mesh_config.py +0 -0
  120. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/overview/__init__.py +0 -0
  121. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/overview/collector.py +0 -0
  122. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/overview/model.py +0 -0
  123. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/overview/renderer_web.py +0 -0
  124. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/overview/web/style.css +0 -0
  125. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/persistence.py +0 -0
  126. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/pidfile.py +0 -0
  127. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/__init__.py +0 -0
  128. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/commands.py +0 -0
  129. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/extensions/federation.md +0 -0
  130. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/extensions/history.md +0 -0
  131. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/extensions/icons.md +0 -0
  132. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/extensions/rooms.md +0 -0
  133. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/extensions/tags.md +0 -0
  134. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/extensions/threads.md +0 -0
  135. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/message.py +0 -0
  136. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/protocol-index.md +0 -0
  137. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/protocol/replies.py +0 -0
  138. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/__init__.py +0 -0
  139. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/__main__.py +0 -0
  140. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/channel.py +0 -0
  141. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/client.py +0 -0
  142. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/config.py +0 -0
  143. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/ircd.py +0 -0
  144. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/remote_client.py +0 -0
  145. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/room_store.py +0 -0
  146. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/rooms_util.py +0 -0
  147. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/server_link.py +0 -0
  148. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/skill.py +0 -0
  149. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/skills/__init__.py +0 -0
  150. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/skills/history.py +0 -0
  151. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/skills/icon.py +0 -0
  152. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/skills/rooms.py +0 -0
  153. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/skills/threads.py +0 -0
  154. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/server/thread_store.py +0 -0
  155. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/culture/skills/culture/SKILL.md +0 -0
  156. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/agent-lifecycle.md +0 -0
  157. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/agentic-self-learn.md +0 -0
  158. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/agent-client.md +0 -0
  159. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/agent-harness-spec.md +0 -0
  160. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/design.md +0 -0
  161. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/harness-conformance.md +0 -0
  162. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/index.md +0 -0
  163. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/layer1-core-irc.md +0 -0
  164. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/layer2-attention.md +0 -0
  165. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/layer3-skills.md +0 -0
  166. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/layer4-federation.md +0 -0
  167. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/layer5-agent-harness.md +0 -0
  168. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/server-architecture.md +0 -0
  169. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/architecture/threads.md +0 -0
  170. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/channel-polling.md +0 -0
  171. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/acp/overview.md +0 -0
  172. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/claude/configuration.md +0 -0
  173. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/claude/context-management.md +0 -0
  174. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/claude/irc-tools.md +0 -0
  175. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/claude/overview.md +0 -0
  176. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/claude/setup.md +0 -0
  177. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/claude/supervisor.md +0 -0
  178. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/claude/webhooks.md +0 -0
  179. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/codex/configuration.md +0 -0
  180. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/codex/context-management.md +0 -0
  181. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/codex/irc-tools.md +0 -0
  182. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/codex/overview.md +0 -0
  183. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/codex/setup.md +0 -0
  184. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/codex/supervisor.md +0 -0
  185. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/codex/webhooks.md +0 -0
  186. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/copilot/configuration.md +0 -0
  187. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/copilot/context-management.md +0 -0
  188. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/copilot/irc-tools.md +0 -0
  189. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/copilot/overview.md +0 -0
  190. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/copilot/setup.md +0 -0
  191. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/copilot/supervisor.md +0 -0
  192. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/clients/copilot/webhooks.md +0 -0
  193. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/culture-cli.md +0 -0
  194. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/getting-started.md +0 -0
  195. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/index.md +0 -0
  196. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/SECURITY.md +0 -0
  197. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/bots.md +0 -0
  198. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/ci.md +0 -0
  199. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/cli.md +0 -0
  200. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/docs-site.md +0 -0
  201. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/index.md +0 -0
  202. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/ops-tooling.md +0 -0
  203. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/overview.md +0 -0
  204. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/operations/publishing.md +0 -0
  205. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  206. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/rooms.md +0 -0
  207. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/server-rename.md +0 -0
  208. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  209. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  210. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  211. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  212. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  213. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  214. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  215. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  216. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  217. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  218. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  219. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  220. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  221. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  222. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  223. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  224. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  225. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  226. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  227. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
  228. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  229. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
  230. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/01-pair-programming.md +0 -0
  231. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/02-code-review-ensemble.md +0 -0
  232. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/03-cross-server-delegation.md +0 -0
  233. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/04-knowledge-propagation.md +0 -0
  234. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/05-the-observer.md +0 -0
  235. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/06-cross-server-ops.md +0 -0
  236. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/07-supervisor-intervention.md +0 -0
  237. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/08-apps-as-agents.md +0 -0
  238. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/09-research-swarm.md +0 -0
  239. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases/10-agent-lifecycle.md +0 -0
  240. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/use-cases-index.md +0 -0
  241. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/docs/what-is-culture.md +0 -0
  242. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/README.md +0 -0
  243. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/config.py +0 -0
  244. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/daemon.py +0 -0
  245. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/ipc.py +0 -0
  246. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/irc_transport.py +0 -0
  247. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/message_buffer.py +0 -0
  248. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/skill/SKILL.md +0 -0
  249. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/skill/irc_client.py +0 -0
  250. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/socket_server.py +0 -0
  251. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/packages/agent-harness/webhook.py +0 -0
  252. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  253. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  254. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  255. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  256. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/sonar-project.properties +0 -0
  257. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/__init__.py +0 -0
  258. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/conftest.py +0 -0
  259. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_acp_daemon.py +0 -0
  260. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_agent_runner.py +0 -0
  261. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_archive.py +0 -0
  262. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_bot.py +0 -0
  263. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_bot_config.py +0 -0
  264. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_bot_manager.py +0 -0
  265. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_bots_integration.py +0 -0
  266. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_channel.py +0 -0
  267. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_codex_daemon.py +0 -0
  268. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_connection.py +0 -0
  269. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_console_client.py +0 -0
  270. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_console_commands.py +0 -0
  271. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_console_connection.py +0 -0
  272. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_console_icons.py +0 -0
  273. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_console_integration.py +0 -0
  274. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_copilot_daemon.py +0 -0
  275. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_daemon.py +0 -0
  276. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_daemon_config.py +0 -0
  277. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_daemon_ipc.py +0 -0
  278. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_discovery.py +0 -0
  279. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_federation.py +0 -0
  280. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_history.py +0 -0
  281. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_http_listener.py +0 -0
  282. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_integration_layer5.py +0 -0
  283. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_ipc.py +0 -0
  284. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_irc_transport.py +0 -0
  285. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_link_reconnect.py +0 -0
  286. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_mention_alias.py +0 -0
  287. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_mention_target_cleanup.py +0 -0
  288. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_mentions.py +0 -0
  289. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_mesh_config.py +0 -0
  290. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_message.py +0 -0
  291. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_message_buffer.py +0 -0
  292. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_messaging.py +0 -0
  293. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_modes.py +0 -0
  294. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_overview_cli.py +0 -0
  295. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_overview_collector.py +0 -0
  296. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_overview_model.py +0 -0
  297. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_overview_renderer.py +0 -0
  298. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_overview_web.py +0 -0
  299. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_persistence.py +0 -0
  300. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_pidfile.py +0 -0
  301. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_poll_loop.py +0 -0
  302. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_room_persistence.py +0 -0
  303. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_rooms.py +0 -0
  304. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_rooms_federation.py +0 -0
  305. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_rooms_integration.py +0 -0
  306. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_server_icon_skill.py +0 -0
  307. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_setup_update_cli.py +0 -0
  308. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_skill_client.py +0 -0
  309. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_skills.py +0 -0
  310. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_socket_server.py +0 -0
  311. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_supervisor.py +0 -0
  312. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_template_engine.py +0 -0
  313. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_thread_buffer.py +0 -0
  314. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_threads.py +0 -0
  315. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_virtual_client.py +0 -0
  316. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_wait_for_port.py +0 -0
  317. {agentirc_cli-4.3.5 → agentirc_cli-4.3.6}/tests/test_webhook.py +0 -0
@@ -4,6 +4,31 @@ 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.6] - 2026-04-07
8
+
9
+
10
+ ### Changed
11
+
12
+ - CLI module docstring updated with current subcommand sets (#147)
13
+
14
+
15
+ ### Fixed
16
+
17
+ - agent message silently succeeds for nonexistent targets (#132)
18
+ - channel message silently succeeds for nonexistent channels (#133)
19
+ - agent sleep/wake error messages use wrong command names (#134)
20
+ - server subcommands ignore default server, hardcode culture (#135)
21
+ - agent start/stop inconsistent behavior with no nick argument (#137)
22
+ - channel message and bot create accept empty strings (#138)
23
+ - bot archive/unarchive missing --config flag (#139)
24
+ - inconsistent error message casing in agent archive vs unarchive (#140)
25
+ - channel commands show confusing timeout error when server is down (#141)
26
+ - uncaught PackageNotFoundError in version fallback (#142)
27
+ - culture --version flag not supported (#143)
28
+ - agent/channel message silently succeeds for nonexistent or empty targets (#144)
29
+ - channel read displays raw Unix timestamps instead of human-readable format (#145)
30
+ - server default accepts nonexistent server names without validation (#146)
31
+
7
32
  ## [4.3.5] - 2026-04-07
8
33
 
9
34
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 4.3.5
3
+ Version: 4.3.6
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
@@ -7,4 +7,7 @@ except PackageNotFoundError:
7
7
  try:
8
8
  __version__ = _v("agentirc-cli")
9
9
  except PackageNotFoundError:
10
- __version__ = _v("agentirc")
10
+ try:
11
+ __version__ = _v("agentirc")
12
+ except PackageNotFoundError:
13
+ __version__ = "0.0.0-dev"
@@ -1,11 +1,11 @@
1
1
  """Unified CLI entry point for culture.
2
2
 
3
3
  Commands are organized into noun-based groups:
4
- culture agent {create,join,start,stop,status,rename,assign,sleep,wake,learn,message,read}
5
- culture server {start,stop,status,default,rename}
4
+ culture agent {create,join,start,stop,status,rename,assign,sleep,wake,learn,message,read,archive,unarchive,delete}
5
+ culture server {start,stop,status,default,rename,archive,unarchive}
6
6
  culture mesh {overview,setup,update,console}
7
7
  culture channel {list,read,message,who}
8
- culture bot {create,start,stop,list,inspect}
8
+ culture bot {create,start,stop,list,inspect,archive,unarchive}
9
9
  culture skills {install}
10
10
  """
11
11
 
@@ -15,6 +15,7 @@ import argparse
15
15
  import logging
16
16
  import sys
17
17
 
18
+ from culture import __version__
18
19
  from culture.cli import agent, bot, channel, mesh, server, skills
19
20
 
20
21
  GROUPS = [agent, server, mesh, channel, bot, skills]
@@ -25,6 +26,7 @@ def _build_parser() -> argparse.ArgumentParser:
25
26
  prog="culture",
26
27
  description="culture — AI agent IRC mesh",
27
28
  )
29
+ parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
28
30
  sub = parser.add_subparsers(dest="command")
29
31
  for group in GROUPS:
30
32
  group.register(sub)
@@ -591,10 +591,17 @@ def _resolve_agents_to_stop(config, args) -> list:
591
591
  if len(config.agents) == 0:
592
592
  print(NO_AGENTS_MSG, file=sys.stderr)
593
593
  sys.exit(1)
594
+ # Multiple agents: try to match by current working directory
595
+ cwd_real = os.path.realpath(os.getcwd())
596
+ cwd_matches = [a for a in config.agents if os.path.realpath(a.directory) == cwd_real]
597
+ if len(cwd_matches) == 1:
598
+ return cwd_matches
594
599
  print(
595
600
  "Multiple agents configured. Specify a nick or use --all.",
596
601
  file=sys.stderr,
597
602
  )
603
+ for a in config.agents:
604
+ print(f" {a.nick}", file=sys.stderr)
598
605
  sys.exit(1)
599
606
 
600
607
 
@@ -763,13 +770,13 @@ def _cmd_assign(args: argparse.Namespace) -> None:
763
770
  # -----------------------------------------------------------------------
764
771
 
765
772
 
766
- def _resolve_ipc_targets(config, args, action_verb: str) -> list:
773
+ def _resolve_ipc_targets(config, args, command_name: str) -> list:
767
774
  """Resolve which agents to send IPC messages to."""
768
775
  if args.nick and args.all:
769
776
  print("Cannot specify both nick and --all", file=sys.stderr)
770
777
  sys.exit(1)
771
778
  if not args.nick and not args.all:
772
- print(f"Usage: culture agent {action_verb} <nick> or --all", file=sys.stderr)
779
+ print(f"Usage: culture agent {command_name} <nick> or --all", file=sys.stderr)
773
780
  sys.exit(1)
774
781
  if args.all:
775
782
  return config.agents
@@ -790,20 +797,22 @@ def _send_ipc(agent, msg_type: str, action_verb: str) -> None:
790
797
  print(f"{agent.nick}: failed (not running?)", file=sys.stderr)
791
798
 
792
799
 
793
- def _ipc_to_agents(args: argparse.Namespace, msg_type: str, action_verb: str) -> None:
800
+ def _ipc_to_agents(
801
+ args: argparse.Namespace, msg_type: str, action_verb: str, command_name: str
802
+ ) -> None:
794
803
  """Send an IPC message (pause/resume) to one or all agents."""
795
804
  config = load_config_or_default(args.config)
796
- targets = _resolve_ipc_targets(config, args, action_verb)
805
+ targets = _resolve_ipc_targets(config, args, command_name)
797
806
  for agent in targets:
798
807
  _send_ipc(agent, msg_type, action_verb)
799
808
 
800
809
 
801
810
  def _cmd_sleep(args: argparse.Namespace) -> None:
802
- _ipc_to_agents(args, "pause", "paused")
811
+ _ipc_to_agents(args, "pause", "paused", "sleep")
803
812
 
804
813
 
805
814
  def _cmd_wake(args: argparse.Namespace) -> None:
806
- _ipc_to_agents(args, "resume", "resumed")
815
+ _ipc_to_agents(args, "resume", "resumed", "wake")
807
816
 
808
817
 
809
818
  def _cmd_learn(args: argparse.Namespace) -> None:
@@ -838,6 +847,16 @@ def _cmd_learn(args: argparse.Namespace) -> None:
838
847
 
839
848
 
840
849
  def _cmd_message(args: argparse.Namespace) -> None:
850
+ if not args.target.strip():
851
+ print("Error: target nick cannot be empty", file=sys.stderr)
852
+ sys.exit(1)
853
+ if not args.text.strip():
854
+ print("Error: message text cannot be empty", file=sys.stderr)
855
+ sys.exit(1)
856
+ config = load_config_or_default(args.config)
857
+ if not config.get_agent(args.target):
858
+ print(f"Agent '{args.target}' not found in config", file=sys.stderr)
859
+ sys.exit(1)
841
860
  observer = get_observer(args.config)
842
861
  asyncio.run(observer.send_message(args.target, args.text))
843
862
  print(f"Sent to {args.target}")
@@ -49,9 +49,11 @@ def register(subparsers: argparse._SubParsersAction) -> None:
49
49
  bot_archive = bot_sub.add_parser("archive", help="Archive a bot")
50
50
  bot_archive.add_argument("name", help="Bot name to archive")
51
51
  bot_archive.add_argument("--reason", default="", help="Reason for archiving")
52
+ bot_archive.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
52
53
 
53
54
  bot_unarchive = bot_sub.add_parser("unarchive", help="Restore an archived bot")
54
55
  bot_unarchive.add_argument("name", help="Bot name to unarchive")
56
+ bot_unarchive.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
55
57
 
56
58
 
57
59
  def dispatch(args: argparse.Namespace) -> None:
@@ -87,6 +89,9 @@ def dispatch(args: argparse.Namespace) -> None:
87
89
  def _bot_create(args: argparse.Namespace) -> None:
88
90
  from culture.bots.config import BOTS_DIR, BotConfig, save_bot_config
89
91
 
92
+ if not args.name.strip():
93
+ print("Error: bot name cannot be empty", file=sys.stderr)
94
+ sys.exit(1)
90
95
  name = args.name
91
96
  config = load_config_or_default(args.config)
92
97
  server_name = config.server.name
@@ -50,11 +50,26 @@ def dispatch(args: argparse.Namespace) -> None:
50
50
  "who": _cmd_who,
51
51
  }
52
52
  handler = handlers.get(args.channel_command)
53
- if handler:
54
- handler(args)
55
- else:
53
+ if not handler:
56
54
  print(f"Unknown channel command: {args.channel_command}", file=sys.stderr)
57
55
  sys.exit(1)
56
+ try:
57
+ handler(args)
58
+ except (ConnectionError, ConnectionRefusedError, TimeoutError, OSError) as exc:
59
+ msg = str(exc)
60
+ if (
61
+ "Timed out" in msg
62
+ or "Connection refused" in msg
63
+ or "Connect call failed" in msg
64
+ or not msg # TimeoutError from asyncio often has empty message
65
+ ):
66
+ print(
67
+ "Error: cannot connect to IRC server. Is the server running?\n"
68
+ " Start it with: culture server start",
69
+ file=sys.stderr,
70
+ )
71
+ sys.exit(1)
72
+ raise
58
73
 
59
74
 
60
75
  # -----------------------------------------------------------------------
@@ -76,6 +91,9 @@ def _cmd_list(args: argparse.Namespace) -> None:
76
91
 
77
92
 
78
93
  def _cmd_read(args: argparse.Namespace) -> None:
94
+ if not args.target.strip():
95
+ print("Error: channel name cannot be empty", file=sys.stderr)
96
+ sys.exit(1)
79
97
  observer = get_observer(args.config)
80
98
  channel = args.target if args.target.startswith("#") else f"#{args.target}"
81
99
  messages = asyncio.run(observer.read_channel(channel, limit=args.limit))
@@ -89,6 +107,12 @@ def _cmd_read(args: argparse.Namespace) -> None:
89
107
 
90
108
 
91
109
  def _cmd_message(args: argparse.Namespace) -> None:
110
+ if not args.target.strip():
111
+ print("Error: channel name cannot be empty", file=sys.stderr)
112
+ sys.exit(1)
113
+ if not args.text.strip():
114
+ print("Error: message text cannot be empty", file=sys.stderr)
115
+ sys.exit(1)
92
116
  observer = get_observer(args.config)
93
117
  target = args.target if args.target.startswith("#") else f"#{args.target}"
94
118
  asyncio.run(observer.send_message(target, args.text))
@@ -96,6 +120,9 @@ def _cmd_message(args: argparse.Namespace) -> None:
96
120
 
97
121
 
98
122
  def _cmd_who(args: argparse.Namespace) -> None:
123
+ if not args.target.strip():
124
+ print("Error: channel name cannot be empty", file=sys.stderr)
125
+ sys.exit(1)
99
126
  observer = get_observer(args.config)
100
127
  target = args.target
101
128
  nicks = asyncio.run(observer.who(target))
@@ -1,4 +1,4 @@
1
- """Server subcommands: culture server {start,stop,status,default,rename}."""
1
+ """Server subcommands: culture server {start,stop,status,default,rename,archive,unarchive}."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -14,6 +14,7 @@ import time
14
14
  from culture.pidfile import (
15
15
  is_culture_process,
16
16
  is_process_alive,
17
+ read_default_server,
17
18
  read_pid,
18
19
  remove_pid,
19
20
  write_pid,
@@ -32,13 +33,22 @@ logger = logging.getLogger("culture")
32
33
 
33
34
  NAME = "server"
34
35
 
36
+ _DEFAULT_SERVER = "culture"
37
+
38
+
39
+ def _resolve_server_name(args: argparse.Namespace) -> str:
40
+ """Resolve the server name from args, default server file, or fallback."""
41
+ if args.name is not None:
42
+ return args.name
43
+ return read_default_server() or _DEFAULT_SERVER
44
+
35
45
 
36
46
  def register(subparsers: argparse._SubParsersAction) -> None:
37
47
  server_parser = subparsers.add_parser("server", help="Manage the IRC server")
38
48
  server_sub = server_parser.add_subparsers(dest="server_command")
39
49
 
40
50
  srv_start = server_sub.add_parser("start", help="Start the IRC server daemon")
41
- srv_start.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
51
+ srv_start.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
42
52
  srv_start.add_argument("--host", default="0.0.0.0", help="Listen address")
43
53
  srv_start.add_argument("--port", type=int, default=6667, help="Listen port")
44
54
  srv_start.add_argument(
@@ -66,10 +76,10 @@ def register(subparsers: argparse._SubParsersAction) -> None:
66
76
  )
67
77
 
68
78
  srv_stop = server_sub.add_parser("stop", help="Stop the IRC server daemon")
69
- srv_stop.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
79
+ srv_stop.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
70
80
 
71
81
  srv_status = server_sub.add_parser("status", help="Check server daemon status")
72
- srv_status.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
82
+ srv_status.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
73
83
 
74
84
  srv_default = server_sub.add_parser("default", help="Set default server")
75
85
  srv_default.add_argument("name", help="Server name to set as default")
@@ -87,7 +97,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
87
97
  srv_archive = server_sub.add_parser(
88
98
  "archive", help="Archive the server and all its agents/bots"
89
99
  )
90
- srv_archive.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
100
+ srv_archive.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
91
101
  srv_archive.add_argument("--reason", default="", help="Reason for archiving")
92
102
  srv_archive.add_argument(
93
103
  "--config",
@@ -98,7 +108,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
98
108
  srv_unarchive = server_sub.add_parser(
99
109
  "unarchive", help="Restore an archived server and all its agents/bots"
100
110
  )
101
- srv_unarchive.add_argument("--name", default="culture", help=_SERVER_NAME_HELP)
111
+ srv_unarchive.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
102
112
  srv_unarchive.add_argument(
103
113
  "--config",
104
114
  default=DEFAULT_CONFIG,
@@ -114,6 +124,10 @@ def dispatch(args: argparse.Namespace) -> None:
114
124
  )
115
125
  sys.exit(1)
116
126
 
127
+ # Resolve --name for commands that use it (all except default/rename)
128
+ if args.server_command not in ("default", "rename") and hasattr(args, "name"):
129
+ args.name = _resolve_server_name(args)
130
+
117
131
  if args.server_command == "start":
118
132
  _server_start(args)
119
133
  elif args.server_command == "stop":
@@ -121,8 +135,40 @@ def dispatch(args: argparse.Namespace) -> None:
121
135
  elif args.server_command == "status":
122
136
  _server_status(args)
123
137
  elif args.server_command == "default":
124
- from culture.pidfile import write_default_server
138
+ from pathlib import Path
139
+
140
+ from culture.pidfile import PID_DIR, list_servers, write_default_server
125
141
 
142
+ from .shared.constants import DEFAULT_CONFIG
143
+
144
+ # Accept the name if: it matches a running server, has a PID file,
145
+ # or matches the configured server name.
146
+ known_running = {s["name"] for s in list_servers()}
147
+ pid_dir = Path(PID_DIR)
148
+ known_pids = set()
149
+ if pid_dir.exists():
150
+ prefix = "server-"
151
+ for p in pid_dir.glob(f"{prefix}*.pid"):
152
+ known_pids.add(p.stem[len(prefix) :])
153
+ known_names = known_running | known_pids
154
+
155
+ # Also accept the configured server name
156
+ try:
157
+ from culture.clients.claude.config import load_config_or_default
158
+
159
+ config = load_config_or_default(DEFAULT_CONFIG)
160
+ known_names.add(config.server.name)
161
+ except Exception:
162
+ pass
163
+
164
+ if args.name not in known_names:
165
+ print(f"Server '{args.name}' not found.", file=sys.stderr)
166
+ if known_names:
167
+ print(
168
+ f"Known servers: {', '.join(sorted(known_names))}",
169
+ file=sys.stderr,
170
+ )
171
+ sys.exit(1)
126
172
  write_default_server(args.name)
127
173
  print(f"Default server set to '{args.name}'")
128
174
  elif args.server_command == "rename":
@@ -0,0 +1,5 @@
1
+ """Re-export formatting utilities from culture.formatting."""
2
+
3
+ from culture.formatting import relative_time
4
+
5
+ __all__ = ["relative_time"]
@@ -175,7 +175,7 @@ def add_agent_to_config(
175
175
  # Check for nick collision
176
176
  for existing in config.agents:
177
177
  if existing.nick == agent.nick:
178
- raise ValueError(f"agent with nick {agent.nick!r} already exists in config")
178
+ raise ValueError(f"Agent with nick {agent.nick!r} already exists in config")
179
179
 
180
180
  config.agents.append(agent)
181
181
  save_config(path, config)
@@ -238,7 +238,7 @@ def rename_agent(
238
238
  # Check new nick doesn't collide
239
239
  for agent in config.agents:
240
240
  if agent.nick == new_nick:
241
- raise ValueError(f"agent with nick {new_nick!r} already exists in config")
241
+ raise ValueError(f"Agent with nick {new_nick!r} already exists in config")
242
242
 
243
243
  # Find and rename
244
244
  for agent in config.agents:
@@ -247,7 +247,7 @@ def rename_agent(
247
247
  save_config(path, config)
248
248
  return
249
249
 
250
- raise ValueError(f"agent {old_nick!r} not found in config")
250
+ raise ValueError(f"Agent {old_nick!r} not found in config")
251
251
 
252
252
 
253
253
  def remove_agent(
@@ -262,7 +262,7 @@ def remove_agent(
262
262
  """
263
263
  path = Path(path)
264
264
  if not path.exists():
265
- raise ValueError(f"agent {nick!r} not found in config")
265
+ raise ValueError(f"Agent {nick!r} not found in config")
266
266
 
267
267
  with open(path) as f:
268
268
  raw = yaml.safe_load(f) or {}
@@ -274,4 +274,4 @@ def remove_agent(
274
274
  with open(path, "w") as f:
275
275
  yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
276
276
  return
277
- raise ValueError(f"agent {nick!r} not found in config")
277
+ raise ValueError(f"Agent {nick!r} not found in config")
@@ -185,7 +185,7 @@ def add_agent_to_config(
185
185
  # Check for nick collision
186
186
  for existing in config.agents:
187
187
  if existing.nick == agent.nick:
188
- raise ValueError(f"agent with nick {agent.nick!r} already exists in config")
188
+ raise ValueError(f"Agent with nick {agent.nick!r} already exists in config")
189
189
 
190
190
  config.agents.append(agent)
191
191
  save_config(path, config)
@@ -248,7 +248,7 @@ def rename_agent(
248
248
  # Check new nick doesn't collide
249
249
  for agent in config.agents:
250
250
  if agent.nick == new_nick:
251
- raise ValueError(f"agent with nick {new_nick!r} already exists in config")
251
+ raise ValueError(f"Agent with nick {new_nick!r} already exists in config")
252
252
 
253
253
  # Find and rename
254
254
  for agent in config.agents:
@@ -257,7 +257,7 @@ def rename_agent(
257
257
  save_config(path, config)
258
258
  return
259
259
 
260
- raise ValueError(f"agent {old_nick!r} not found in config")
260
+ raise ValueError(f"Agent {old_nick!r} not found in config")
261
261
 
262
262
 
263
263
  def archive_agent(
@@ -279,7 +279,7 @@ def archive_agent(
279
279
  agent.archived_reason = reason
280
280
  save_config(path, config)
281
281
  return
282
- raise ValueError(f"agent {nick!r} not found in config")
282
+ raise ValueError(f"Agent {nick!r} not found in config")
283
283
 
284
284
 
285
285
  def unarchive_agent(
@@ -294,13 +294,13 @@ def unarchive_agent(
294
294
  for agent in config.agents:
295
295
  if agent.nick == nick:
296
296
  if not agent.archived:
297
- raise ValueError(f"agent {nick!r} is not archived")
297
+ raise ValueError(f"Agent {nick!r} is not archived")
298
298
  agent.archived = False
299
299
  agent.archived_at = ""
300
300
  agent.archived_reason = ""
301
301
  save_config(path, config)
302
302
  return
303
- raise ValueError(f"agent {nick!r} not found in config")
303
+ raise ValueError(f"Agent {nick!r} not found in config")
304
304
 
305
305
 
306
306
  def remove_agent(
@@ -315,7 +315,7 @@ def remove_agent(
315
315
  """
316
316
  path = Path(path)
317
317
  if not path.exists():
318
- raise ValueError(f"agent {nick!r} not found in config")
318
+ raise ValueError(f"Agent {nick!r} not found in config")
319
319
 
320
320
  with open(path) as f:
321
321
  raw = yaml.safe_load(f) or {}
@@ -327,7 +327,7 @@ def remove_agent(
327
327
  with open(path, "w") as f:
328
328
  yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
329
329
  return
330
- raise ValueError(f"agent {nick!r} not found in config")
330
+ raise ValueError(f"Agent {nick!r} not found in config")
331
331
 
332
332
 
333
333
  def archive_server(
@@ -175,7 +175,7 @@ def add_agent_to_config(
175
175
  # Check for nick collision
176
176
  for existing in config.agents:
177
177
  if existing.nick == agent.nick:
178
- raise ValueError(f"agent with nick {agent.nick!r} already exists in config")
178
+ raise ValueError(f"Agent with nick {agent.nick!r} already exists in config")
179
179
 
180
180
  config.agents.append(agent)
181
181
  save_config(path, config)
@@ -238,7 +238,7 @@ def rename_agent(
238
238
  # Check new nick doesn't collide
239
239
  for agent in config.agents:
240
240
  if agent.nick == new_nick:
241
- raise ValueError(f"agent with nick {new_nick!r} already exists in config")
241
+ raise ValueError(f"Agent with nick {new_nick!r} already exists in config")
242
242
 
243
243
  # Find and rename
244
244
  for agent in config.agents:
@@ -247,7 +247,7 @@ def rename_agent(
247
247
  save_config(path, config)
248
248
  return
249
249
 
250
- raise ValueError(f"agent {old_nick!r} not found in config")
250
+ raise ValueError(f"Agent {old_nick!r} not found in config")
251
251
 
252
252
 
253
253
  def remove_agent(
@@ -262,7 +262,7 @@ def remove_agent(
262
262
  """
263
263
  path = Path(path)
264
264
  if not path.exists():
265
- raise ValueError(f"agent {nick!r} not found in config")
265
+ raise ValueError(f"Agent {nick!r} not found in config")
266
266
 
267
267
  with open(path) as f:
268
268
  raw = yaml.safe_load(f) or {}
@@ -274,4 +274,4 @@ def remove_agent(
274
274
  with open(path, "w") as f:
275
275
  yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
276
276
  return
277
- raise ValueError(f"agent {nick!r} not found in config")
277
+ raise ValueError(f"Agent {nick!r} not found in config")
@@ -175,7 +175,7 @@ def add_agent_to_config(
175
175
  # Check for nick collision
176
176
  for existing in config.agents:
177
177
  if existing.nick == agent.nick:
178
- raise ValueError(f"agent with nick {agent.nick!r} already exists in config")
178
+ raise ValueError(f"Agent with nick {agent.nick!r} already exists in config")
179
179
 
180
180
  config.agents.append(agent)
181
181
  save_config(path, config)
@@ -238,7 +238,7 @@ def rename_agent(
238
238
  # Check new nick doesn't collide
239
239
  for agent in config.agents:
240
240
  if agent.nick == new_nick:
241
- raise ValueError(f"agent with nick {new_nick!r} already exists in config")
241
+ raise ValueError(f"Agent with nick {new_nick!r} already exists in config")
242
242
 
243
243
  # Find and rename
244
244
  for agent in config.agents:
@@ -247,7 +247,7 @@ def rename_agent(
247
247
  save_config(path, config)
248
248
  return
249
249
 
250
- raise ValueError(f"agent {old_nick!r} not found in config")
250
+ raise ValueError(f"Agent {old_nick!r} not found in config")
251
251
 
252
252
 
253
253
  def remove_agent(
@@ -262,7 +262,7 @@ def remove_agent(
262
262
  """
263
263
  path = Path(path)
264
264
  if not path.exists():
265
- raise ValueError(f"agent {nick!r} not found in config")
265
+ raise ValueError(f"Agent {nick!r} not found in config")
266
266
 
267
267
  with open(path) as f:
268
268
  raw = yaml.safe_load(f) or {}
@@ -274,4 +274,4 @@ def remove_agent(
274
274
  with open(path, "w") as f:
275
275
  yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
276
276
  return
277
- raise ValueError(f"agent {nick!r} not found in config")
277
+ raise ValueError(f"Agent {nick!r} not found in config")
@@ -0,0 +1,19 @@
1
+ """Shared formatting utilities used across culture modules."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+
7
+
8
+ def relative_time(timestamp: float) -> str:
9
+ """Format a Unix timestamp as relative time (e.g., '2m ago', '1h ago')."""
10
+ delta = int(time.time() - timestamp)
11
+ if delta < 0:
12
+ return "just now"
13
+ if delta < 60:
14
+ return f"{delta}s ago"
15
+ if delta < 3600:
16
+ return f"{delta // 60}m ago"
17
+ if delta < 86400:
18
+ return f"{delta // 3600}h ago"
19
+ return f"{delta // 86400}d ago"
@@ -167,11 +167,17 @@ class IRCObserver:
167
167
 
168
168
  @staticmethod
169
169
  def _parse_history_line(msg):
170
+ from culture.formatting import relative_time
171
+
170
172
  if msg.command != "HISTORY":
171
173
  return None
172
174
  if len(msg.params) >= 4:
173
175
  entry_nick, ts, text = msg.params[1], msg.params[2], msg.params[3]
174
- return f"[{ts}] <{entry_nick}> {text}"
176
+ try:
177
+ label = relative_time(float(ts))
178
+ except (ValueError, TypeError):
179
+ label = ts
180
+ return f"[{label}] <{entry_nick}> {text}"
175
181
  if len(msg.params) >= 3:
176
182
  return f"<{msg.params[1]}> {msg.params[2]}"
177
183
  return None
@@ -2,23 +2,11 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import time
5
+ from culture.formatting import relative_time as _relative_time
6
6
 
7
7
  from .model import Agent, MeshState, Message, Room
8
8
 
9
9
 
10
- def _relative_time(timestamp: float) -> str:
11
- """Format a timestamp as relative time (e.g., '2m ago', '1h ago')."""
12
- delta = int(time.time() - timestamp)
13
- if delta < 60:
14
- return f"{delta}s ago"
15
- if delta < 3600:
16
- return f"{delta // 60}m ago"
17
- if delta < 86400:
18
- return f"{delta // 3600}h ago"
19
- return f"{delta // 86400}d ago"
20
-
21
-
22
10
  def _escape_cell(text: str) -> str:
23
11
  """Escape pipe and newline characters for markdown table cells."""
24
12
  return text.replace("|", "\\|").replace("\n", " ")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentirc-cli"
3
- version = "4.3.5"
3
+ version = "4.3.6"
4
4
  description = "Legacy alias for culture — install culture instead"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -561,7 +561,7 @@ wheels = [
561
561
 
562
562
  [[package]]
563
563
  name = "culture"
564
- version = "4.3.5"
564
+ version = "4.3.6"
565
565
  source = { editable = "." }
566
566
  dependencies = [
567
567
  { name = "aiohttp" },
File without changes