agentirc-cli 8.1.0__tar.gz → 8.3.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-8.1.0 → agentirc_cli-8.3.0}/CHANGELOG.md +32 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/PKG-INFO +5 -1
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/_config.culture.yml +3 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/_data/sites.yml +1 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/_includes/head_custom.html +1 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/client.py +268 -144
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/config.py +15 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/ircd.py +49 -20
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/server_link.py +161 -42
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/config.py +10 -0
- agentirc_cli-8.3.0/culture/protocol/extensions/tracing.md +37 -0
- agentirc_cli-8.3.0/culture/telemetry/__init__.py +26 -0
- agentirc_cli-8.3.0/culture/telemetry/context.py +121 -0
- agentirc_cli-8.3.0/culture/telemetry/tracing.py +114 -0
- agentirc_cli-8.3.0/docs/agentirc/otelcol-template.yaml +25 -0
- agentirc_cli-8.3.0/docs/agentirc/telemetry.md +101 -0
- agentirc_cli-8.3.0/docs/reference/architecture/index.md +27 -0
- agentirc_cli-8.3.0/docs/reference/architecture/subsites.md +111 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/server/config.md +26 -0
- agentirc_cli-8.3.0/docs/superpowers/plans/2026-04-24-otel-foundation.md +2159 -0
- agentirc_cli-8.3.0/docs/superpowers/plans/2026-04-25-otel-federation.md +229 -0
- agentirc_cli-8.3.0/docs/superpowers/specs/2026-04-24-otel-observability-design.md +334 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/pyproject.toml +5 -1
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/sitemap.html +1 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/conftest.py +26 -0
- agentirc_cli-8.3.0/tests/telemetry/__init__.py +0 -0
- agentirc_cli-8.3.0/tests/telemetry/_fakes.py +26 -0
- agentirc_cli-8.3.0/tests/telemetry/test_config.py +26 -0
- agentirc_cli-8.3.0/tests/telemetry/test_config_load.py +36 -0
- agentirc_cli-8.3.0/tests/telemetry/test_context.py +147 -0
- agentirc_cli-8.3.0/tests/telemetry/test_dispatch_span.py +45 -0
- agentirc_cli-8.3.0/tests/telemetry/test_emit_event_span.py +42 -0
- agentirc_cli-8.3.0/tests/telemetry/test_federation_propagation.py +141 -0
- agentirc_cli-8.3.0/tests/telemetry/test_outbound_inject.py +70 -0
- agentirc_cli-8.3.0/tests/telemetry/test_parse_error.py +33 -0
- agentirc_cli-8.3.0/tests/telemetry/test_privmsg_span.py +45 -0
- agentirc_cli-8.3.0/tests/telemetry/test_s2s_dispatch_span.py +156 -0
- agentirc_cli-8.3.0/tests/telemetry/test_s2s_relay_span.py +114 -0
- agentirc_cli-8.3.0/tests/telemetry/test_s2s_session_span.py +64 -0
- agentirc_cli-8.3.0/tests/telemetry/test_server_init.py +29 -0
- agentirc_cli-8.3.0/tests/telemetry/test_server_link_inject.py +124 -0
- agentirc_cli-8.3.0/tests/telemetry/test_session_span.py +105 -0
- agentirc_cli-8.3.0/tests/telemetry/test_tracing.py +49 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_federation.py +47 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/uv.lock +185 -1
- agentirc_cli-8.1.0/docs/reference/architecture/index.md +0 -13
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.claude/agents/doc-test-alignment.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.flake8 +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.github/workflows/docs-check.yml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.gitignore +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.pr_agent.toml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/.pylintrc +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/CLAUDE.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/Gemfile +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/Gemfile.lock +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/LICENSE +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/README.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/SECURITY.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/_config.base.yml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/_sass/color_schemes/dark-terminal.scss +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/assets/images/IMG_3183.png +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/assets/images/apple-touch-icon.png +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/assets/images/favicon-16x16.png +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/assets/images/favicon-32x32.png +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/assets/images/favicon.ico +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/assets/images/og-agentirc.png +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/assets/images/og-culture.png +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/__main__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/CLAUDE.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/__main__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/channel.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/docs/agentirc-architecture.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/docs/agentirc-features.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/docs/agentirc-skill.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/docs/agentirc.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/events.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/history_store.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/remote_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/room_store.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/rooms_util.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/skill.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/skills/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/skills/history.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/skills/icon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/skills/rooms.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/skills/threads.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/agentirc/thread_store.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/aio.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/bot.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/filter_dsl.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/system/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/system/welcome/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/system/welcome/bot.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/system/welcome/handler.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/_passthrough.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/afi.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/agent.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/bot.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/channel.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/devex.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/introspect.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/mesh.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/server.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/shared/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/shared/constants.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/shared/display.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/shared/formatting.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/shared/ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/shared/mesh.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/shared/process.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/cli/skills.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/agent_runner.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/culture.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/irc_transport.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/skill/irc_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/culture.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/culture.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/culture.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/skill/irc_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/app.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/commands.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/status.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/constants.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/credentials.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/formatting.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/learn_prompt.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/mesh_config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/observer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/overview/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/overview/collector.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/overview/model.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/overview/web/style.css +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/persistence.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/pidfile.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/commands.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/extensions/events.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/message.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/protocol/replies.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/README.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/agentirc/architecture-overview.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/agentirc/bots.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/agentirc/events.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/agentirc/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/agentirc/why-agentirc.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/agent-lifecycle.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/choose-a-harness.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/features.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/mental-model.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/operate.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/patterns.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/quickstart.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/reflective-development.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/vision-patterns-index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/vision.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/culture/what-is-culture.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/architecture/agent-harness-spec.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/architecture/layers.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/architecture/threads.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/cli/afi.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/cli/commands.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/cli/devex.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/cli/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/console.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/harnesses/acp.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/harnesses/claude.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/harnesses/codex.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/harnesses/copilot.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/harnesses/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/server/architecture.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/server/deployment.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/server/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/reference/server/security.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/resources/positioning.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/concepts/federation.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/concepts/harnesses.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/concepts/humans-and-agents.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/concepts/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/concepts/persistence.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/concepts/rooms.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/demos/magic-demo.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/guides/first-session.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/guides/index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/guides/join-as-human.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/guides/local-setup.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/guides/multi-machine.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/shared/use-cases-index.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-09-decentralized-agent-config.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-12-console-enhancements.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-15-mesh-events.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-18-culture-dev-positioning.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/plans/2026-04-22-agex-integration.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-07-reflective-development-reframe-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-08-reflective-development-deepening-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-09-decentralized-agent-config-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-12-console-enhancements-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-15-mesh-events-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-17-sites-repositioning-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-18-culture-dev-positioning-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/docs/superpowers/specs/2026-04-22-agex-integration-design.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/favicon.ico +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/culture.yaml +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/robots.txt +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/sitemap-agentirc.html +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/sitemap-main.html +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/sonar-project.properties +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/__init__.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_archive.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_bot.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_bot_config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_bot_config_fires_event_toplevel.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_channel.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_channel_cli.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_cli_afi.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_cli_devex.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_cli_introspect.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_cli_passthrough.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_connection.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_chat_markdown.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_commands.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_connection.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_fixes_224_227.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_icons.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_integration.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_console_status.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_credentials.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_culture_config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_daemon.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_discovery.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_display.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_basic.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_bot_chain.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_bot_trigger.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_cap_fallback.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_catalog.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_federation.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_history.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_lifecycle.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_events_reserved_nick.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_filter_dsl.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_history.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_http_listener.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_ipc.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_irc_transport_tags.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_learn_prompt.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_manifest_config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_mention_warning.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_mentions.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_mesh_readiness.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_message.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_message_tags.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_messaging.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_migrate_cli.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_modes.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_overview_model.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_overview_web.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_persistence.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_persistence_timeout.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_pidfile.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_register_cli.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_rooms.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_skill_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_skill_docs.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_skills.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_socket_server.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_supervisor.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_template_engine.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_threads.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_wait_for_port.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_webhook.py +0 -0
- {agentirc_cli-8.1.0 → agentirc_cli-8.3.0}/tests/test_welcome_bot.py +0 -0
|
@@ -4,6 +4,38 @@ 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
|
+
## [8.3.0] - 2026-04-25
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `irc.s2s.session` span over ServerLink connection lifetime.
|
|
12
|
+
- `irc.s2s.<VERB>` per-verb spans on inbound federation messages with traceparent extraction and the inbound mitigation rules from `culture/protocol/extensions/tracing.md`.
|
|
13
|
+
- `irc.s2s.relay` span on outbound relay enforcing the re-sign-per-hop rule.
|
|
14
|
+
- `irc.client.session` span over Client connection lifetime (#290).
|
|
15
|
+
- `irc.join` and `irc.part` spans (#290).
|
|
16
|
+
- Public `culture.telemetry.context_from_traceparent` and `culture.telemetry.current_traceparent` helpers.
|
|
17
|
+
- Single traceparent injection choke point at `ServerLink.send_raw`.
|
|
18
|
+
- End-to-end propagation tests proving one `trace_id` spans federated client → server → relay → server hops.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `Client._dispatch` span name and `irc.command` attribute now uppercase, matching `ServerLink._dispatch` convention.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- `_replay_event` uses the hasattr-guarded comparison so string-typed federated `event.type` no longer skips the typed fast path. (#291)
|
|
27
|
+
|
|
28
|
+
## [8.2.0] - 2026-04-24
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- OpenTelemetry foundation: `culture/telemetry/` package with TracerProvider bootstrap, W3C trace context extract/inject helpers for IRCv3 tags, and `TelemetryConfig` block in `server.yaml`.
|
|
33
|
+
- Protocol extension: `culture.dev/traceparent` and `culture.dev/tracestate` IRCv3 tags (`culture/protocol/extensions/tracing.md`).
|
|
34
|
+
- Server-side tracing: `IRCd.emit_event`, `Client._dispatch`, `Client._process_buffer` (with parse-error compensation), and PRIVMSG dispatch/delivery paths now emit spans.
|
|
35
|
+
- Outbound traceparent injection on `Client.send` and `Client.send_raw` when a span is active.
|
|
36
|
+
- Operator docs at `docs/agentirc/telemetry.md` and starter collector config at `docs/agentirc/otelcol-template.yaml`; `docs/reference/server/config.md` documents the new `telemetry` block.
|
|
37
|
+
- Dependencies: `opentelemetry-api`, `opentelemetry-sdk`, `opentelemetry-exporter-otlp-proto-grpc`, `opentelemetry-semantic-conventions`.
|
|
38
|
+
|
|
7
39
|
## [8.1.0] - 2026-04-23
|
|
8
40
|
|
|
9
41
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentirc-cli
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.3.0
|
|
4
4
|
Summary: Legacy alias for culture — install culture instead
|
|
5
5
|
Project-URL: Homepage, https://github.com/OriNachum/culture
|
|
6
6
|
Author: Ori Nachum
|
|
@@ -18,6 +18,10 @@ Requires-Dist: aiohttp>=3.9
|
|
|
18
18
|
Requires-Dist: anthropic>=0.40
|
|
19
19
|
Requires-Dist: claude-agent-sdk>=0.1
|
|
20
20
|
Requires-Dist: mistune>=3.0
|
|
21
|
+
Requires-Dist: opentelemetry-api>=1.25
|
|
22
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25
|
|
23
|
+
Requires-Dist: opentelemetry-sdk>=1.25
|
|
24
|
+
Requires-Dist: opentelemetry-semantic-conventions>=0.46b0
|
|
21
25
|
Requires-Dist: pyyaml>=6.0
|
|
22
26
|
Requires-Dist: textual>=1.0
|
|
23
27
|
Provides-Extra: copilot
|
|
@@ -36,6 +36,8 @@ aux_links:
|
|
|
36
36
|
- "/agentirc/"
|
|
37
37
|
"Agent Experience":
|
|
38
38
|
- "https://culture.dev/agex/"
|
|
39
|
+
"Agent First Interop":
|
|
40
|
+
- "https://culture.dev/afi/"
|
|
39
41
|
"Citation CLI":
|
|
40
42
|
- "/citation-cli/"
|
|
41
43
|
"GitHub":
|
|
@@ -49,5 +51,6 @@ footer_content: >-
|
|
|
49
51
|
Inspectable CLI via <a href="/reference/cli/devex/">culture devex</a>
|
|
50
52
|
(explain / overview / learn at every level).
|
|
51
53
|
Agent Experience via <a href="https://culture.dev/agex/">agex-cli</a>.
|
|
54
|
+
Agent First Interop via <a href="https://culture.dev/afi/">afi-cli</a>.
|
|
52
55
|
Code distribution via <a href="/citation-cli/">Citation CLI</a>.
|
|
53
56
|
Source on <a href="https://github.com/agentculture/culture">GitHub</a>.
|
|
@@ -4,4 +4,5 @@
|
|
|
4
4
|
<link rel="icon" type="image/png" sizes="16x16" href="{{ '/assets/images/favicon-16x16.png' | relative_url }}">
|
|
5
5
|
<link rel="apple-touch-icon" sizes="180x180" href="{{ '/assets/images/apple-touch-icon.png' | relative_url }}">
|
|
6
6
|
<link rel="related" href="{{ site.data.sites.agex }}" title="Agent Experience">
|
|
7
|
+
<link rel="related" href="{{ site.data.sites.afi }}" title="Agent First Interop">
|
|
7
8
|
<link rel="related" href="{{ site.data.sites.citation_cli }}" title="Citation CLI">
|
|
@@ -6,12 +6,34 @@ import logging
|
|
|
6
6
|
import re
|
|
7
7
|
from typing import TYPE_CHECKING
|
|
8
8
|
|
|
9
|
+
from opentelemetry import trace as _otel_trace
|
|
10
|
+
from opentelemetry.context import Context as _OtelContext
|
|
11
|
+
from opentelemetry.trace import Span as _OtelSpan
|
|
12
|
+
|
|
9
13
|
from culture.agentirc.channel import Channel
|
|
10
14
|
from culture.agentirc.skill import Event, EventType
|
|
11
15
|
from culture.aio import maybe_await
|
|
12
16
|
from culture.constants import SYSTEM_USER_PREFIX
|
|
13
17
|
from culture.protocol import replies
|
|
14
18
|
from culture.protocol.message import Message
|
|
19
|
+
from culture.telemetry.context import TRACEPARENT_TAG as _TP_TAG_NAME
|
|
20
|
+
from culture.telemetry.context import (
|
|
21
|
+
context_from_traceparent,
|
|
22
|
+
current_traceparent,
|
|
23
|
+
extract_traceparent_from_tags,
|
|
24
|
+
)
|
|
25
|
+
from culture.telemetry.context import inject_traceparent as _inject_traceparent
|
|
26
|
+
|
|
27
|
+
# OTEL instrumentation name (must match `_CULTURE_TRACER_NAME` in
|
|
28
|
+
# culture/telemetry/tracing.py so trace consumers see one consistent value).
|
|
29
|
+
_TRACER_NAME = "culture.agentirc"
|
|
30
|
+
# Span attribute keys, defined once so a future rename / sanitization layer
|
|
31
|
+
# has one edit point.
|
|
32
|
+
_ATTR_BODY = "irc.message.body"
|
|
33
|
+
_ATTR_SIZE = "irc.message.size"
|
|
34
|
+
_ATTR_NICK = "irc.client.nick"
|
|
35
|
+
_ATTR_CHANNEL = "irc.channel"
|
|
36
|
+
|
|
15
37
|
|
|
16
38
|
if TYPE_CHECKING:
|
|
17
39
|
from culture.agentirc.ircd import IRCd
|
|
@@ -39,12 +61,21 @@ class Client:
|
|
|
39
61
|
self.caps: set[str] = set()
|
|
40
62
|
self.modes: set[str] = set()
|
|
41
63
|
self.icon: str | None = None
|
|
64
|
+
self._session_span: _OtelSpan | None = None
|
|
42
65
|
|
|
43
66
|
@property
|
|
44
67
|
def prefix(self) -> str:
|
|
45
68
|
return f"{self.nick}!{self.user}@{self.host}"
|
|
46
69
|
|
|
47
70
|
async def send(self, message: Message) -> None:
|
|
71
|
+
# Only inject trace context for clients that negotiated IRCv3
|
|
72
|
+
# message-tags; otherwise older clients would see an unexpected @-tag
|
|
73
|
+
# block and `send_tagged`'s tag-stripping for non-capable clients
|
|
74
|
+
# would be undone here.
|
|
75
|
+
if "message-tags" in self.caps:
|
|
76
|
+
tp = current_traceparent()
|
|
77
|
+
if tp is not None:
|
|
78
|
+
_inject_traceparent(message, traceparent=tp, tracestate=None)
|
|
48
79
|
try:
|
|
49
80
|
self.writer.write(message.format().encode("utf-8"))
|
|
50
81
|
await self.writer.drain()
|
|
@@ -55,7 +86,15 @@ class Client:
|
|
|
55
86
|
"""Write a pre-formatted IRC line to the client socket.
|
|
56
87
|
|
|
57
88
|
Appends CRLF internally, matching ServerLink.send_raw convention.
|
|
89
|
+
Injects `culture.dev/traceparent` as an IRCv3 tag when a span is active
|
|
90
|
+
AND the client negotiated the `message-tags` capability.
|
|
58
91
|
"""
|
|
92
|
+
if "message-tags" in self.caps:
|
|
93
|
+
tp = current_traceparent()
|
|
94
|
+
if tp is not None:
|
|
95
|
+
# send_raw takes a pre-formatted line without an existing tag
|
|
96
|
+
# block; prefix a fresh @tag.
|
|
97
|
+
line = f"@{_TP_TAG_NAME}={tp} {line}"
|
|
59
98
|
try:
|
|
60
99
|
self.writer.write(f"{line}\r\n".encode("utf-8"))
|
|
61
100
|
await self.writer.drain()
|
|
@@ -84,46 +123,94 @@ class Client:
|
|
|
84
123
|
|
|
85
124
|
async def _process_buffer(self, buffer: str) -> str:
|
|
86
125
|
"""Parse and dispatch all complete lines from buffer, return remainder."""
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
126
|
+
# Per-call get_tracer: test fixture swaps provider between tests.
|
|
127
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
128
|
+
"irc.client.process_buffer"
|
|
129
|
+
) as span:
|
|
130
|
+
while "\n" in buffer:
|
|
131
|
+
line, buffer = buffer.split("\n", 1)
|
|
132
|
+
if not line.strip():
|
|
133
|
+
continue
|
|
134
|
+
try:
|
|
135
|
+
msg = Message.parse(line)
|
|
136
|
+
except Exception as exc: # noqa: BLE001 -- widen for any parser failure
|
|
137
|
+
span.add_event(
|
|
138
|
+
"irc.parse_error",
|
|
139
|
+
attributes={
|
|
140
|
+
"line_preview": line[:64],
|
|
141
|
+
"error": type(exc).__name__,
|
|
142
|
+
},
|
|
143
|
+
)
|
|
144
|
+
continue
|
|
91
145
|
if msg.command:
|
|
92
146
|
await self._dispatch(msg)
|
|
93
|
-
|
|
147
|
+
return buffer
|
|
94
148
|
|
|
95
149
|
async def handle(self, initial_msg: str | None = None) -> None:
|
|
96
|
-
|
|
97
|
-
if
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
150
|
+
peer_info = self.writer.get_extra_info("peername")
|
|
151
|
+
remote_addr = f"{peer_info[0]}:{peer_info[1]}" if peer_info else ""
|
|
152
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
153
|
+
"irc.client.session",
|
|
154
|
+
attributes={"irc.client.remote_addr": remote_addr},
|
|
155
|
+
) as span:
|
|
156
|
+
self._session_span = span
|
|
157
|
+
try:
|
|
158
|
+
buffer = ""
|
|
159
|
+
if initial_msg:
|
|
160
|
+
buffer = initial_msg.replace("\r\n", "\n").replace("\r", "\n")
|
|
161
|
+
buffer = await self._process_buffer(buffer)
|
|
162
|
+
while True:
|
|
163
|
+
data = await self.reader.read(4096)
|
|
164
|
+
if not data:
|
|
165
|
+
break
|
|
166
|
+
buffer += data.decode("utf-8", errors="replace")
|
|
167
|
+
# Cap buffer to prevent unbounded memory growth (512 bytes per RFC 2812)
|
|
168
|
+
if len(buffer) > 8192:
|
|
169
|
+
buffer = buffer[-4096:]
|
|
170
|
+
# Normalize all line endings to \n for simpler parsing
|
|
171
|
+
buffer = buffer.replace("\r\n", "\n").replace("\r", "\n")
|
|
172
|
+
buffer = await self._process_buffer(buffer)
|
|
173
|
+
except (ConnectionError, asyncio.IncompleteReadError):
|
|
174
|
+
pass
|
|
111
175
|
|
|
112
176
|
async def _dispatch(self, msg: Message) -> None:
|
|
113
|
-
|
|
114
|
-
if
|
|
115
|
-
|
|
177
|
+
extract = extract_traceparent_from_tags(msg, peer=None)
|
|
178
|
+
if extract.status == "valid":
|
|
179
|
+
parent_ctx: _OtelContext | None = context_from_traceparent(extract.traceparent)
|
|
116
180
|
else:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
181
|
+
parent_ctx = _OtelContext() # force root: detach from session span
|
|
182
|
+
|
|
183
|
+
verb = msg.command.upper()
|
|
184
|
+
attrs = {
|
|
185
|
+
"irc.command": verb,
|
|
186
|
+
"irc.prefix_nick": (msg.prefix.split("!")[0] if msg.prefix else ""),
|
|
187
|
+
"culture.trace.origin": "local" if extract.status == "missing" else "remote",
|
|
188
|
+
}
|
|
189
|
+
if extract.status in ("malformed", "too_long"):
|
|
190
|
+
attrs["culture.trace.dropped_reason"] = extract.status
|
|
191
|
+
|
|
192
|
+
# Per-call get_tracer: test fixture swaps provider between tests.
|
|
193
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
194
|
+
f"irc.command.{verb}",
|
|
195
|
+
context=parent_ctx,
|
|
196
|
+
attributes=attrs,
|
|
197
|
+
):
|
|
198
|
+
handler = getattr(self, f"_handle_{msg.command.lower()}", None)
|
|
199
|
+
if handler:
|
|
200
|
+
await maybe_await(handler(msg))
|
|
125
201
|
else:
|
|
126
|
-
|
|
202
|
+
skill = self.server.get_skill_for_command(msg.command)
|
|
203
|
+
if skill and self._registered:
|
|
204
|
+
try:
|
|
205
|
+
await skill.on_command(self, msg)
|
|
206
|
+
except Exception:
|
|
207
|
+
logging.getLogger(__name__).exception(
|
|
208
|
+
"Skill %s failed on command %s", skill.name, msg.command
|
|
209
|
+
)
|
|
210
|
+
else:
|
|
211
|
+
await self.send_numeric(
|
|
212
|
+
replies.ERR_UNKNOWNCOMMAND, msg.command, "Unknown command"
|
|
213
|
+
)
|
|
127
214
|
|
|
128
215
|
async def _handle_ping(self, msg: Message) -> None:
|
|
129
216
|
token = msg.params[0] if msg.params else ""
|
|
@@ -205,6 +292,8 @@ class Client:
|
|
|
205
292
|
|
|
206
293
|
self.nick = nick
|
|
207
294
|
self.server.clients[nick] = self
|
|
295
|
+
if self._session_span is not None:
|
|
296
|
+
self._session_span.set_attribute(_ATTR_NICK, nick)
|
|
208
297
|
await self._try_register()
|
|
209
298
|
|
|
210
299
|
async def _handle_user(self, msg: Message) -> None:
|
|
@@ -256,45 +345,49 @@ class Client:
|
|
|
256
345
|
return
|
|
257
346
|
|
|
258
347
|
channel_name = msg.params[0]
|
|
259
|
-
|
|
260
|
-
|
|
348
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
349
|
+
"irc.join",
|
|
350
|
+
attributes={_ATTR_CHANNEL: channel_name, _ATTR_NICK: self.nick or ""},
|
|
351
|
+
):
|
|
352
|
+
if not channel_name.startswith("#"):
|
|
353
|
+
return
|
|
261
354
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
355
|
+
# Block joins to archived rooms
|
|
356
|
+
existing = self.server.channels.get(channel_name)
|
|
357
|
+
if existing and existing.archived:
|
|
358
|
+
await self.send(
|
|
359
|
+
Message(
|
|
360
|
+
prefix=self.server.config.name,
|
|
361
|
+
command="NOTICE",
|
|
362
|
+
params=[self.nick, f"{channel_name} is archived and cannot be joined"],
|
|
363
|
+
)
|
|
270
364
|
)
|
|
271
|
-
|
|
272
|
-
return
|
|
365
|
+
return
|
|
273
366
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
367
|
+
channel = self.server.get_or_create_channel(channel_name)
|
|
368
|
+
if self in channel.members:
|
|
369
|
+
return
|
|
277
370
|
|
|
278
|
-
|
|
279
|
-
|
|
371
|
+
channel.add(self)
|
|
372
|
+
self.channels.add(channel)
|
|
280
373
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
374
|
+
# Notify all channel members (including self)
|
|
375
|
+
join_msg = Message(prefix=self.prefix, command="JOIN", params=[channel_name])
|
|
376
|
+
for member in list(channel.members):
|
|
377
|
+
await member.send(join_msg)
|
|
285
378
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
379
|
+
# Send topic if set
|
|
380
|
+
if channel.topic:
|
|
381
|
+
await self.send_numeric(replies.RPL_TOPIC, channel_name, channel.topic)
|
|
289
382
|
|
|
290
|
-
|
|
291
|
-
|
|
383
|
+
# Send names list
|
|
384
|
+
await self._send_names(channel)
|
|
292
385
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
386
|
+
# Emit event AFTER delivering all join-related numerics (topic, NAMES)
|
|
387
|
+
# so that the event PRIVMSG doesn't interleave with 353/366 in client buffers.
|
|
388
|
+
await self.server.emit_event(
|
|
389
|
+
Event(type=EventType.JOIN, channel=channel_name, nick=self.nick)
|
|
390
|
+
)
|
|
298
391
|
|
|
299
392
|
async def _handle_part(self, msg: Message) -> None:
|
|
300
393
|
if not msg.params:
|
|
@@ -302,36 +395,40 @@ class Client:
|
|
|
302
395
|
return
|
|
303
396
|
|
|
304
397
|
channel_name = msg.params[0]
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
398
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
399
|
+
"irc.part",
|
|
400
|
+
attributes={_ATTR_CHANNEL: channel_name, _ATTR_NICK: self.nick or ""},
|
|
401
|
+
):
|
|
402
|
+
reason = msg.params[1] if len(msg.params) > 1 else ""
|
|
403
|
+
|
|
404
|
+
channel = self.server.channels.get(channel_name)
|
|
405
|
+
if not channel or self not in channel.members:
|
|
406
|
+
await self.send_numeric(
|
|
407
|
+
replies.ERR_NOTONCHANNEL,
|
|
408
|
+
channel_name,
|
|
409
|
+
replies.MSG_NOTONCHANNEL,
|
|
410
|
+
)
|
|
411
|
+
return
|
|
315
412
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
413
|
+
part_params = [channel_name, reason] if reason else [channel_name]
|
|
414
|
+
part_msg = Message(prefix=self.prefix, command="PART", params=part_params)
|
|
415
|
+
for member in list(channel.members):
|
|
416
|
+
await member.send(part_msg)
|
|
320
417
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
418
|
+
await self.server.emit_event(
|
|
419
|
+
Event(
|
|
420
|
+
type=EventType.PART,
|
|
421
|
+
channel=channel_name,
|
|
422
|
+
nick=self.nick,
|
|
423
|
+
data={"reason": reason},
|
|
424
|
+
)
|
|
327
425
|
)
|
|
328
|
-
)
|
|
329
426
|
|
|
330
|
-
|
|
331
|
-
|
|
427
|
+
channel.remove(self)
|
|
428
|
+
self.channels.discard(channel)
|
|
332
429
|
|
|
333
|
-
|
|
334
|
-
|
|
430
|
+
if not channel.members and not channel.persistent:
|
|
431
|
+
del self.server.channels[channel_name]
|
|
335
432
|
|
|
336
433
|
async def _handle_topic(self, msg: Message) -> None:
|
|
337
434
|
if not msg.params:
|
|
@@ -615,46 +712,64 @@ class Client:
|
|
|
615
712
|
await self.send_numeric(replies.RPL_UMODEIS, mode_str)
|
|
616
713
|
|
|
617
714
|
async def _send_to_channel(self, channel, target, relay, text, is_notice):
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
715
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
716
|
+
"irc.privmsg.deliver.channel",
|
|
717
|
+
attributes={
|
|
718
|
+
"irc.channel": target,
|
|
719
|
+
_ATTR_BODY: text,
|
|
720
|
+
_ATTR_SIZE: len(text),
|
|
721
|
+
"irc.notice": is_notice,
|
|
722
|
+
},
|
|
723
|
+
):
|
|
724
|
+
for member in list(channel.members):
|
|
725
|
+
if member is not self:
|
|
726
|
+
await member.send(relay)
|
|
727
|
+
event_data = {"text": text}
|
|
728
|
+
if is_notice:
|
|
729
|
+
event_data["notice"] = True
|
|
730
|
+
await self.server.emit_event(
|
|
731
|
+
Event(
|
|
732
|
+
type=EventType.MESSAGE,
|
|
733
|
+
channel=target,
|
|
734
|
+
nick=self.nick,
|
|
735
|
+
data=event_data,
|
|
736
|
+
)
|
|
630
737
|
)
|
|
631
|
-
)
|
|
632
738
|
|
|
633
739
|
async def _send_to_client(self, target, relay, text, is_notice):
|
|
634
740
|
from culture.agentirc.remote_client import RemoteClient
|
|
635
741
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
742
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
743
|
+
"irc.privmsg.deliver.dm",
|
|
744
|
+
attributes={
|
|
745
|
+
"irc.target.nick": target,
|
|
746
|
+
_ATTR_BODY: text,
|
|
747
|
+
_ATTR_SIZE: len(text),
|
|
748
|
+
"irc.notice": is_notice,
|
|
749
|
+
},
|
|
750
|
+
):
|
|
751
|
+
recipient = self.server.get_client(target)
|
|
752
|
+
if not recipient:
|
|
753
|
+
return False
|
|
754
|
+
if isinstance(recipient, RemoteClient):
|
|
755
|
+
s2s_cmd = "SNOTICE" if is_notice else "SMSG"
|
|
756
|
+
await recipient.link.send_raw(
|
|
757
|
+
f":{self.server.config.name} {s2s_cmd} {target} {self.nick} :{text}"
|
|
758
|
+
)
|
|
759
|
+
else:
|
|
760
|
+
await recipient.send(relay)
|
|
761
|
+
event_data = {"text": text, "target": target}
|
|
762
|
+
if is_notice:
|
|
763
|
+
event_data["notice"] = True
|
|
764
|
+
await self.server.emit_event(
|
|
765
|
+
Event(
|
|
766
|
+
type=EventType.MESSAGE,
|
|
767
|
+
channel=None,
|
|
768
|
+
nick=self.nick,
|
|
769
|
+
data=event_data,
|
|
770
|
+
)
|
|
655
771
|
)
|
|
656
|
-
|
|
657
|
-
return True
|
|
772
|
+
return True
|
|
658
773
|
|
|
659
774
|
async def _handle_privmsg(self, msg: Message) -> None:
|
|
660
775
|
if len(msg.params) < 2:
|
|
@@ -665,28 +780,37 @@ class Client:
|
|
|
665
780
|
|
|
666
781
|
target = msg.params[0]
|
|
667
782
|
text = msg.params[1]
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
)
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
783
|
+
# Per-call get_tracer: test fixture swaps provider between tests.
|
|
784
|
+
with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
|
|
785
|
+
"irc.privmsg.dispatch",
|
|
786
|
+
attributes={
|
|
787
|
+
"irc.target": target,
|
|
788
|
+
_ATTR_BODY: text,
|
|
789
|
+
_ATTR_SIZE: len(text),
|
|
790
|
+
},
|
|
791
|
+
):
|
|
792
|
+
relay = Message(prefix=self.prefix, command="PRIVMSG", params=[target, text])
|
|
793
|
+
|
|
794
|
+
if target.startswith("#"):
|
|
795
|
+
channel = self.server.channels.get(target)
|
|
796
|
+
if not channel:
|
|
797
|
+
await self.send_numeric(
|
|
798
|
+
replies.ERR_NOSUCHCHANNEL, target, replies.MSG_NOSUCHCHANNEL
|
|
799
|
+
)
|
|
800
|
+
return
|
|
801
|
+
if self not in channel.members:
|
|
802
|
+
await self.send_numeric(
|
|
803
|
+
replies.ERR_CANNOTSENDTOCHAN, target, "Cannot send to channel"
|
|
804
|
+
)
|
|
805
|
+
return
|
|
806
|
+
await self._send_to_channel(channel, target, relay, text, False)
|
|
807
|
+
await self._notify_mentions(target, text)
|
|
808
|
+
else:
|
|
809
|
+
found = await self._send_to_client(target, relay, text, False)
|
|
810
|
+
if not found:
|
|
811
|
+
await self.send_numeric(replies.ERR_NOSUCHNICK, target, replies.MSG_NOSUCHNICK)
|
|
812
|
+
return
|
|
813
|
+
await self._notify_mentions(None, text)
|
|
690
814
|
|
|
691
815
|
async def _notify_mentions(self, channel_name: str | None, text: str) -> None:
|
|
692
816
|
from culture.agentirc.remote_client import RemoteClient
|
|
@@ -12,6 +12,20 @@ class LinkConfig:
|
|
|
12
12
|
trust: str = "full" # "full" or "restricted"
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
@dataclass
|
|
16
|
+
class TelemetryConfig:
|
|
17
|
+
"""OpenTelemetry settings. Mirrors server.yaml `telemetry:` block."""
|
|
18
|
+
|
|
19
|
+
enabled: bool = False
|
|
20
|
+
service_name: str = "culture.agentirc"
|
|
21
|
+
otlp_endpoint: str = "http://localhost:4317"
|
|
22
|
+
otlp_protocol: str = "grpc" # grpc | http/protobuf (only grpc supported initially)
|
|
23
|
+
otlp_timeout_ms: int = 5000
|
|
24
|
+
otlp_compression: str = "gzip" # gzip | none
|
|
25
|
+
traces_enabled: bool = True
|
|
26
|
+
traces_sampler: str = "parentbased_always_on"
|
|
27
|
+
|
|
28
|
+
|
|
15
29
|
@dataclass
|
|
16
30
|
class ServerConfig:
|
|
17
31
|
"""Configuration for a culture server instance."""
|
|
@@ -23,3 +37,4 @@ class ServerConfig:
|
|
|
23
37
|
data_dir: str = ""
|
|
24
38
|
links: list[LinkConfig] = field(default_factory=list)
|
|
25
39
|
system_bots: dict = field(default_factory=dict)
|
|
40
|
+
telemetry: TelemetryConfig = field(default_factory=TelemetryConfig)
|