agentirc-cli 0.17.0__tar.gz → 0.19.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/CHANGELOG.md +38 -0
  2. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/PKG-INFO +1 -1
  3. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/cli.py +435 -22
  4. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/daemon.py +89 -2
  5. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/irc_transport.py +12 -0
  6. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/message_buffer.py +20 -1
  7. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/daemon.py +89 -2
  8. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/irc_transport.py +12 -0
  9. {agentirc_cli-0.17.0/agentirc/clients/codex → agentirc_cli-0.19.0/agentirc/clients/claude}/message_buffer.py +20 -1
  10. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/daemon.py +89 -2
  11. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/irc_transport.py +12 -0
  12. {agentirc_cli-0.17.0/agentirc/clients/claude → agentirc_cli-0.19.0/agentirc/clients/codex}/message_buffer.py +20 -1
  13. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/daemon.py +89 -2
  14. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/irc_transport.py +12 -0
  15. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/message_buffer.py +20 -1
  16. agentirc_cli-0.19.0/agentirc/credentials.py +132 -0
  17. agentirc_cli-0.19.0/agentirc/mesh_config.py +94 -0
  18. agentirc_cli-0.19.0/agentirc/persistence.py +233 -0
  19. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/commands.py +8 -0
  20. agentirc_cli-0.19.0/agentirc/protocol/extensions/threads.md +296 -0
  21. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/ircd.py +95 -1
  22. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/server_link.py +94 -1
  23. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/skill.py +3 -0
  24. agentirc_cli-0.19.0/agentirc/server/skills/threads.py +598 -0
  25. agentirc_cli-0.19.0/agentirc/server/thread_store.py +50 -0
  26. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/skills/agentirc/SKILL.md +70 -0
  27. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/cli.md +53 -0
  28. agentirc_cli-0.19.0/docs/ops-tooling.md +271 -0
  29. agentirc_cli-0.19.0/docs/superpowers/plans/2026-04-02-conversation-threads.md +1885 -0
  30. agentirc_cli-0.19.0/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +326 -0
  31. agentirc_cli-0.19.0/docs/threads.md +200 -0
  32. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/daemon.py +96 -2
  33. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/irc_transport.py +12 -0
  34. agentirc_cli-0.19.0/packages/agent-harness/message_buffer.py +65 -0
  35. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/pyproject.toml +1 -1
  36. agentirc_cli-0.19.0/tests/test_link_reconnect.py +221 -0
  37. agentirc_cli-0.19.0/tests/test_mesh_config.py +89 -0
  38. agentirc_cli-0.19.0/tests/test_persistence.py +103 -0
  39. agentirc_cli-0.19.0/tests/test_setup_update_cli.py +42 -0
  40. agentirc_cli-0.19.0/tests/test_thread_buffer.py +56 -0
  41. agentirc_cli-0.19.0/tests/test_threads.py +383 -0
  42. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/uv.lock +1 -1
  43. agentirc_cli-0.17.0/packages/agent-harness/message_buffer.py +0 -46
  44. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/.claude/skills/pr-review/SKILL.md +0 -0
  45. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/.github/workflows/pages.yml +0 -0
  46. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/.github/workflows/publish.yml +0 -0
  47. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/.github/workflows/tests.yml +0 -0
  48. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/.gitignore +0 -0
  49. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/.markdownlint-cli2.yaml +0 -0
  50. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/.pr_agent.toml +0 -0
  51. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/CLAUDE.md +0 -0
  52. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/CNAME +0 -0
  53. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/Gemfile +0 -0
  54. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/Gemfile.lock +0 -0
  55. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/LICENSE +0 -0
  56. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/README.md +0 -0
  57. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/_config.yml +0 -0
  58. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/_sass/color_schemes/anthropic.scss +0 -0
  59. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/_sass/custom/custom.scss +0 -0
  60. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/__init__.py +0 -0
  61. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/__main__.py +0 -0
  62. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/__init__.py +0 -0
  63. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/__init__.py +0 -0
  64. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/agent_runner.py +0 -0
  65. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/config.py +0 -0
  66. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/ipc.py +0 -0
  67. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/skill/SKILL.md +0 -0
  68. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/skill/__init__.py +0 -0
  69. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/skill/irc_client.py +0 -0
  70. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/socket_server.py +0 -0
  71. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/supervisor.py +0 -0
  72. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/acp/webhook.py +0 -0
  73. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/__init__.py +0 -0
  74. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/__main__.py +0 -0
  75. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/agent_runner.py +0 -0
  76. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/config.py +0 -0
  77. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/ipc.py +0 -0
  78. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/skill/SKILL.md +0 -0
  79. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/skill/__init__.py +0 -0
  80. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/skill/irc_client.py +0 -0
  81. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/socket_server.py +0 -0
  82. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/supervisor.py +0 -0
  83. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/claude/webhook.py +0 -0
  84. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/__init__.py +0 -0
  85. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/agent_runner.py +0 -0
  86. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/config.py +0 -0
  87. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/ipc.py +0 -0
  88. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/skill/SKILL.md +0 -0
  89. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/skill/__init__.py +0 -0
  90. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/skill/irc_client.py +0 -0
  91. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/socket_server.py +0 -0
  92. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/supervisor.py +0 -0
  93. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/codex/webhook.py +0 -0
  94. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/__init__.py +0 -0
  95. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/agent_runner.py +0 -0
  96. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/config.py +0 -0
  97. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/ipc.py +0 -0
  98. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/skill/SKILL.md +0 -0
  99. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/skill/__init__.py +0 -0
  100. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/skill/irc_client.py +0 -0
  101. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/socket_server.py +0 -0
  102. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/supervisor.py +0 -0
  103. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/clients/copilot/webhook.py +0 -0
  104. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/learn_prompt.py +0 -0
  105. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/observer.py +0 -0
  106. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/overview/__init__.py +0 -0
  107. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/overview/collector.py +0 -0
  108. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/overview/model.py +0 -0
  109. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/overview/renderer_text.py +0 -0
  110. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/overview/renderer_web.py +0 -0
  111. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/overview/web/style.css +0 -0
  112. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/pidfile.py +0 -0
  113. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/__init__.py +0 -0
  114. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/extensions/federation.md +0 -0
  115. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/extensions/history.md +0 -0
  116. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/extensions/rooms.md +0 -0
  117. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/extensions/tags.md +0 -0
  118. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/message.py +0 -0
  119. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/protocol-index.md +0 -0
  120. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/protocol/replies.py +0 -0
  121. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/__init__.py +0 -0
  122. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/__main__.py +0 -0
  123. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/channel.py +0 -0
  124. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/client.py +0 -0
  125. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/config.py +0 -0
  126. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/remote_client.py +0 -0
  127. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/room_store.py +0 -0
  128. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/rooms_util.py +0 -0
  129. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/skills/__init__.py +0 -0
  130. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/skills/history.py +0 -0
  131. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/agentirc/server/skills/rooms.py +0 -0
  132. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/agent-client.md +0 -0
  133. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/agent-harness-spec.md +0 -0
  134. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/agentic-self-learn.md +0 -0
  135. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/ci.md +0 -0
  136. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/acp/overview.md +0 -0
  137. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/claude/configuration.md +0 -0
  138. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/claude/context-management.md +0 -0
  139. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/claude/irc-tools.md +0 -0
  140. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/claude/overview.md +0 -0
  141. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/claude/setup.md +0 -0
  142. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/claude/supervisor.md +0 -0
  143. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/claude/webhooks.md +0 -0
  144. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/codex/configuration.md +0 -0
  145. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/codex/context-management.md +0 -0
  146. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/codex/irc-tools.md +0 -0
  147. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/codex/overview.md +0 -0
  148. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/codex/setup.md +0 -0
  149. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/codex/supervisor.md +0 -0
  150. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/codex/webhooks.md +0 -0
  151. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/copilot/configuration.md +0 -0
  152. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/copilot/context-management.md +0 -0
  153. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/copilot/irc-tools.md +0 -0
  154. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/copilot/overview.md +0 -0
  155. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/copilot/setup.md +0 -0
  156. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/copilot/supervisor.md +0 -0
  157. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/clients/copilot/webhooks.md +0 -0
  158. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/codex-backend.md +0 -0
  159. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/copilot-backend.md +0 -0
  160. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/design.md +0 -0
  161. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/docs-site.md +0 -0
  162. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/getting-started.md +0 -0
  163. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/grow-your-agent.md +0 -0
  164. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/harness-conformance.md +0 -0
  165. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/layer1-core-irc.md +0 -0
  166. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/layer2-attention.md +0 -0
  167. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/layer3-skills.md +0 -0
  168. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/layer4-federation.md +0 -0
  169. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/layer5-agent-harness.md +0 -0
  170. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/overview.md +0 -0
  171. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/publishing.md +0 -0
  172. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  173. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/rooms.md +0 -0
  174. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/server-architecture.md +0 -0
  175. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  176. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  177. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  178. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  179. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  180. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  181. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  182. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  183. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/01-pair-programming.md +0 -0
  184. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/02-code-review-ensemble.md +0 -0
  185. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/03-cross-server-delegation.md +0 -0
  186. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/04-knowledge-propagation.md +0 -0
  187. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/05-the-observer.md +0 -0
  188. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/06-cross-server-ops.md +0 -0
  189. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/07-supervisor-intervention.md +0 -0
  190. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/08-apps-as-agents.md +0 -0
  191. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/09-research-swarm.md +0 -0
  192. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases/10-grow-your-agent.md +0 -0
  193. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/docs/use-cases-index.md +0 -0
  194. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/index.md +0 -0
  195. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/README.md +0 -0
  196. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/config.py +0 -0
  197. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/ipc.py +0 -0
  198. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/skill/SKILL.md +0 -0
  199. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/skill/irc_client.py +0 -0
  200. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/socket_server.py +0 -0
  201. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/packages/agent-harness/webhook.py +0 -0
  202. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  203. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/plugins/claude-code/skills/agentirc/SKILL.md +0 -0
  204. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  205. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/plugins/codex/skills/agentirc-irc/SKILL.md +0 -0
  206. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/__init__.py +0 -0
  207. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/conftest.py +0 -0
  208. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_acp_daemon.py +0 -0
  209. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_agent_runner.py +0 -0
  210. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_channel.py +0 -0
  211. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_codex_daemon.py +0 -0
  212. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_connection.py +0 -0
  213. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_copilot_daemon.py +0 -0
  214. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_daemon.py +0 -0
  215. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_daemon_config.py +0 -0
  216. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_daemon_ipc.py +0 -0
  217. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_discovery.py +0 -0
  218. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_federation.py +0 -0
  219. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_history.py +0 -0
  220. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_integration_layer5.py +0 -0
  221. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_ipc.py +0 -0
  222. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_irc_transport.py +0 -0
  223. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_mentions.py +0 -0
  224. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_message.py +0 -0
  225. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_message_buffer.py +0 -0
  226. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_messaging.py +0 -0
  227. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_modes.py +0 -0
  228. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_overview_cli.py +0 -0
  229. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_overview_collector.py +0 -0
  230. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_overview_model.py +0 -0
  231. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_overview_renderer.py +0 -0
  232. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_overview_web.py +0 -0
  233. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_room_persistence.py +0 -0
  234. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_rooms.py +0 -0
  235. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_rooms_federation.py +0 -0
  236. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_rooms_integration.py +0 -0
  237. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_skill_client.py +0 -0
  238. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_skills.py +0 -0
  239. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_socket_server.py +0 -0
  240. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_supervisor.py +0 -0
  241. {agentirc_cli-0.17.0 → agentirc_cli-0.19.0}/tests/test_webhook.py +0 -0
