agentirc-cli 3.0.1__tar.gz → 3.0.2__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 (294) hide show
  1. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/CHANGELOG.md +8 -0
  2. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/CLAUDE.md +1 -1
  3. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/PKG-INFO +1 -1
  4. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/cli.py +67 -12
  5. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/ircd.py +20 -6
  6. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/pyproject.toml +1 -1
  7. agentirc_cli-3.0.2/tests/test_wait_for_port.py +89 -0
  8. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/uv.lock +1 -1
  9. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.claude/skills/pr-review/SKILL.md +0 -0
  10. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.claude/skills/run-tests/SKILL.md +0 -0
  11. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.claude/skills/run-tests/scripts/test.sh +0 -0
  12. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.flake8 +0 -0
  13. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.github/workflows/pages.yml +0 -0
  14. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.github/workflows/publish.yml +0 -0
  15. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.github/workflows/security-checks.yml +0 -0
  16. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.github/workflows/tests.yml +0 -0
  17. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.gitignore +0 -0
  18. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.markdownlint-cli2.yaml +0 -0
  19. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.pr_agent.toml +0 -0
  20. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.pre-commit-config.yaml +0 -0
  21. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/.pylintrc +0 -0
  22. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/CNAME +0 -0
  23. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/Gemfile +0 -0
  24. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/Gemfile.lock +0 -0
  25. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/LICENSE +0 -0
  26. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/README.md +0 -0
  27. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/SECURITY.md +0 -0
  28. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/_config.yml +0 -0
  29. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/_sass/color_schemes/anthropic.scss +0 -0
  30. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/_sass/custom/custom.scss +0 -0
  31. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/__init__.py +0 -0
  32. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/__main__.py +0 -0
  33. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/bots/__init__.py +0 -0
  34. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/bots/bot.py +0 -0
  35. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/bots/bot_manager.py +0 -0
  36. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/bots/config.py +0 -0
  37. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/bots/http_listener.py +0 -0
  38. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/bots/template_engine.py +0 -0
  39. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/bots/virtual_client.py +0 -0
  40. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/__init__.py +0 -0
  41. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/__init__.py +0 -0
  42. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/agent_runner.py +0 -0
  43. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/config.py +0 -0
  44. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/daemon.py +0 -0
  45. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/ipc.py +0 -0
  46. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/irc_transport.py +0 -0
  47. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/message_buffer.py +0 -0
  48. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/skill/SKILL.md +0 -0
  49. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/skill/__init__.py +0 -0
  50. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/skill/irc_client.py +0 -0
  51. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/socket_server.py +0 -0
  52. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/supervisor.py +0 -0
  53. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/acp/webhook.py +0 -0
  54. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/__init__.py +0 -0
  55. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/__main__.py +0 -0
  56. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/agent_runner.py +0 -0
  57. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/config.py +0 -0
  58. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/daemon.py +0 -0
  59. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/ipc.py +0 -0
  60. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/irc_transport.py +0 -0
  61. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/message_buffer.py +0 -0
  62. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/skill/SKILL.md +0 -0
  63. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/skill/__init__.py +0 -0
  64. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/skill/irc_client.py +0 -0
  65. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/socket_server.py +0 -0
  66. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/supervisor.py +0 -0
  67. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/claude/webhook.py +0 -0
  68. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/__init__.py +0 -0
  69. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/agent_runner.py +0 -0
  70. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/config.py +0 -0
  71. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/daemon.py +0 -0
  72. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/ipc.py +0 -0
  73. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/irc_transport.py +0 -0
  74. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/message_buffer.py +0 -0
  75. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/skill/SKILL.md +0 -0
  76. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/skill/__init__.py +0 -0
  77. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/skill/irc_client.py +0 -0
  78. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/socket_server.py +0 -0
  79. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/supervisor.py +0 -0
  80. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/codex/webhook.py +0 -0
  81. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/__init__.py +0 -0
  82. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/agent_runner.py +0 -0
  83. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/config.py +0 -0
  84. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/daemon.py +0 -0
  85. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/ipc.py +0 -0
  86. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/irc_transport.py +0 -0
  87. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/message_buffer.py +0 -0
  88. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/skill/SKILL.md +0 -0
  89. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/skill/__init__.py +0 -0
  90. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/skill/irc_client.py +0 -0
  91. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/socket_server.py +0 -0
  92. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/supervisor.py +0 -0
  93. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/clients/copilot/webhook.py +0 -0
  94. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/__init__.py +0 -0
  95. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/app.py +0 -0
  96. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/client.py +0 -0
  97. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/commands.py +0 -0
  98. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/widgets/__init__.py +0 -0
  99. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/widgets/chat.py +0 -0
  100. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/widgets/info_panel.py +0 -0
  101. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/console/widgets/sidebar.py +0 -0
  102. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/credentials.py +0 -0
  103. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/learn_prompt.py +0 -0
  104. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/mesh_config.py +0 -0
  105. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/observer.py +0 -0
  106. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/overview/__init__.py +0 -0
  107. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/overview/collector.py +0 -0
  108. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/overview/model.py +0 -0
  109. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/overview/renderer_text.py +0 -0
  110. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/overview/renderer_web.py +0 -0
  111. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/overview/web/style.css +0 -0
  112. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/persistence.py +0 -0
  113. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/pidfile.py +0 -0
  114. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/__init__.py +0 -0
  115. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/commands.py +0 -0
  116. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/extensions/federation.md +0 -0
  117. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/extensions/history.md +0 -0
  118. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/extensions/icons.md +0 -0
  119. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/extensions/rooms.md +0 -0
  120. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/extensions/tags.md +0 -0
  121. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/extensions/threads.md +0 -0
  122. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/message.py +0 -0
  123. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/protocol-index.md +0 -0
  124. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/protocol/replies.py +0 -0
  125. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/__init__.py +0 -0
  126. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/__main__.py +0 -0
  127. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/channel.py +0 -0
  128. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/client.py +0 -0
  129. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/config.py +0 -0
  130. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/remote_client.py +0 -0
  131. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/room_store.py +0 -0
  132. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/rooms_util.py +0 -0
  133. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/server_link.py +0 -0
  134. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/skill.py +0 -0
  135. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/skills/__init__.py +0 -0
  136. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/skills/history.py +0 -0
  137. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/skills/icon.py +0 -0
  138. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/skills/rooms.py +0 -0
  139. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/skills/threads.py +0 -0
  140. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/server/thread_store.py +0 -0
  141. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/culture/skills/culture/SKILL.md +0 -0
  142. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/agent-lifecycle.md +0 -0
  143. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/agentic-self-learn.md +0 -0
  144. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/agent-client.md +0 -0
  145. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/agent-harness-spec.md +0 -0
  146. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/design.md +0 -0
  147. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/harness-conformance.md +0 -0
  148. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/index.md +0 -0
  149. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/layer1-core-irc.md +0 -0
  150. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/layer2-attention.md +0 -0
  151. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/layer3-skills.md +0 -0
  152. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/layer4-federation.md +0 -0
  153. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/layer5-agent-harness.md +0 -0
  154. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/server-architecture.md +0 -0
  155. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/architecture/threads.md +0 -0
  156. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/acp/overview.md +0 -0
  157. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/claude/configuration.md +0 -0
  158. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/claude/context-management.md +0 -0
  159. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/claude/irc-tools.md +0 -0
  160. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/claude/overview.md +0 -0
  161. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/claude/setup.md +0 -0
  162. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/claude/supervisor.md +0 -0
  163. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/claude/webhooks.md +0 -0
  164. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/codex/configuration.md +0 -0
  165. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/codex/context-management.md +0 -0
  166. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/codex/irc-tools.md +0 -0
  167. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/codex/overview.md +0 -0
  168. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/codex/setup.md +0 -0
  169. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/codex/supervisor.md +0 -0
  170. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/codex/webhooks.md +0 -0
  171. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/copilot/configuration.md +0 -0
  172. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/copilot/context-management.md +0 -0
  173. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/copilot/irc-tools.md +0 -0
  174. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/copilot/overview.md +0 -0
  175. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/copilot/setup.md +0 -0
  176. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/copilot/supervisor.md +0 -0
  177. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/clients/copilot/webhooks.md +0 -0
  178. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/culture-cli.md +0 -0
  179. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/getting-started.md +0 -0
  180. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/index.md +0 -0
  181. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/SECURITY.md +0 -0
  182. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/bots.md +0 -0
  183. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/ci.md +0 -0
  184. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/cli.md +0 -0
  185. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/docs-site.md +0 -0
  186. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/index.md +0 -0
  187. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/ops-tooling.md +0 -0
  188. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/overview.md +0 -0
  189. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/operations/publishing.md +0 -0
  190. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  191. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/rooms.md +0 -0
  192. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  193. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  194. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  195. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  196. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  197. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  198. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  199. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  200. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  201. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  202. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  203. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  204. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  205. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  206. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  207. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  208. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  209. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  210. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  211. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  212. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/01-pair-programming.md +0 -0
  213. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/02-code-review-ensemble.md +0 -0
  214. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/03-cross-server-delegation.md +0 -0
  215. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/04-knowledge-propagation.md +0 -0
  216. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/05-the-observer.md +0 -0
  217. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/06-cross-server-ops.md +0 -0
  218. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/07-supervisor-intervention.md +0 -0
  219. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/08-apps-as-agents.md +0 -0
  220. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/09-research-swarm.md +0 -0
  221. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases/10-agent-lifecycle.md +0 -0
  222. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/use-cases-index.md +0 -0
  223. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/docs/what-is-culture.md +0 -0
  224. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/README.md +0 -0
  225. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/config.py +0 -0
  226. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/daemon.py +0 -0
  227. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/ipc.py +0 -0
  228. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/irc_transport.py +0 -0
  229. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/message_buffer.py +0 -0
  230. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/skill/SKILL.md +0 -0
  231. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/skill/irc_client.py +0 -0
  232. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/socket_server.py +0 -0
  233. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/packages/agent-harness/webhook.py +0 -0
  234. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  235. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  236. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  237. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  238. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/sonar-project.properties +0 -0
  239. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/__init__.py +0 -0
  240. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/conftest.py +0 -0
  241. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_acp_daemon.py +0 -0
  242. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_agent_runner.py +0 -0
  243. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_bot.py +0 -0
  244. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_bot_config.py +0 -0
  245. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_bot_manager.py +0 -0
  246. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_bots_integration.py +0 -0
  247. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_channel.py +0 -0
  248. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_codex_daemon.py +0 -0
  249. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_connection.py +0 -0
  250. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_console_client.py +0 -0
  251. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_console_commands.py +0 -0
  252. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_console_connection.py +0 -0
  253. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_console_icons.py +0 -0
  254. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_console_integration.py +0 -0
  255. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_copilot_daemon.py +0 -0
  256. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_daemon.py +0 -0
  257. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_daemon_config.py +0 -0
  258. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_daemon_ipc.py +0 -0
  259. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_discovery.py +0 -0
  260. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_federation.py +0 -0
  261. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_history.py +0 -0
  262. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_http_listener.py +0 -0
  263. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_integration_layer5.py +0 -0
  264. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_ipc.py +0 -0
  265. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_irc_transport.py +0 -0
  266. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_link_reconnect.py +0 -0
  267. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_mentions.py +0 -0
  268. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_mesh_config.py +0 -0
  269. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_message.py +0 -0
  270. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_message_buffer.py +0 -0
  271. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_messaging.py +0 -0
  272. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_modes.py +0 -0
  273. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_overview_cli.py +0 -0
  274. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_overview_collector.py +0 -0
  275. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_overview_model.py +0 -0
  276. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_overview_renderer.py +0 -0
  277. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_overview_web.py +0 -0
  278. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_persistence.py +0 -0
  279. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_pidfile.py +0 -0
  280. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_room_persistence.py +0 -0
  281. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_rooms.py +0 -0
  282. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_rooms_federation.py +0 -0
  283. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_rooms_integration.py +0 -0
  284. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_server_icon_skill.py +0 -0
  285. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_setup_update_cli.py +0 -0
  286. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_skill_client.py +0 -0
  287. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_skills.py +0 -0
  288. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_socket_server.py +0 -0
  289. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_supervisor.py +0 -0
  290. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_template_engine.py +0 -0
  291. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_thread_buffer.py +0 -0
  292. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_threads.py +0 -0
  293. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_virtual_client.py +0 -0
  294. {agentirc_cli-3.0.1 → agentirc_cli-3.0.2}/tests/test_webhook.py +0 -0
