agentirc-cli 9.13.0__tar.gz → 9.13.1__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 (201) hide show
  1. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.github/workflows/tests.yml +18 -0
  2. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/CHANGELOG.md +11 -0
  3. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/PKG-INFO +1 -1
  4. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/pyproject.toml +1 -1
  5. agentirc_cli-9.13.1/scripts/sonar-pr-issues.py +168 -0
  6. agentirc_cli-9.13.1/sonar-project.properties +6 -0
  7. agentirc_cli-9.13.1/tests/test_sonar_pr_issues.py +128 -0
  8. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/uv.lock +1 -1
  9. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/ask-colleague/SKILL.md +0 -0
  10. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
  11. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/ask-colleague/prompts/review.md +0 -0
  12. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/ask-colleague/prompts/write.md +0 -0
  13. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
  14. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
  15. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
  16. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/cicd/SKILL.md +0 -0
  17. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
  18. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
  19. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
  20. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
  21. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/cicd/scripts/workflow.sh +0 -0
  22. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/communicate/SKILL.md +0 -0
  23. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
  24. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
  25. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
  26. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
  27. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/recall/SKILL.md +0 -0
  28. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/recall/scripts/recall.sh +0 -0
  29. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/remember/SKILL.md +0 -0
  30. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/remember/scripts/remember.sh +0 -0
  31. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/spec-to-plan/SKILL.md +0 -0
  32. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
  33. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/think/SKILL.md +0 -0
  34. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills/think/scripts/think.sh +0 -0
  35. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.claude/skills.local.yaml.example +0 -0
  36. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/current +0 -0
  37. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/current_plan +0 -0
  38. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/frames/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
  39. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/frames/agentirc-now-speaks-presence-the-ircd-parses-resid.json +0 -0
  40. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/frames/agentirc-ships-an-agent-accessibility-release-ai-a.json +0 -0
  41. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/plans/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
  42. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/plans/agentirc-now-speaks-presence-the-ircd-parses-resid.json +0 -0
  43. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.devague/plans/agentirc-ships-an-agent-accessibility-release-ai-a.json +0 -0
  44. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.github/workflows/publish.yml +0 -0
  45. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/.gitignore +0 -0
  46. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/CLAUDE.md +0 -0
  47. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/LICENSE +0 -0
  48. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/README.md +0 -0
  49. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/TRADEMARKS.md +0 -0
  50. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/__init__.py +0 -0
  51. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/__main__.py +0 -0
  52. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/__init__.py +0 -0
  53. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/aio.py +0 -0
  54. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/bots/__init__.py +0 -0
  55. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/bots/bot_manager.py +0 -0
  56. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/bots/http_listener.py +0 -0
  57. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/cli_client.py +0 -0
  58. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/cli_shared/__init__.py +0 -0
  59. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/cli_shared/constants.py +0 -0
  60. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/cli_shared/mesh.py +0 -0
  61. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/constants.py +0 -0
  62. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/event_subscriptions.py +0 -0
  63. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/pidfile.py +0 -0
  64. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/protocol/__init__.py +0 -0
  65. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/protocol/message.py +0 -0
  66. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/protocol/replies.py +0 -0
  67. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/telemetry/__init__.py +0 -0
  68. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/telemetry/audit.py +0 -0
  69. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/telemetry/context.py +0 -0
  70. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/telemetry/metrics.py +0 -0
  71. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/telemetry/tracing.py +0 -0
  72. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/_internal/virtual_client.py +0 -0
  73. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/agent_client.py +0 -0
  74. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/__init__.py +0 -0
  75. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/bot.py +0 -0
  76. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/bot_manager.py +0 -0
  77. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/cli.py +0 -0
  78. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/config.py +0 -0
  79. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/filter_dsl.py +0 -0
  80. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/http_listener.py +0 -0
  81. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/template_engine.py +0 -0
  82. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/bots/virtual_client.py +0 -0
  83. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/channel.py +0 -0
  84. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/cli.py +0 -0
  85. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/client.py +0 -0
  86. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/config.py +0 -0
  87. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/events.py +0 -0
  88. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/history_store.py +0 -0
  89. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/ircd.py +0 -0
  90. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/protocol.py +0 -0
  91. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/remote_client.py +0 -0
  92. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/room_store.py +0 -0
  93. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/rooms_util.py +0 -0
  94. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/server_link.py +0 -0
  95. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/skill.py +0 -0
  96. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/skills/__init__.py +0 -0
  97. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/skills/history.py +0 -0
  98. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/skills/icon.py +0 -0
  99. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/skills/presence.py +0 -0
  100. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/skills/rooms.py +0 -0
  101. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/skills/threads.py +0 -0
  102. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/thread_store.py +0 -0
  103. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/agentirc/virtual_client.py +0 -0
  104. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/agent-walkthrough.md +0 -0
  105. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/api-stability.md +0 -0
  106. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/bots.md +0 -0
  107. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/cli.md +0 -0
  108. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/deployment.md +0 -0
  109. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/extension-api.md +0 -0
  110. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/plans/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
  111. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/plans/2026-07-01-agentirc-ships-an-agent-accessibility-release-ai-a.md +0 -0
  112. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/plans/2026-07-07-agentirc-now-speaks-presence-the-ircd-parses-resid.md +0 -0
  113. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/specs/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
  114. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/specs/2026-07-01-agentirc-ships-an-agent-accessibility-release-ai-a.md +0 -0
  115. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/specs/2026-07-02-agent-accessibility-gap-verification.md +0 -0
  116. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/specs/2026-07-02-agent-accessibility-release-audit.md +0 -0
  117. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/specs/2026-07-07-agentirc-now-speaks-presence-the-ircd-parses-resid.md +0 -0
  118. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/steward/onboarding.md +0 -0
  119. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/superpowers/specs/2026-04-30-bootstrap-design.md +0 -0
  120. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/superpowers/specs/2026-05-01-bot-extension-api-design.md +0 -0
  121. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/docs/superpowers/specs/2026-05-01-task14-audit.md +0 -0
  122. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/__init__.py +0 -0
  123. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/_helpers.py +0 -0
  124. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/__init__.py +0 -0
  125. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_bot.py +0 -0
  126. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_bot_host.py +0 -0
  127. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_bot_manager.py +0 -0
  128. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_cli_bot.py +0 -0
  129. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_config_bots.py +0 -0
  130. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_filter_dsl.py +0 -0
  131. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_http_listener.py +0 -0
  132. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_public_surface.py +0 -0
  133. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/bots/test_template_engine.py +0 -0
  134. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/conftest.py +0 -0
  135. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/__init__.py +0 -0
  136. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/_fakes.py +0 -0
  137. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/_metrics_helpers.py +0 -0
  138. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_audit_emit.py +0 -0
  139. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_audit_lifecycle.py +0 -0
  140. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_audit_module.py +0 -0
  141. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_audit_parse_error.py +0 -0
  142. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_config.py +0 -0
  143. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_dispatch_span.py +0 -0
  144. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_emit_event_span.py +0 -0
  145. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_metrics_init.py +0 -0
  146. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_metrics_s2s.py +0 -0
  147. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_outbound_inject.py +0 -0
  148. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_parse_error.py +0 -0
  149. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_s2s_relay_span.py +0 -0
  150. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_server_init.py +0 -0
  151. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_server_link_inject.py +0 -0
  152. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/telemetry/test_tracing.py +0 -0
  153. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_agent_client.py +0 -0
  154. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_agent_walkthrough.py +0 -0
  155. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_api_stability_embedding.py +0 -0
  156. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_bot_capability.py +0 -0
  157. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_channel.py +0 -0
  158. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_cli.py +0 -0
  159. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_cli_client_verbs.py +0 -0
  160. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_cli_json.py +0 -0
  161. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_client_backfill.py +0 -0
  162. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_config_loader.py +0 -0
  163. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_connection.py +0 -0
  164. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_discovery.py +0 -0
  165. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_disk_paths.py +0 -0
  166. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_dm_history.py +0 -0
  167. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_docs_promises.py +0 -0
  168. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_error_tokens.py +0 -0
  169. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_event_subscriptions.py +0 -0
  170. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_eventpub.py +0 -0
  171. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_events_basic.py +0 -0
  172. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_events_catalog.py +0 -0
  173. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_events_federation.py +0 -0
  174. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_events_history.py +0 -0
  175. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_events_lifecycle.py +0 -0
  176. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_events_reserved_nick.py +0 -0
  177. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_federation.py +0 -0
  178. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_history.py +0 -0
  179. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_history_since.py +0 -0
  180. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_link_reconnect.py +0 -0
  181. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_liveness.py +0 -0
  182. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_long_messages.py +0 -0
  183. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_mentions.py +0 -0
  184. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_message_tags.py +0 -0
  185. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_messaging.py +0 -0
  186. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_modes.py +0 -0
  187. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_motd.py +0 -0
  188. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_presence.py +0 -0
  189. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_presence_federation.py +0 -0
  190. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_presence_stale.py +0 -0
  191. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_protocol_bot_exports.py +0 -0
  192. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_protocol_presence.py +0 -0
  193. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_reconnect_catchup.py +0 -0
  194. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_room_persistence.py +0 -0
  195. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_rooms_federation.py +0 -0
  196. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_rooms_integration.py +0 -0
  197. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_server_icon_skill.py +0 -0
  198. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_skills.py +0 -0
  199. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_threads.py +0 -0
  200. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_verb_discovery.py +0 -0
  201. {agentirc_cli-9.13.0 → agentirc_cli-9.13.1}/tests/test_wire_format_envelope.py +0 -0