@@ -4,6 +4,44 @@ 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
+ ## [0.19.0] - 2026-04-03
8
+
9
+
10
+ ### Added
11
+
12
+ - Conversation threads — inline sub-conversations with [thread:name] prefix
13
+ - Breakout channel promotion from threads
14
+ - Thread-scoped agent context on @mention
15
+ - S2S federation for thread messages
16
+ - JSON persistence for threads across restarts
17
+ - Thread support in all 4 agent backends (claude, codex, copilot, acp)
18
+
19
+ ## [0.18.0] - 2026-04-03
20
+
21
+
22
+ ### Added
23
+
24
+ - Conversation threads — inline sub-conversations with [thread:name] prefix
25
+ - Breakout channel promotion from threads
26
+ - Thread-scoped agent context on @mention
27
+ - S2S federation for thread messages
28
+ - JSON persistence for threads across restarts
29
+ - Thread support in all 4 agent backends (claude, codex, copilot, acp)
30
+ - S2S link auto-reconnect with exponential backoff (5s to 120s)
31
+ - Declarative mesh.yaml configuration for multi-machine setup
32
+ - Cross-platform auto-start persistence (systemd, launchd, Windows schtasks)
33
+ - agentirc setup command — bootstrap a machine into the mesh from mesh.yaml
34
+ - agentirc update command — upgrade package and gracefully restart all services
35
+ - --foreground flag for server start and agent start (required by service managers)
36
+ - Windows platform support guards (no fork, SIGTERM fallback)
37
+
38
+
39
+ ### Changed
40
+
41
+ - S2S links now auto-retry on initial startup failure
42
+ - SQUIT (intentional delink) suppresses reconnect attempts
43
+ - Incoming peer connections cancel outbound retry tasks
44
+
7
45
  ## [0.17.0] - 2026-04-01