@@ -4,6 +4,14 @@ 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
+ ## [3.0.2] - 2026-04-06
8
+
9
+
10
+ ### Fixed
11
+
12
+ - Server startup readiness — culture server start now waits for port to accept connections before returning
13
+ - Added startup phase logging to server log for diagnosing slow starts
14
+
7
15
  ## [3.0.1] - 2026-04-06
8
16
 
9
17
 
@@ -42,7 +42,7 @@ When implementing features, write a corresponding markdown doc in `docs/` descri
42
42
 
43
43
  ## Testing
44
44
 
45
- - `pytest` + `pytest-asyncio`
45
+ - `pytest` + `pytest-asyncio`, always run with `-n auto` for parallel execution
46
46
  - No mocks for the server — tests spin up real server instances on random ports with real TCP connections
47
47
  - Validate each layer with real IRC clients (weechat/irssi)
48
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 3.0.1
3
+ Version: 3.0.2
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
@@ -29,6 +29,7 @@ import logging
29
29
  import os
30
30
  import shutil
31
31
  import signal
32
+ import socket
32
33
  import subprocess
33
34
  import sys
34
35
  import time
@@ -493,6 +494,39 @@ def _cmd_server(args: argparse.Namespace) -> None:
493
494
  print(f"Default server set to '{args.name}'")