@@ -24,6 +24,11 @@ jobs:
24
24
  runs-on: ubuntu-latest
25
25
  permissions:
26
26
  contents: read
27
+ # A presence flag, not the secret: `secrets.*` isn't allowed in `if:`.
28
+ # Fork and Dependabot PRs get no SONAR_TOKEN, so the SonarCloud gate skips
29
+ # there instead of waiting out its 300 s timeout.
30
+ env:
31
+ SONAR_TOKEN_PRESENT: ${{ secrets.SONAR_TOKEN != '' }}
27
32
  steps:
28
33
  - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
29
34
 
@@ -57,6 +62,19 @@ jobs:
57
62
  UV_PROJECT_ENVIRONMENT: .venv
58
63
  run: uv run pytest -n auto -v
59
64
 
65
+ # No unresolved SonarCloud issue on the PR. SonarCloud's automatic analysis
66
+ # (the GitHub App) scans the PR; a code smell leaves its quality gate green,
67
+ # so this fails the job while the PR has any OPEN or CONFIRMED issue.
68
+ # ACCEPTED and FALSE_POSITIVE ones pass. Cited from culture-rules (#43).
69
+ - name: SonarCloud unresolved issues
70
+ if: steps.bootstrap.outputs.ready == 'true' && env.SONAR_TOKEN_PRESENT == 'true' && github.event_name == 'pull_request'
71
+ env:
72
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
73
+ SONAR_HOST_URL: https://sonarcloud.io
74
+ PR_NUMBER: ${{ github.event.pull_request.number }}
75
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
76
+ run: python3 scripts/sonar-pr-issues.py
77
+
60
78
  version-check:
61
79
  needs: lint
62
80
  runs-on: ubuntu-latest
@@ -4,6 +4,17 @@ 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
+ ## [9.13.1] - 2026-10-30
8
+
9
+ ### Added
10
+
11
+ - CI fails a pull request that has an unresolved SonarCloud issue: after
12
+ SonarCloud's automatic analysis of the PR's head commit,
13
+ `scripts/sonar-pr-issues.py` (cited from culture-rules) fails on any OPEN or
14
+ CONFIRMED issue. ACCEPTED and FALSE_POSITIVE issues pass. Same gate as
15
+ culture, irc-lens and culture-library. `sonar-project.properties` names the
16
+ project key for it.
17
+
7
18
  ## [9.13.0] - 2026-10-30
8
19
 
9
20
  First agentirc release that presents itself as CULTURE.DEV on the wire —
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentirc-cli
3
- Version: 9.13.0
3
+ Version: 9.13.1
4
4
  Summary: Agent-friendly IRCd: server core for AI agent meshes
5
5
  Project-URL: Homepage, https://github.com/agentculture/agentirc
6
6
  Project-URL: Issues, https://github.com/agentculture/agentirc/issues
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentirc-cli"
3
- version = "9.13.0"
3
+ version = "9.13.1"
4
4
  description = "Agent-friendly IRCd: server core for AI agent meshes"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env python3
