agentirc-cli 9.13.0__tar.gz → 9.14.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.
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.github/workflows/tests.yml +18 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/CHANGELOG.md +79 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/PKG-INFO +1 -1
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/event_subscriptions.py +23 -9
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/protocol/replies.py +11 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/telemetry/metrics.py +7 -0
- agentirc_cli-9.14.0/agentirc/accounts.py +574 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/channel.py +29 -11
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/cli.py +10 -1
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/client.py +706 -68
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/config.py +121 -6
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/ircd.py +154 -16
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/protocol.py +28 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/skills/history.py +8 -1
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/skills/rooms.py +88 -14
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/skills/threads.py +56 -6
- agentirc_cli-9.14.0/docs/accounts.md +501 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/api-stability.md +27 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/cli.md +3 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/extension-api.md +24 -4
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/pyproject.toml +1 -1
- agentirc_cli-9.14.0/scripts/sonar-pr-issues.py +168 -0
- agentirc_cli-9.14.0/sonar-project.properties +6 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/_helpers.py +3 -0
- agentirc_cli-9.14.0/tests/test_accounts_grants.py +230 -0
- agentirc_cli-9.14.0/tests/test_accounts_hardening.py +704 -0
- agentirc_cli-9.14.0/tests/test_accounts_hardening_medium.py +625 -0
- agentirc_cli-9.14.0/tests/test_accounts_review66.py +385 -0
- agentirc_cli-9.14.0/tests/test_accounts_revoke.py +310 -0
- agentirc_cli-9.14.0/tests/test_accounts_sasl.py +985 -0
- agentirc_cli-9.14.0/tests/test_accounts_sighup.py +133 -0
- agentirc_cli-9.14.0/tests/test_cap_registration_hold.py +132 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_events_reserved_nick.py +2 -2
- agentirc_cli-9.14.0/tests/test_sonar_pr_issues.py +128 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_verb_discovery.py +9 -10
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/uv.lock +1 -1
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/ask-colleague/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/ask-colleague/prompts/review.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/ask-colleague/prompts/write.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/cicd/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/communicate/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/recall/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/recall/scripts/recall.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/remember/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/remember/scripts/remember.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/think/SKILL.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills/think/scripts/think.sh +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.claude/skills.local.yaml.example +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/current +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/current_plan +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/frames/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/frames/agentirc-now-speaks-presence-the-ircd-parses-resid.json +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/frames/agentirc-ships-an-agent-accessibility-release-ai-a.json +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/plans/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/plans/agentirc-now-speaks-presence-the-ircd-parses-resid.json +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.devague/plans/agentirc-ships-an-agent-accessibility-release-ai-a.json +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/.gitignore +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/CLAUDE.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/LICENSE +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/README.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/TRADEMARKS.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/__main__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/aio.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/bots/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/bots/bot_manager.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/bots/http_listener.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/cli_client.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/cli_shared/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/cli_shared/constants.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/cli_shared/mesh.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/constants.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/pidfile.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/protocol/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/protocol/message.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/telemetry/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/telemetry/audit.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/telemetry/context.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/telemetry/tracing.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/_internal/virtual_client.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/agent_client.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/bot.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/bot_manager.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/cli.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/config.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/filter_dsl.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/http_listener.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/template_engine.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/bots/virtual_client.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/events.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/history_store.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/remote_client.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/room_store.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/rooms_util.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/server_link.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/skill.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/skills/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/skills/icon.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/skills/presence.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/thread_store.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/agentirc/virtual_client.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/agent-walkthrough.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/bots.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/deployment.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/plans/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/plans/2026-07-01-agentirc-ships-an-agent-accessibility-release-ai-a.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/plans/2026-07-07-agentirc-now-speaks-presence-the-ircd-parses-resid.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/specs/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/specs/2026-07-01-agentirc-ships-an-agent-accessibility-release-ai-a.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/specs/2026-07-02-agent-accessibility-gap-verification.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/specs/2026-07-02-agent-accessibility-release-audit.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/specs/2026-07-07-agentirc-now-speaks-presence-the-ircd-parses-resid.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/steward/onboarding.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/superpowers/specs/2026-04-30-bootstrap-design.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/superpowers/specs/2026-05-01-bot-extension-api-design.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/docs/superpowers/specs/2026-05-01-task14-audit.md +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_bot.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_bot_host.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_bot_manager.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_cli_bot.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_config_bots.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_filter_dsl.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_http_listener.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_public_surface.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/bots/test_template_engine.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/conftest.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/__init__.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/_fakes.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/_metrics_helpers.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_audit_emit.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_audit_lifecycle.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_audit_module.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_audit_parse_error.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_config.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_dispatch_span.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_emit_event_span.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_metrics_init.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_metrics_s2s.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_outbound_inject.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_parse_error.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_s2s_relay_span.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_server_init.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_server_link_inject.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/telemetry/test_tracing.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_agent_client.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_agent_walkthrough.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_api_stability_embedding.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_bot_capability.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_channel.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_cli.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_cli_client_verbs.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_cli_json.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_client_backfill.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_config_loader.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_connection.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_discovery.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_disk_paths.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_dm_history.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_docs_promises.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_error_tokens.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_event_subscriptions.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_eventpub.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_events_basic.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_events_catalog.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_events_federation.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_events_history.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_events_lifecycle.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_federation.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_history.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_history_since.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_liveness.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_long_messages.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_mentions.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_message_tags.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_messaging.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_modes.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_motd.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_presence.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_presence_federation.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_presence_stale.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_protocol_bot_exports.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_protocol_presence.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_reconnect_catchup.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_skills.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/tests/test_threads.py +0 -0
- {agentirc_cli-9.13.0 → agentirc_cli-9.14.0}/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,85 @@ 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.14.0] - 2026-11-01
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Agent accounts (culture#506): a reserved nick, a secret (only its sha256 is
|
|
12
|
+
stored), a role (`resident`, `operator`, `guest`), channel grants (`read`,
|
|
13
|
+
`speak`) and a state (`active`, `suspended`, `revoked`), read from
|
|
14
|
+
`<data_dir>/accounts.json` (written by culture). The file reloads within
|
|
15
|
+
about 1 s of a change and on SIGHUP; a malformed file never crashes the
|
|
16
|
+
server — it is rejected whole, the last good table is kept, and the nicks it
|
|
17
|
+
names stay reserved (fail closed). See docs/accounts.md.
|
|
18
|
+
- SASL PLAIN (IRCv3 `sasl` capability, numerics 900/903-908). An account nick
|
|
19
|
+
never gets `001` unless the connection authenticated as exactly that
|
|
20
|
+
account, on every registration path. SASL is accepted only from loopback
|
|
21
|
+
(`accounts.trust_loopback`, default true) or `accounts.trusted_cidrs`; other
|
|
22
|
+
peers are refused before they are asked for the secret. A correct login
|
|
23
|
+
reclaims the nick from any other local holder.
|
|
24
|
+
- Channel grants and roles are enforced on JOIN, PRIVMSG/NOTICE, HISTORY,
|
|
25
|
+
BACKFILL, EVENTSUB, EVENTPUB, THREAD, TOPIC and the room verbs; operator-only
|
|
26
|
+
room verbs need the `operator` role; guests may only hold grants on channels
|
|
27
|
+
under `accounts.guest_channel_prefixes`. Clients without an account are not
|
|
28
|
+
gated.
|
|
29
|
+
- Live revoke: a session whose account is revoked, suspended, removed or
|
|
30
|
+
re-keyed is closed within 5 s; a nick squatted before its account existed
|
|
31
|
+
is evicted too.
|
|
32
|
+
- Failed-authentication logging (nick, peer, reason code; never secret
|
|
33
|
+
material), a per (address, account) rate limit (`accounts.auth_failure_limit`,
|
|
34
|
+
default 10 per `accounts.auth_failure_window` 60 s) and the
|
|
35
|
+
`culture.auth.failures` counter (attribute `reason`).
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Registration now waits for IRCv3 capability negotiation to finish: a client
|
|
40
|
+
that opens negotiation with `CAP LS` gets no `001` welcome and no `SNICK`
|
|
41
|
+
relay to linked peers until it sends `CAP END` (even if `NICK` and `USER`
|
|
42
|
+
already arrived). `CAP END` completes the held registration. A client that
|
|
43
|
+
never sends `CAP` registers exactly as before, and a bare `CAP REQ` without a
|
|
44
|
+
preceding `CAP LS` does not hold registration (legacy-client compatibility).
|
|
45
|
+
A client that sends `CAP LS` and never `CAP END` stays unregistered. This is
|
|
46
|
+
the groundwork for SASL authentication of reserved nicks (culture#506).
|
|
47
|
+
- Before registration only CAP, NICK, USER, PASS, PING, PONG, AUTHENTICATE
|
|
48
|
+
and QUIT are accepted (plus the EVENT*/BACKFILL verbs, which keep their
|
|
49
|
+
`EVENTERR :not-registered` reply); anything else gets `451
|
|
50
|
+
ERR_NOTREGISTERED`, and a pre-registration QUIT emits no event. Applies to
|
|
51
|
+
all clients.
|
|
52
|
+
- Local nicks must be printable ASCII, and a nick that matches an account nick
|
|
53
|
+
under an ASCII case fold without being equal to it is refused (432).
|
|
54
|
+
- Accounts that are not operators are no longer auto-opped as a channel's
|
|
55
|
+
first joiner.
|
|
56
|
+
- EVENTSUB scopes channel-less events for non-operator account sessions: a
|
|
57
|
+
payload `channel` / `target` / `room_id` the session cannot read drops the
|
|
58
|
+
event, and a `channels` list (e.g. `user.quit`) is filtered to readable
|
|
59
|
+
channels (dropped when none remain). Clients without an account are
|
|
60
|
+
unchanged.
|
|
61
|
+
- Channel-less `EVENTPUB <type> *` is refused (`permission-denied`) for
|
|
62
|
+
`guest` accounts and for sessions whose account is suspended, revoked or
|
|
63
|
+
gone; `operator` and `resident` accounts and clients without an account
|
|
64
|
+
are unchanged.
|
|
65
|
+
- `ROOMINVITE` needs read access on the channel for an account session;
|
|
66
|
+
without it the reply is the same `403` as for a nonexistent channel.
|
|
67
|
+
- The failed-authentication limiter is a bounded LRU (4096 keys, O(1)
|
|
68
|
+
amortised per failure) instead of growing without bound under churning
|
|
69
|
+
`authcid`s (agentirc#65).
|
|
70
|
+
- Account lookups no longer `stat()` the accounts file: they read the cached
|
|
71
|
+
table, refreshed by the 1 s watcher, SIGHUP, and at most three file checks
|
|
72
|
+
per connection on the registration/SASL path. Grant and role changes reach
|
|
73
|
+
connected sessions within about 1 s instead of on the next lookup.
|
|
74
|
+
|
|
75
|
+
## [9.13.1] - 2026-10-30
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- CI fails a pull request that has an unresolved SonarCloud issue: after
|
|
80
|
+
SonarCloud's automatic analysis of the PR's head commit,
|
|
81
|
+
`scripts/sonar-pr-issues.py` (cited from culture-rules) fails on any OPEN or
|
|
82
|
+
CONFIRMED issue. ACCEPTED and FALSE_POSITIVE issues pass. Same gate as
|
|
83
|
+
culture, irc-lens and culture-library. `sonar-project.properties` names the
|
|
84
|
+
project key for it.
|
|
85
|
+
|
|
7
86
|
## [9.13.0] - 2026-10-30
|
|
8
87
|
|
|
9
88
|
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.
|
|
3
|
+
Version: 9.14.0
|
|
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
|
|
@@ -207,15 +207,29 @@ class SubscriptionRegistry:
|
|
|
207
207
|
# ``add`` or ``remove`` and mutate the dicts. The ``list()`` snapshots
|
|
208
208
|
# avoid ``RuntimeError: dictionary changed size during iteration``.
|
|
209
209
|
for client, per_client in list(self._subs.items()): # NOSONAR python:S7504: defensive snapshot vs. concurrent mutation
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
210
|
+
# Read grants (culture#506 h1): an account session only receives
|
|
211
|
+
# events it could read through any other path. Checked per event,
|
|
212
|
+
# live, so a grant change applies to the very next event.
|
|
213
|
+
# Channel-less events are scoped to the channels the session can
|
|
214
|
+
# read (agentirc#66 review): ``visible_event`` may return a copy
|
|
215
|
+
# with a filtered channel list, or ``None`` to drop the event.
|
|
216
|
+
visible_event = getattr(client, "visible_event", None)
|
|
217
|
+
delivered = event if visible_event is None else visible_event(event)
|
|
218
|
+
if delivered is None:
|
|
219
|
+
continue
|
|
220
|
+
await self._deliver_to_client(client, per_client, delivered)
|
|
221
|
+
|
|
222
|
+
async def _deliver_to_client(
|
|
223
|
+
self, client: Client, per_client: dict[str, Subscription], delivered: Event
|
|
224
|
+
) -> None:
|
|
225
|
+
"""Enqueue *delivered* on each live, matching subscription of *client*."""
|
|
226
|
+
for sub in list(per_client.values()): # NOSONAR python:S7504: defensive snapshot vs. concurrent mutation
|
|
227
|
+
if sub.dropped or not sub.matches(delivered):
|
|
228
|
+
continue
|
|
229
|
+
try:
|
|
230
|
+
sub.queue.put_nowait(delivered)
|
|
231
|
+
except asyncio.QueueFull:
|
|
232
|
+
await self._handle_overflow(client, sub)
|
|
219
233
|
|
|
220
234
|
async def _handle_overflow(self, client: Client, sub: Subscription) -> None:
|
|
221
235
|
sub.dropped = True
|
|
@@ -43,13 +43,24 @@ ERR_ERRONEUSNICKNAME = "432"
|
|
|
43
43
|
ERR_NICKNAMEINUSE = "433"
|
|
44
44
|
ERR_USERNOTINCHANNEL = "441"
|
|
45
45
|
ERR_NOTONCHANNEL = "442"
|
|
46
|
+
ERR_NOTREGISTERED = "451"
|
|
46
47
|
ERR_NEEDMOREPARAMS = "461"
|
|
47
48
|
ERR_ALREADYREGISTRED = "462"
|
|
48
49
|
ERR_CHANOPRIVSNEEDED = "482"
|
|
49
50
|
ERR_USERSDONTMATCH = "502"
|
|
50
51
|
|
|
52
|
+
# SASL (IRCv3 sasl-3.1)
|
|
53
|
+
RPL_LOGGEDIN = "900"
|
|
54
|
+
RPL_SASLSUCCESS = "903"
|
|
55
|
+
ERR_SASLFAIL = "904"
|
|
56
|
+
ERR_SASLTOOLONG = "905"
|
|
57
|
+
ERR_SASLABORTED = "906"
|
|
58
|
+
ERR_SASLALREADY = "907"
|
|
59
|
+
RPL_SASLMECHS = "908"
|
|
60
|
+
|
|
51
61
|
# Error/reply message texts
|
|
52
62
|
MSG_NEEDMOREPARAMS = "Not enough parameters"
|
|
63
|
+
MSG_NOTREGISTERED = "You have not registered"
|
|
53
64
|
MSG_NOSUCHCHANNEL = "No such channel"
|
|
54
65
|
MSG_NOSUCHNICK = "No such nick"
|
|
55
66
|
MSG_NOTONCHANNEL = "You're not on that channel"
|
|
@@ -66,6 +66,8 @@ class MetricsRegistry:
|
|
|
66
66
|
# Bots (Plan 7)
|
|
67
67
|
bot_invocations: Counter
|
|
68
68
|
bot_webhook_duration: Histogram
|
|
69
|
+
# Agent accounts (culture#506 t10)
|
|
70
|
+
auth_failures: Counter
|
|
69
71
|
|
|
70
72
|
|
|
71
73
|
def reset_for_tests() -> None:
|
|
@@ -181,6 +183,11 @@ def _build_registry(meter: Meter) -> MetricsRegistry:
|
|
|
181
183
|
unit="s",
|
|
182
184
|
description="Webhook request handler duration by bot and status_class=2xx|3xx|4xx|5xx",
|
|
183
185
|
),
|
|
186
|
+
# Agent accounts (culture#506 t10)
|
|
187
|
+
auth_failures=meter.create_counter(
|
|
188
|
+
"culture.auth.failures",
|
|
189
|
+
description="Failed authentications by reason (bad_secret, unknown_account, ...)",
|
|
190
|
+
),
|
|
184
191
|
)
|
|
185
192
|
|
|
186
193
|
|