8
46
 
9
47
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 0.17.0
3
+ Version: 0.19.0
4
4
  Summary: 🌱 The space your agents deserve — an autonomous agent mesh where AI agents live, collaborate, and grow
5
5
  Project-URL: Homepage, https://github.com/OriNachum/agentirc
6
6
  Author: Ori Nachum
@@ -14,6 +14,8 @@ Subcommands:
14
14
  agentirc sleep [nick] [--all] Pause agent(s) — stay connected but idle
15
15
  agentirc wake [nick] [--all] Resume paused agent(s)
16
16
  agentirc overview [--room X] [--agent X] Show mesh overview
17
+ agentirc setup [--config X] [--uninstall] Set up mesh from mesh.yaml
18
+ agentirc update [--dry-run] [--skip-upgrade] Upgrade and restart mesh
17
19
  """
18
20
  from __future__ import annotations
19
21
 
@@ -22,7 +24,9 @@ import asyncio
22
24
  import json
23
25
  import logging
24
26
  import os
27
+ import shutil
25
28
  import signal
29
+ import subprocess
26
30
  import sys
27
31
  import time
28
32
 
@@ -92,6 +96,14 @@ def _build_parser() -> argparse.ArgumentParser:
92
96
  "--link", type=_parse_link, action="append", default=[],
93
97
  help="Link to peer: name:host:port:password",
94
98
  )
99
+ srv_start.add_argument(
100
+ "--mesh-config", default=None,
101
+ help="Read links from mesh.yaml + OS keyring (no passwords in CLI args)",
102
+ )
103
+ srv_start.add_argument(
104
+ "--foreground", action="store_true",
105
+ help="Run in foreground (for service managers)",
106
+ )
95
107
 
96
108
  srv_stop = server_sub.add_parser("stop", help="Stop the IRC server daemon")
97
109
  srv_stop.add_argument("--name", default="agentirc", help="Server name")
@@ -112,6 +124,10 @@ def _build_parser() -> argparse.ArgumentParser:
112
124
  start_parser.add_argument("nick", nargs="?", help="Agent nick to start")
113
125
  start_parser.add_argument("--all", action="store_true", help="Start all agents")
114
126
  start_parser.add_argument("--config", default=DEFAULT_CONFIG, help="Config file path")
127
+ start_parser.add_argument(
128
+ "--foreground", action="store_true",
129
+ help="Run in foreground (for service managers)",
130
+ )
115
131
 
116
132
  # -- stop subcommand ---------------------------------------------------
117
133
  stop_parser = sub.add_parser("stop", help="Stop agent daemon(s)")
@@ -181,6 +197,32 @@ def _build_parser() -> argparse.ArgumentParser:
181
197
  overview_parser.add_argument("--refresh", type=int, default=5, help="Web refresh interval in seconds (default: 5, min: 1)")
182
198
  overview_parser.add_argument("--config", default=DEFAULT_CONFIG)
183
199
 
200
+ # -- setup subcommand --------------------------------------------------
201
+ setup_parser = sub.add_parser("setup", help="Set up mesh from mesh.yaml")
202
+ setup_parser.add_argument(
203
+ "--config", default=os.path.expanduser("~/.agentirc/mesh.yaml"),
204
+ help="Path to mesh.yaml",
205
+ )
206
+ setup_parser.add_argument(
207
+ "--uninstall", action="store_true",
208
+ help="Remove auto-start entries and stop services",
209
+ )
210
+
211
+ # -- update subcommand -------------------------------------------------
212
+ update_parser = sub.add_parser("update", help="Upgrade and restart the mesh")
213
+ update_parser.add_argument(
214
+ "--dry-run", action="store_true",
215
+ help="Show what would happen without executing",
216
+ )
217
+ update_parser.add_argument(
218
+ "--skip-upgrade", action="store_true",
219
+ help="Just restart, don't upgrade the package",
220
+ )
221
+ update_parser.add_argument(
222
+ "--config", default=os.path.expanduser("~/.agentirc/mesh.yaml"),
223
+ help="Path to mesh.yaml",
224
+ )
225
+
184
226
  return parser
185
227
 
186
228
 
@@ -213,6 +255,8 @@ def main() -> None:
213
255
  "wake": _cmd_wake,
214
256
  "skills": _cmd_skills,
215
257
  "overview": _cmd_overview,
258
+ "setup": _cmd_setup,
259
+ "update": _cmd_update,
216
260
  }
217
261
  handler = dispatch.get(args.command)
218
262
  if handler:
@@ -253,10 +297,30 @@ def _server_start(args: argparse.Namespace) -> None:
253
297
  print(f"Server '{args.name}' is already running (PID {existing})")
254
298
  sys.exit(1)
255
299
 
300
+ # Resolve links: --mesh-config reads from mesh.yaml + OS keyring (no passwords in CLI)
301
+ links = list(args.link) # from --link args (may include passwords for manual use)
302
+ if getattr(args, "mesh_config", None):
303
+ links = _resolve_links_from_mesh(args.mesh_config)
304
+
305
+ if getattr(args, "foreground", False):
306
+ # Foreground mode — run directly (for service managers)
307
+ write_pid(pid_name, os.getpid())
308
+ os.makedirs(LOG_DIR, exist_ok=True)
309
+ print(f"Server '{args.name}' starting in foreground (PID {os.getpid()})")
310
+ print(f" Listening on {args.host}:{args.port}")
311
+ try:
312
+ asyncio.run(_run_server(args.name, args.host, args.port, links))
313
+ finally:
314
+ remove_pid(pid_name)
315
+ return
316
+
317
+ if sys.platform == "win32":
318
+ print("Daemon mode not supported on Windows. Use --foreground.", file=sys.stderr)
319
+ sys.exit(1)
320
+
256
321
  # Fork to daemonize
257
322
  pid = os.fork()
258
323
  if pid > 0:
259
- # Parent: wait briefly to check child started, then exit
260
324
  time.sleep(0.2)
261
325
  if is_process_alive(pid):
262
326
  print(f"Server '{args.name}' started (PID {pid})")
@@ -278,17 +342,14 @@ def _server_start(args: argparse.Namespace) -> None:
278
342
  os.dup2(log_fd, 2)
279
343
  os.close(log_fd)
280
344
 
281
- # Close stdin
282
345
  devnull = os.open(os.devnull, os.O_RDONLY)
283
346
  os.dup2(devnull, 0)
284
347
  os.close(devnull)
285
348
 
286
- # Write PID file
287
349
  write_pid(pid_name, os.getpid())
288
350
 
289
- # Run the server
290
351
  try:
291
- asyncio.run(_run_server(args.name, args.host, args.port, args.link))
352
+ asyncio.run(_run_server(args.name, args.host, args.port, links))
292
353
  finally:
293
354
  remove_pid(pid_name)
294
355
  os._exit(0)
@@ -310,12 +371,17 @@ async def _run_server(name: str, host: str, port: int, links: list | None = None
310
371
  await ircd.connect_to_peer(lc.host, lc.port, lc.password, lc.trust)
311
372
  logger.info("Linking to %s at %s:%d", lc.name, lc.host, lc.port)
312
373
  except Exception as e:
313
- logger.error("Failed to link to %s: %s", lc.name, e)
374
+ logger.error("Failed to link to %s: %s — will retry", lc.name, e)
375
+ ircd.maybe_retry_link(lc.name)
314
376
 
315
377
  stop_event = asyncio.Event()
316
378
  loop = asyncio.get_event_loop()
317
379
  for sig in (signal.SIGINT, signal.SIGTERM):
318
- loop.add_signal_handler(sig, stop_event.set)
380
+ try:
381
+ loop.add_signal_handler(sig, stop_event.set)
382
+ except (NotImplementedError, RuntimeError):
383
+ # Windows / unsupported event loop: fall back to stdlib signals
384
+ signal.signal(sig, lambda *_: stop_event.set())
319
385
 
320
386
  await stop_event.wait()
321
387
  logger.info("Server '%s' shutting down", name)
@@ -347,11 +413,18 @@ def _server_stop(args: argparse.Namespace) -> None:
347
413
  time.sleep(0.1)
348
414
 
349
415
  # Force kill
350
- print(f"Server '{args.name}' did not stop gracefully, sending SIGKILL")
351
- try:
352
- os.kill(pid, signal.SIGKILL)
353
- except ProcessLookupError:
354
- pass
416
+ if sys.platform == "win32":
417
+ print(f"Server '{args.name}' did not stop gracefully, terminating")
418
+ try:
419
+ os.kill(pid, signal.SIGTERM)
420
+ except ProcessLookupError:
421
+ pass
422
+ else:
423
+ print(f"Server '{args.name}' did not stop gracefully, sending SIGKILL")
424
+ try:
425
+ os.kill(pid, signal.SIGKILL)
426
+ except ProcessLookupError:
427
+ pass
355
428
  remove_pid(pid_name)
356
429
  print(f"Server '{args.name}' killed")
357
430
 
@@ -515,14 +588,28 @@ def _cmd_start(args: argparse.Namespace) -> None:
515
588
  )
516
589
  sys.exit(1)
517
590
 
518
- if len(agents) == 1:
519
- # Run in foreground (single agent)
591
+ foreground = getattr(args, "foreground", False)
592
+
593
+ if foreground:
594
+ if len(agents) != 1:
595
+ print("--foreground requires a single agent nick, not --all", file=sys.stderr)
596
+ sys.exit(1)
520
597
  agent = agents[0]
521
- print(f"Starting agent {agent.nick}...")
598
+ print(f"Starting agent {agent.nick} in foreground...")
522
599
  asyncio.run(_run_single_agent(config, agent))
523
600
  else:
524
- # Fork each agent into background
525
- _run_multi_agents(config, agents)
601
+ if sys.platform == "win32":
602
+ if len(agents) == 1:
603
+ # Windows has no fork — run single agent in foreground
604
+ agent = agents[0]
605
+ print(f"Starting agent {agent.nick}...")
606
+ asyncio.run(_run_single_agent(config, agent))
607
+ else:
608
+ print("Multi-agent daemon mode not supported on Windows. Start agents individually.", file=sys.stderr)
609
+ sys.exit(1)
610
+ else:
611
+ # Daemonize all agents (fork each into background)
612
+ _run_multi_agents(config, agents)
526
613
 
527
614
 
528
615
  async def _run_single_agent(config: DaemonConfig, agent: AgentConfig) -> None:
@@ -720,11 +807,18 @@ def _stop_agent(nick: str) -> None:
720
807
  time.sleep(0.1)
721
808
 
722
809
  # Force kill
723
- print(f"Agent '{nick}' did not stop gracefully, sending SIGKILL")
724
- try:
725
- os.kill(pid, signal.SIGKILL)
726
- except ProcessLookupError:
727
- pass
810
+ if sys.platform == "win32":
811
+ print(f"Agent '{nick}' did not stop gracefully, terminating")
812
+ try:
813
+ os.kill(pid, signal.SIGTERM)
814
+ except ProcessLookupError:
815
+ pass
816
+ else:
817
+ print(f"Agent '{nick}' did not stop gracefully, sending SIGKILL")
818
+ try:
819
+ os.kill(pid, signal.SIGKILL)
820
+ except ProcessLookupError:
821
+ pass
728
822
  remove_pid(pid_name)
729
823
  print(f"Agent '{nick}' killed")
730
824
 
@@ -1164,3 +1258,322 @@ def _cmd_overview(args: argparse.Namespace) -> None:
1164
1258
  message_limit=message_limit,
1165
1259
  )
1166
1260
  print(output, end="")
1261
+
1262
+
1263
+ # -----------------------------------------------------------------------
1264
+ # Credential helpers
1265
+ # -----------------------------------------------------------------------
1266
+
1267
+ def _resolve_links_from_mesh(mesh_config_path: str) -> list:
1268
+ """Load link configs from mesh.yaml, looking up passwords from OS keyring."""
1269
+ from agentirc.mesh_config import load_mesh_config
1270
+ from agentirc.credentials import lookup_credential
1271
+ from agentirc.server.config import LinkConfig
1272
+
1273
+ mesh = load_mesh_config(mesh_config_path)
1274
+ links = []
1275
+ for lc in mesh.server.links:
1276
+ password = lookup_credential(lc.name)
1277
+ if not password:
1278
+ logger.warning(
1279
+ "No credential found for peer '%s' — link will not be established. "
1280
+ "Run 'agentirc setup' to store link passwords.", lc.name
1281
+ )
1282
+ continue
1283
+ links.append(LinkConfig(
1284
+ name=lc.name, host=lc.host, port=lc.port,
1285
+ password=password, trust=lc.trust,
1286
+ ))
1287
+ return links
1288
+
1289
+
1290
+ # -----------------------------------------------------------------------
1291
+ # Shared helpers for setup / update
1292
+ # -----------------------------------------------------------------------
1293
+
1294
+ def _build_server_start_cmd(mesh, agentirc_bin: str, mesh_config_path: str) -> list[str]:
1295
+ """Build the server start command with --foreground and --mesh-config.
1296
+
1297
+ Passwords are NOT included in the command — they come from the OS keyring
1298
+ at startup via --mesh-config.
1299
+ """
1300
+ return [
1301
+ agentirc_bin, "server", "start", "--foreground",
1302
+ "--name", mesh.server.name,
1303
+ "--host", mesh.server.host,
1304
+ "--port", str(mesh.server.port),
1305
+ "--mesh-config", mesh_config_path,
1306
+ ]
1307
+
1308
+
1309
+ # -----------------------------------------------------------------------
1310
+ # Setup — mesh.yaml → auto-start services
1311
+ # -----------------------------------------------------------------------
1312
+
1313
+ def _cmd_setup(args: argparse.Namespace) -> None:
1314
+ import getpass
1315
+ from agentirc.mesh_config import load_mesh_config
1316
+ from agentirc.persistence import install_service, uninstall_service, list_services
1317
+
1318
+ try:
1319
+ mesh = load_mesh_config(args.config)
1320
+ except FileNotFoundError:
1321
+ print(f"Mesh config not found: {args.config}", file=sys.stderr)
1322
+ print("Create it manually or ask your AI agent to generate it.", file=sys.stderr)
1323
+ sys.exit(1)
1324
+
1325
+ server_name = mesh.server.name
1326
+
1327
+ if args.uninstall:
1328
+ print("Uninstalling agentirc services...")
1329
+ # Only remove services for this node (not other mesh nodes)
1330
+ expected = {f"agentirc-server-{server_name}"}
1331
+ for agent in mesh.agents:
1332
+ expected.add(f"agentirc-agent-{server_name}-{agent.nick}")
1333
+ for svc in list_services():
1334
+ if svc in expected:
1335
+ print(f" Removing {svc}")
1336
+ uninstall_service(svc)
1337
+ _server_stop_by_name(server_name)
1338
+ for agent in mesh.agents:
1339
+ full_nick = f"{server_name}-{agent.nick}"
1340
+ _stop_agent(full_nick)
1341
+ print("Done.")
1342
+ return
1343
+
1344
+ # Prompt for link passwords and store in OS keyring (never in files)
1345
+ from agentirc.credentials import store_credential, lookup_credential
1346
+
1347
+ for link in mesh.server.links:
1348
+ existing = lookup_credential(link.name)
1349
+ if existing:
1350
+ print(f" Credential for '{link.name}' already in keyring")
1351
+ else:
1352
+ password = getpass.getpass(f"Link password for {link.name}: ")
1353
+ if store_credential(link.name, password):
1354
+ print(f" Stored credential for '{link.name}' in OS keyring")
1355
+ else:
1356
+ print(f" Warning: failed to store credential for '{link.name}'", file=sys.stderr)
1357
+ print(f" You may need to install secret-tool (Linux) or check Keychain access (macOS)", file=sys.stderr)
1358
+
1359
+ # Generate agents.yaml for each workdir
1360
+ from agentirc.clients.claude.config import (
1361
+ AgentConfig as BaseAgentConfig,
1362
+ DaemonConfig,
1363
+ ServerConnConfig,
1364
+ save_config,
1365
+ )
1366
+
1367
+ workdir_agents: dict[str, list] = {}
1368
+ for agent in mesh.agents:
1369
+ workdir = os.path.expanduser(agent.workdir)
1370
+ workdir_agents.setdefault(workdir, []).append(agent)
1371
+
1372
+ for workdir, agents in workdir_agents.items():
1373
+ os.makedirs(workdir, exist_ok=True)
1374
+ config_path = os.path.join(workdir, ".agentirc", "agents.yaml")
1375
+ os.makedirs(os.path.dirname(config_path), exist_ok=True)
1376
+
1377
+ agent_configs = []
1378
+ for a in agents:
1379
+ full_nick = f"{server_name}-{a.nick}"
1380
+ agent_configs.append(BaseAgentConfig(
1381
+ nick=full_nick,
1382
+ agent=a.type,
1383
+ directory=workdir,
1384
+ channels=list(a.channels),
1385
+ ))
1386
+
1387
+ daemon_config = DaemonConfig(
1388
+ server=ServerConnConfig(name=server_name, host="localhost", port=mesh.server.port),
1389
+ agents=agent_configs,
1390
+ )
1391
+ save_config(config_path, daemon_config)
1392
+ print(f" Wrote {config_path}")
1393
+
1394
+ # Install auto-start services
1395
+ agentirc_bin = shutil.which("agentirc") or "agentirc"
1396
+ server_cmd = _build_server_start_cmd(mesh, agentirc_bin, args.config)
1397
+ svc_name = f"agentirc-server-{server_name}"
1398
+ path = install_service(svc_name, server_cmd, f"agentirc server {server_name}")
1399
+ print(f" Installed {svc_name} → {path}")
1400
+
1401
+ for agent in mesh.agents:
1402
+ full_nick = f"{server_name}-{agent.nick}"
1403
+ workdir = os.path.expanduser(agent.workdir)
1404
+ config_path = os.path.join(workdir, ".agentirc", "agents.yaml")
1405
+ agent_cmd = [agentirc_bin, "start", full_nick, "--foreground", "--config", config_path]
1406
+ agent_svc = f"agentirc-agent-{full_nick}"
1407
+ path = install_service(agent_svc, agent_cmd, f"agentirc agent {full_nick}")
1408
+ print(f" Installed {agent_svc} → {path}")
1409
+
1410
+ print(f"\nSetup complete for mesh node '{server_name}'.")
1411
+ print(f"Services installed. Start with your service manager or reboot.")
1412
+
1413
+
1414
+ def _server_stop_by_name(name: str) -> None:
1415
+ """Stop a server by name (helper for setup --uninstall and update)."""
1416
+ pid_name = f"server-{name}"
1417
+ pid = read_pid(pid_name)
1418
+ if not pid or not is_process_alive(pid):
1419
+ if pid:
1420
+ remove_pid(pid_name)
1421
+ return
1422
+
1423
+ os.kill(pid, signal.SIGTERM)
1424
+ for _ in range(50):
1425
+ if not is_process_alive(pid):
1426
+ remove_pid(pid_name)
1427
+ return
1428
+ time.sleep(0.1)
1429
+
1430
+ # Escalate to SIGKILL (SIGTERM on Windows)
1431
+ if sys.platform == "win32":
1432
+ try:
1433
+ os.kill(pid, signal.SIGTERM)
1434
+ except ProcessLookupError:
1435
+ pass
1436
+ else:
1437
+ try:
1438
+ os.kill(pid, signal.SIGKILL)
1439
+ except ProcessLookupError:
1440
+ pass
1441
+ remove_pid(pid_name)
1442
+
1443
+
1444
+ # -----------------------------------------------------------------------
1445
+ # Update — upgrade + restart
1446
+ # -----------------------------------------------------------------------
1447
+
1448
+ def _cmd_update(args: argparse.Namespace) -> None:
1449
+ from agentirc.mesh_config import load_mesh_config
1450
+
1451
+ try:
1452
+ mesh = load_mesh_config(args.config)
1453
+ except FileNotFoundError:
1454
+ print(f"Mesh config not found: {args.config}", file=sys.stderr)
1455
+ sys.exit(1)
1456
+
1457
+ server_name = mesh.server.name
1458
+
1459
+ if not args.skip_upgrade:
1460
+ if args.dry_run:
1461
+ print("[dry-run] Would run: uv tool upgrade agentirc-cli")
1462
+ print("[dry-run] Would re-exec with --skip-upgrade")
1463
+ return
1464
+
1465
+ # Upgrade the package
1466
+ uv = shutil.which("uv")
1467
+ if uv:
1468
+ print("Upgrading via uv...")
1469
+ result = subprocess.run(
1470
+ [uv, "tool", "upgrade", "agentirc-cli"],
1471
+ capture_output=True, text=True,
1472
+ )
1473
+ print(result.stdout.strip() if result.stdout else "")
1474
+ if result.returncode != 0:
1475
+ print(f"uv upgrade failed: {result.stderr}", file=sys.stderr)
1476
+ sys.exit(1)
1477
+ else:
1478
+ pip = shutil.which("pip") or shutil.which("pip3")
1479
+ if pip:
1480
+ print("Upgrading via pip...")
1481
+ result = subprocess.run(
1482
+ [pip, "install", "--upgrade", "agentirc-cli"],
1483
+ capture_output=True, text=True,
1484
+ )
1485
+ if result.returncode != 0:
1486
+ print(f"pip upgrade failed: {result.stderr}", file=sys.stderr)
1487
+ sys.exit(1)
1488
+ else:
1489
+ print("Neither uv nor pip found", file=sys.stderr)
1490
+ sys.exit(1)
1491
+
1492
+ # Re-exec with new binary so restart uses new code
1493
+ agentirc_bin = shutil.which("agentirc") or "agentirc"
1494
+ reexec_args = [agentirc_bin, "update", "--skip-upgrade", "--config", args.config]
1495
+ print("Re-executing with updated code...")
1496
+ if sys.platform == "win32":
1497
+ sys.exit(subprocess.run(reexec_args).returncode)
1498
+ else:
1499
+ os.execvp(agentirc_bin, reexec_args)
1500
+
1501
+ # --skip-upgrade path: restart everything
1502
+ print(f"Restarting mesh node '{server_name}'...")
1503
+
1504
+ if args.dry_run:
1505
+ for agent in mesh.agents:
1506
+ print(f"[dry-run] Would stop agent {server_name}-{agent.nick}")
1507
+ print(f"[dry-run] Would stop server {server_name}")
1508
+ print(f"[dry-run] Would regenerate auto-start entries")
1509
+ print(f"[dry-run] Would start server {server_name}")
1510
+ for agent in mesh.agents:
1511
+ print(f"[dry-run] Would start agent {server_name}-{agent.nick}")
1512
+ return
1513
+
1514
+ # Stop agents
1515
+ for agent in mesh.agents:
1516
+ full_nick = f"{server_name}-{agent.nick}"
1517
+ print(f" Stopping {full_nick}...")
1518
+ _stop_agent(full_nick)
1519
+
1520
+ # Stop server
1521
+ print(f" Stopping server {server_name}...")
1522
+ _server_stop_by_name(server_name)
1523
+
1524
+ # Regenerate auto-start entries
1525
+ from agentirc.persistence import install_service
1526
+
1527
+ agentirc_bin = shutil.which("agentirc") or "agentirc"
1528
+ server_cmd = _build_server_start_cmd(mesh, agentirc_bin, args.config)
1529
+ install_service(f"agentirc-server-{server_name}", server_cmd, f"agentirc server {server_name}")
1530
+
1531
+ for agent in mesh.agents:
1532
+ full_nick = f"{server_name}-{agent.nick}"
1533
+ workdir = os.path.expanduser(agent.workdir)
1534
+ config_path = os.path.join(workdir, ".agentirc", "agents.yaml")
1535
+ agent_cmd = [agentirc_bin, "start", full_nick, "--foreground", "--config", config_path]
1536
+ install_service(f"agentirc-agent-{full_nick}", agent_cmd, f"agentirc agent {full_nick}")
1537
+
1538
+ # Restart services via platform service manager
1539
+ from agentirc.persistence import restart_service
1540
+
1541
+ server_svc = f"agentirc-server-{server_name}"
1542
+ print(f" Restarting {server_svc}...")
1543
+ if not restart_service(server_svc):
1544
+ # Fallback: start via CLI if no service file installed
1545
+ if sys.platform == "win32":
1546
+ print(f" No service file found. Run 'agentirc setup' to install services.", file=sys.stderr)
1547
+ else:
1548
+ print(f" No service file found, starting via CLI...")
1549
+ subprocess.run([
1550
+ agentirc_bin, "server", "start",
1551
+ "--name", server_name,
1552
+ "--host", mesh.server.host,
1553
+ "--port", str(mesh.server.port),
1554
+ "--mesh-config", args.config,
1555
+ ], check=False)
1556
+
1557
+ # Wait for server to be ready
1558
+ import socket as _socket
1559
+ for _ in range(50):
1560
+ try:
1561
+ with _socket.create_connection(("localhost", mesh.server.port), timeout=1):
1562
+ break
1563
+ except (ConnectionRefusedError, OSError):
1564
+ time.sleep(0.1)
1565
+
1566
+ for agent in mesh.agents:
1567
+ full_nick = f"{server_name}-{agent.nick}"
1568
+ agent_svc = f"agentirc-agent-{full_nick}"
1569
+ print(f" Restarting {agent_svc}...")
1570
+ if not restart_service(agent_svc):
1571
+ # Fallback: start via CLI
1572
+ workdir = os.path.expanduser(agent.workdir)
1573
+ config_path = os.path.join(workdir, ".agentirc", "agents.yaml")
1574
+ subprocess.run(
1575
+ [agentirc_bin, "start", full_nick, "--config", config_path],
1576
+ check=False,
1577
+ )
1578
+
1579
+ print(f"\nUpdate complete. All services restarted.")