2
+ # Cited from agentculture/culture-rules@48942c3 scripts/sonar-pr-issues.py (cite, don't import).
3
+ """Fail a pull request that has unresolved SonarCloud issues.
4
+
5
+ SonarCloud's quality gate can pass with open issues on new code (a code smell does not
6
+ turn it red), so CI runs this right after the scan: it waits until SonarCloud's analysis
7
+ of the PR is for the PR's head commit, then lists the PR's issues whose status is OPEN or
8
+ CONFIRMED and exits 1 when there is any. ACCEPTED and FALSE_POSITIVE issues are resolved
9
+ by a person and pass; FIXED ones are gone.
10
+
11
+ Environment: ``SONAR_HOST_URL`` (the server; defaults to localhost so nothing outside is
12
+ called by accident), ``SONAR_PROJECT_KEY`` (else ``sonar.projectKey`` from
13
+ ``sonar-project.properties``), ``PR_NUMBER``, ``HEAD_SHA`` and optionally ``SONAR_TOKEN``.
14
+ Exit codes: 0 no unresolved issue, 1 unresolved issues, 2 the analysis or the API could
15
+ not be read. Standard library only.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import base64
21
+ import json
22
+ import os
23
+ import sys
24
+ import time
25
+ import urllib.parse
26
+ import urllib.request
27
+ from collections.abc import Callable, Mapping
28
+ from pathlib import Path
29
+ from typing import Any
30
+
31
+ UNRESOLVED = ("OPEN", "CONFIRMED")
32
+ PAGE_SIZE = 100
33
+ WAIT_S = 300
34
+ POLL_S = 10
35
+
36
+ Fetch = Callable[[str, Mapping[str, str]], Mapping[str, Any]]
37
+
38
+
39
+ def project_key(env: Mapping[str, str], root: Path) -> str:
40
+ """``SONAR_PROJECT_KEY``, else ``sonar.projectKey`` from ``sonar-project.properties``."""
41
+ if env.get("SONAR_PROJECT_KEY"):
42
+ return env["SONAR_PROJECT_KEY"]
43
+ for line in (root / "sonar-project.properties").read_text().splitlines():
44
+ name, _, value = line.partition("=")
45
+ if name.strip() == "sonar.projectKey" and value.strip():
46
+ return value.strip()
47
+ raise SystemExit("sonar-pr-issues: no SONAR_PROJECT_KEY and no sonar.projectKey")
48
+
49
+
50
+ def http_fetch(host: str, token: str | None) -> Fetch:
51
+ """A GET of ``host + path`` with ``params``, as JSON (token as basic auth, if any)."""
52
+
53
+ def fetch(path: str, params: Mapping[str, str]) -> Mapping[str, Any]:
54
+ url = f"{host.rstrip('/')}{path}?{urllib.parse.urlencode(params)}"
55
+ req = urllib.request.Request(url) # noqa: S310 - the host is the configured server
56
+ if token:
57
+ basic = base64.b64encode(f"{token}:".encode()).decode()
58
+ req.add_header("Authorization", f"Basic {basic}")
59
+ with urllib.request.urlopen(req, timeout=30) as resp: # nosec B310
60
+ return json.load(resp)
61
+
62
+ return fetch
63
+
64
+
65
+ def analysed_commit(fetch: Fetch, project: str, pr: str) -> str | None:
66
+ """The commit SonarCloud last analysed for pull request ``pr``, or ``None``."""
67
+ data = fetch("/api/project_pull_requests/list", {"project": project})
68
+ for item in data.get("pullRequests") or ():
69
+ if str(item.get("key")) == pr:
70
+ commit = item.get("commit") or {}
71
+ sha = commit.get("sha")
72
+ return sha if isinstance(sha, str) else None
73
+ return None
74
+
75
+
76
+ def wait_for_analysis(
77
+ fetch: Fetch,
78
+ project: str,
79
+ pr: str,
80
+ head: str,
81
+ *,
82
+ wait_s: float = WAIT_S,
83
+ poll_s: float = POLL_S,
84
+ sleep: Callable[[float], None] = time.sleep,
85
+ clock: Callable[[], float] = time.monotonic,
86
+ ) -> bool:
87
+ """True once the PR's analysis is for ``head``; False when ``wait_s`` runs out."""
88
+ deadline = clock() + wait_s
89
+ while True:
90
+ if analysed_commit(fetch, project, pr) == head:
91
+ return True
92
+ if clock() >= deadline:
93
+ return False
94
+ sleep(poll_s)
95
+
96
+
97
+ def unresolved_issues(fetch: Fetch, project: str, pr: str) -> list[Mapping[str, Any]]:
98
+ """Every OPEN or CONFIRMED issue of pull request ``pr``, across pages."""
99
+ out: list[Mapping[str, Any]] = []
100
+ page = 1
101
+ while True:
102
+ data = fetch(
103
+ "/api/issues/search",
104
+ {
105
+ "componentKeys": project,
106
+ "pullRequest": pr,
107
+ "issueStatuses": ",".join(UNRESOLVED),
108
+ "ps": str(PAGE_SIZE),
109
+ "p": str(page),
110
+ },
111
+ )
112
+ issues = [i for i in data.get("issues") or () if isinstance(i, Mapping)]
113
+ out.extend(issues)
114
+ total = data.get("total")
115
+ if not issues or not isinstance(total, int) or len(out) >= total:
116
+ return out
117
+ page += 1
118
+
119
+
120
+ def describe(issue: Mapping[str, Any], project: str) -> str:
121
+ """One line: rule, file and line, severity, message."""
122
+ component = str(issue.get("component") or "").removeprefix(f"{project}:")
123
+ line = issue.get("line")
124
+ where = f"{component}:{line}" if line else component
125
+ return (
126
+ f"[{issue.get('rule')}] {where} ({issue.get('severity')}, "
127
+ f"{issue.get('issueStatus') or issue.get('status')}): {issue.get('message')}"
128
+ )
129
+
130
+
131
+ def main(
132
+ env: Mapping[str, str] | None = None,
133
+ fetch: Fetch | None = None,
134
+ root: Path | None = None,
135
+ sleep: Callable[[float], None] = time.sleep,
136
+ ) -> int:
137
+ env = os.environ if env is None else env
138
+ root = Path(__file__).resolve().parents[1] if root is None else root
139
+ pr, head = env.get("PR_NUMBER", ""), env.get("HEAD_SHA", "")
140
+ if not pr or not head:
141
+ print("sonar-pr-issues: PR_NUMBER and HEAD_SHA are required", file=sys.stderr)
142
+ return 2
143
+ project = project_key(env, root)
144
+ if fetch is None:
145
+ host = env.get("SONAR_HOST_URL") or "http://localhost:9000"
146
+ fetch = http_fetch(host, env.get("SONAR_TOKEN") or None)
147
+ try:
148
+ if not wait_for_analysis(fetch, project, pr, head, sleep=sleep):
149
+ print(
150
+ f"sonar-pr-issues: no SonarCloud analysis of PR #{pr} at {head[:12]}",
151
+ file=sys.stderr,
152
+ )
153
+ return 2
154
+ issues = unresolved_issues(fetch, project, pr)
155
+ except (OSError, ValueError) as exc: # URLError is an OSError; bad JSON a ValueError
156
+ print(f"sonar-pr-issues: SonarCloud could not be read: {exc}", file=sys.stderr)
157
+ return 2
158
+ if not issues:
159
+ print(f"SonarCloud: PR #{pr} has no unresolved issue (accepted ones pass)")
160
+ return 0
161
+ print(f"SonarCloud: PR #{pr} has {len(issues)} unresolved issue(s); fix or accept each:")
162
+ for issue in issues:
163
+ print(f" - {describe(issue, project)}")
164
+ return 1
165
+
166
+
167
+ if __name__ == "__main__":
168
+ sys.exit(main())
@@ -0,0 +1,6 @@
1
+ # SonarCloud project identity. agentirc is analysed by SonarCloud's automatic
2
+ # analysis (the GitHub App), not by a CI scan step, so this file is not read by
3
+ # a scanner. scripts/sonar-pr-issues.py reads sonar.projectKey from it to find
4
+ # the PR's analysis and its unresolved issues.
5
+ sonar.projectKey=agentculture_agentirc
6
+ sonar.organization=agentculture
@@ -0,0 +1,128 @@
1
+ # Cited from agentculture/culture-rules@48942c3 tests/test_sonar_pr_issues.py
2
+ # (cite, don't import); PROJECT is agentirc's key.
3
+ """Tests for scripts/sonar-pr-issues.py: a PR with an unresolved SonarCloud issue fails CI.
4
+
5
+ The SonarCloud API is a fake ``fetch`` keyed by path; nothing outside is called.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import importlib.util
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ REPO_ROOT = Path(__file__).resolve().parents[1]
15
+ SCRIPT = REPO_ROOT / "scripts" / "sonar-pr-issues.py"
16
+
17
+ _spec = importlib.util.spec_from_file_location("sonar_pr_issues", SCRIPT)
18
+ spi = importlib.util.module_from_spec(_spec)
19
+ assert _spec.loader is not None
20
+ sys.modules["sonar_pr_issues"] = spi
21
+ _spec.loader.exec_module(spi)
22
+
23
+ PROJECT = "agentculture_agentirc"
24
+ HEAD = "c8207ca" + "0" * 33
25
+ ENV = {"PR_NUMBER": "43", "HEAD_SHA": HEAD, "SONAR_PROJECT_KEY": PROJECT}
26
+
27
+
28
+ def issue(rule="python:S3776", status="OPEN", line=153):
29
+ return {
30
+ "rule": rule,
31
+ "component": f"{PROJECT}:culture_rules/events/emit.py",
32
+ "line": line,
33
+ "severity": "CRITICAL",
34
+ "issueStatus": status,
35
+ "message": "Refactor this function",
36
+ }
37
+
38
+
39
+ class FakeSonar:
40
+ """``/api/project_pull_requests/list`` answers ``commits`` in turn (the last repeats);
41
+ ``/api/issues/search`` answers the issues whose status was asked for, one per page."""
42
+
43
+ def __init__(self, commits, issues=()):
44
+ self.commits = list(commits)
45
+ self.issues = list(issues)
46
+ self.calls = []
47
+
48
+ def __call__(self, path, params):
49
+ self.calls.append((path, dict(params)))
50
+ if path == "/api/project_pull_requests/list":
51
+ sha = self.commits.pop(0) if len(self.commits) > 1 else self.commits[0]
52
+ return {"pullRequests": [{"key": "42"}, {"key": "43", "commit": {"sha": sha}}]}
53
+ wanted = params["issueStatuses"].split(",")
54
+ found = [i for i in self.issues if i["issueStatus"] in wanted]
55
+ page = int(params["p"])
56
+ return {"total": len(found), "issues": found[page - 1 : page]}
57
+
58
+
59
+ def run(fake, capsys):
60
+ code = spi.main(env=ENV, fetch=fake, root=REPO_ROOT, sleep=lambda s: None)
61
+ return code, capsys.readouterr()
62
+
63
+
64
+ def test_a_pr_without_issues_passes(capsys):
65
+ code, out = run(FakeSonar([HEAD]), capsys)
66
+ assert code == 0
67
+ assert "no unresolved issue" in out.out
68
+
69
+
70
+ def test_an_open_issue_fails_and_is_listed(capsys):
71
+ code, out = run(FakeSonar([HEAD], [issue()]), capsys)
72
+ assert code == 1
73
+ assert "[python:S3776] culture_rules/events/emit.py:153" in out.out
74
+
75
+
76
+ def test_accepted_and_false_positive_issues_pass(capsys):
77
+ fake = FakeSonar([HEAD], [issue(status="ACCEPTED"), issue(status="FALSE_POSITIVE")])
78
+ code, _ = run(fake, capsys)
79
+ assert code == 0
80
+ (search,) = [p for path, p in fake.calls if path == "/api/issues/search"]
81
+ assert search["issueStatuses"] == "OPEN,CONFIRMED"
82
+
83
+
84
+ def test_a_confirmed_issue_fails(capsys):
85
+ code, _ = run(FakeSonar([HEAD], [issue(status="CONFIRMED")]), capsys)
86
+ assert code == 1
87
+
88
+
89
+ def test_every_page_is_read(capsys):
90
+ issues = [issue(line=n) for n in range(1, 4)]
91
+ code, out = run(FakeSonar([HEAD], issues), capsys)
92
+ assert code == 1
93
+ assert "3 unresolved issue(s)" in out.out
94
+
95
+
96
+ def test_it_waits_for_the_analysis_of_the_head_commit(capsys):
97
+ fake = FakeSonar(["old" + "0" * 37, "old" + "0" * 37, HEAD], [issue()])
98
+ code, _ = run(fake, capsys)
99
+ assert code == 1
100
+ lists = [c for c in fake.calls if c[0] == "/api/project_pull_requests/list"]
101
+ assert len(lists) == 3
102
+
103
+
104
+ def test_no_analysis_of_the_head_is_an_environment_error(capsys):
105
+ ticks = iter(range(0, 10_000, 100))
106
+ fake = FakeSonar(["old" + "0" * 37])
107
+ ok = spi.wait_for_analysis(
108
+ fake, PROJECT, "43", HEAD, wait_s=300, sleep=lambda s: None, clock=lambda: next(ticks)
109
+ )
110
+ assert ok is False
111
+
112
+
113
+ def test_an_unreadable_api_is_an_environment_error(capsys):
114
+ def broken(path, params):
115
+ raise OSError("connection refused")
116
+
117
+ code, out = run(broken, capsys)
118
+ assert code == 2
119
+ assert "could not be read" in out.err
120
+
121
+
122
+ def test_the_project_key_comes_from_sonar_project_properties():
123
+ assert spi.project_key({}, REPO_ROOT) == PROJECT
124
+
125
+
126
+ def test_missing_pr_or_head_is_an_environment_error(capsys):
127
+ code = spi.main(env={}, fetch=FakeSonar([HEAD]), root=REPO_ROOT, sleep=lambda s: None)
128
+ assert code == 2
@@ -10,7 +10,7 @@ resolution-markers = [
10
10
 
11
11
  [[package]]
12
12
  name = "agentirc-cli"
13
- version = "9.13.0"
13
+ version = "9.13.1"
14
14
  source = { editable = "." }
15
15
  dependencies = [
16
16
  { name = "aiohttp" },
File without changes
File without changes
File without changes
File without changes
File without changes