494
495
 
495
496
 
497
+ def _wait_for_port(
498
+ host: str,
499
+ port: int,
500
+ pid: int,
501
+ timeout: float = 30,
502
+ ) -> tuple[bool, str]:
503
+ """Poll *host*:*port* until a TCP connect succeeds or *timeout* expires.
504
+
505
+ Returns ``(True, "")`` on success, or ``(False, reason)`` on failure.
506
+ Checks that *pid* is still alive on every iteration so we fail fast if
507
+ the child crashes (e.g. because the port was already in use).
508
+ """
509
+ check_host = "127.0.0.1" if host == "0.0.0.0" else host
510
+ deadline = time.monotonic() + timeout
511
+ while time.monotonic() < deadline:
512
+ if not is_process_alive(pid):
513
+ return False, "failed to start"
514
+ try:
515
+ s = socket.create_connection((check_host, port), timeout=0.5)
516
+ s.close()
517
+ except OSError:
518
+ time.sleep(0.2)
519
+ continue
520
+ # Port responded — give the child a moment, then confirm it's
521
+ # still alive (guards against connecting to a *stale* listener
522
+ # on the same port while our child crashes).
523
+ time.sleep(0.1)
524
+ if not is_process_alive(pid):
525
+ return False, "failed to start"
526
+ return True, ""
527
+ return False, "started but not yet accepting connections"
528
+
529
+
496
530
  def _server_start(args: argparse.Namespace) -> None:
497
531
  pid_name = f"server-{args.name}"
498
532
 
@@ -532,19 +566,33 @@ def _server_start(args: argparse.Namespace) -> None:
532
566
  # Fork to daemonize
533
567
  pid = os.fork()
534
568
  if pid > 0:
535
- time.sleep(0.2)
536
- if is_process_alive(pid):
537
- print(f"Server '{args.name}' started (PID {pid})")
538
- print(f" Listening on {args.host}:{args.port}")
539
- print(f" Logs: {LOG_DIR}/server-{args.name}.log")
540
- # Auto-set default server if none is set
541
- from culture.pidfile import read_default_server, write_default_server
542
-
543
- if read_default_server() is None:
544
- write_default_server(args.name)
569
+ log_hint = f"{LOG_DIR}/server-{args.name}.log"
570
+
571
+ if args.port == 0:
572
+ # Ephemeral port — can't probe; fall back to process-alive check
573
+ time.sleep(0.5)
574
+ if not is_process_alive(pid):
575
+ print(f"Server '{args.name}' failed to start", file=sys.stderr)
576
+ print(f" Check logs: {log_hint}", file=sys.stderr)
577
+ sys.exit(1)
545
578
  else:
546
- print(f"Server '{args.name}' failed to start", file=sys.stderr)
547
- sys.exit(1)
579
+ ok, err = _wait_for_port(args.host, args.port, pid, timeout=30)
580
+ if not ok:
581
+ print(
582
+ f"Server '{args.name}' {err}",
583
+ file=sys.stderr,
584
+ )
585
+ print(f" Check logs: {log_hint}", file=sys.stderr)
586
+ sys.exit(1)
587
+
588
+ print(f"Server '{args.name}' started (PID {pid})")
589
+ print(f" Listening on {args.host}:{args.port}")
590
+ print(f" Logs: {log_hint}")
591
+ # Auto-set default server if none is set
592
+ from culture.pidfile import read_default_server, write_default_server
593
+
594
+ if read_default_server() is None:
595
+ write_default_server(args.name)
548
596
  return
549
597
 
550
598
  # Child: detach from parent session
@@ -562,6 +610,13 @@ def _server_start(args: argparse.Namespace) -> None:
562
610
  os.dup2(devnull, 0)
563
611
  os.close(devnull)
564
612
 
613
+ # Reconfigure logging so handlers write to the redirected stderr (log file)
614
+ logging.basicConfig(
615
+ level=logging.INFO,
616
+ format="%(asctime)s %(name)s %(levelname)s %(message)s",
617
+ force=True,
618
+ )
619
+
565
620
  write_pid(pid_name, os.getpid())
566
621
 
567
622
  try:
@@ -10,6 +10,8 @@ from culture.server.channel import Channel
10
10
  from culture.server.config import ServerConfig
11
11
  from culture.server.skill import Event, Skill
12
12
 
13
+ logger = logging.getLogger(__name__)
14
+
13
15
  if TYPE_CHECKING:
14
16
  from culture.bots.virtual_client import VirtualClient
15
17
  from culture.server.client import Client
@@ -41,16 +43,25 @@ class IRCd:
41
43
  self.bot_manager = None # set in start() if webhook_port configured
42
44
 
43
45
  async def start(self) -> None:
46
+ logger.info("Registering default skills...")
44
47
  await self._register_default_skills()
48
+
49
+ logger.info("Restoring persistent rooms...")
45
50
  self._restore_persistent_rooms()
46
51
 
47
52
  # Initialize bot manager and webhook HTTP listener
48
53
  from culture.bots.bot_manager import BotManager
49
54
  from culture.bots.http_listener import HttpListener
50
55
 
56
+ logger.info("Loading bots...")
51
57
  self.bot_manager = BotManager(self)
52
58
  await self.bot_manager.load_bots()
53
59
 
60
+ logger.info(
61
+ "Binding IRC socket on %s:%d...",
62
+ self.config.host,
63
+ self.config.port,
64
+ )
54
65
  self._server = await asyncio.start_server(
55
66
  self._handle_connection,
56
67
  self.config.host,
@@ -63,16 +74,22 @@ class IRCd:
63
74
  self.config.webhook_port,
64
75
  )
65
76
  try:
77
+ logger.info(
78
+ "Starting webhook listener on port %d...",
79
+ self.config.webhook_port,
80
+ )
66
81
  await self._http_listener.start()
67
82
  except OSError:
68
83
  # Port unavailable (e.g. in tests using port 0 that got
69
84
  # assigned an in-use ephemeral port). Non-fatal — bots
70
85
  # still work, just without the HTTP endpoint.
71
- logging.getLogger(__name__).warning(
86
+ logger.warning(
72
87
  "Could not start webhook listener on port %d",
73
88
  self.config.webhook_port,
74
89
  )
75
90
 
91
+ logger.info("Server ready")
92
+
76
93
  async def _register_default_skills(self) -> None:
77
94
  from culture.server.skills.history import HistorySkill
78
95
  from culture.server.skills.icon import IconSkill
@@ -101,9 +118,7 @@ class IRCd:
101
118
  try:
102
119
  await skill.on_event(event)
103
120
  except Exception:
104
- logging.getLogger(__name__).exception(
105
- "Skill %s failed on event %s", skill.name, event.type
106
- )
121
+ logger.exception("Skill %s failed on event %s", skill.name, event.type)
107
122
 
108
123
  # Relay to linked peers — only relay locally-originated events
109
124
  # (no mesh routing; scope is direct peers only)
@@ -112,7 +127,7 @@ class IRCd:
112
127
  try:
113
128
  await link.relay_event(event)
114
129
  except Exception:
115
- logging.getLogger(__name__).exception("Failed to relay event to %s", peer_name)
130
+ logger.exception("Failed to relay event to %s", peer_name)
116
131
 
117
132
  def get_skill_for_command(self, command: str) -> Skill | None:
118
133
  for skill in self.skills:
@@ -190,7 +205,6 @@ class IRCd:
190
205
 
191
206
  async def _retry_link_loop(self, peer_name: str, link_config, state: dict) -> None:
192
207
  """Retry connecting to a peer with exponential backoff."""
193
- logger = logging.getLogger(__name__)
194
208
  try:
195
209
  while True:
196
210
  await asyncio.sleep(state["delay"])
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentirc-cli"
3
- version = "3.0.1"
3
+ version = "3.0.2"
4
4
  description = "Legacy alias for culture — install culture instead"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -0,0 +1,89 @@
1
+ """Tests for the _wait_for_port readiness helper."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import socket
6
+ import threading
7
+ import time
8
+
9
+ from culture.cli import _wait_for_port
10
+
11
+
12
+ def _start_listener(port_holder: list, delay: float = 0) -> socket.socket:
13
+ """Start a TCP listener, optionally after *delay* seconds.
14
+
15
+ Stores the assigned port in *port_holder[0]*.
16
+ """
17
+ srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
18
+ srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
19
+
20
+ def _bind():
21
+ if delay:
22
+ time.sleep(delay)
23
+ srv.bind(("127.0.0.1", 0))
24
+ srv.listen(1)
25
+ port_holder.append(srv.getsockname()[1])
26
+
27
+ t = threading.Thread(target=_bind, daemon=True)
28
+ t.start()
29
+ t.join(timeout=delay + 2)
30
+ return srv
31
+
32
+
33
+ def test_success_immediate():
34
+ """Port already open — should return immediately."""
35
+ port_holder: list[int] = []
36
+ srv = _start_listener(port_holder)
37
+ try:
38
+ ok, err = _wait_for_port(
39
+ "127.0.0.1",
40
+ port_holder[0],
41
+ # Use our own PID (always alive)
42
+ pid=threading.current_thread().native_id or 1,
43
+ timeout=5,
44
+ )
45
+ assert ok
46
+ assert err == ""
47
+ finally:
48
+ srv.close()
49
+
50
+
51
+ def test_timeout_no_listener():
52
+ """No listener — should time out."""
53
+ # Bind then close to get a free port that nothing listens on
54
+ tmp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
55
+ tmp.bind(("127.0.0.1", 0))
56
+ port = tmp.getsockname()[1]
57
+ tmp.close()
58
+
59
+ import os
60
+
61
+ ok, err = _wait_for_port("127.0.0.1", port, pid=os.getpid(), timeout=1)
62
+ assert not ok
63
+ assert "not yet accepting connections" in err
64
+
65
+
66
+ def test_process_dies():
67
+ """Dead PID — should fail fast."""
68
+ import subprocess
69
+
70
+ # Spawn a process that exits immediately to get a dead PID
71
+ p = subprocess.Popen(["true"])
72
+ p.wait()
73
+
74
+ ok, err = _wait_for_port("127.0.0.1", 1, pid=p.pid, timeout=5)
75
+ assert not ok
76
+ assert "failed to start" in err
77
+
78
+
79
+ def test_host_0000_uses_localhost():
80
+ """0.0.0.0 host should probe 127.0.0.1."""
81
+ port_holder: list[int] = []
82
+ srv = _start_listener(port_holder)
83
+ try:
84
+ import os
85
+
86
+ ok, _ = _wait_for_port("0.0.0.0", port_holder[0], pid=os.getpid(), timeout=5)
87
+ assert ok
88
+ finally:
89
+ srv.close()
@@ -561,7 +561,7 @@ wheels = [
561
561
 
562
562
  [[package]]
563
563
  name = "culture"
564
- version = "3.0.1"
564
+ version = "3.0.2"
565
565
  source = { editable = "." }
566
566
  dependencies = [
567
567
  { name = "aiohttp" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes