agentirc-cli 4.3.2__tar.gz → 4.3.3__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-4.3.2 → agentirc_cli-4.3.3}/CHANGELOG.md +7 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/PKG-INFO +1 -1
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/agent_runner.py +46 -36
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/daemon.py +22 -16
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/skill/irc_client.py +98 -57
- {agentirc_cli-4.3.2/culture/clients/claude → agentirc_cli-4.3.3/culture/clients/acp}/supervisor.py +8 -4
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/agent_runner.py +14 -6
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/skill/irc_client.py +98 -57
- {agentirc_cli-4.3.2/culture/clients/acp → agentirc_cli-4.3.3/culture/clients/claude}/supervisor.py +8 -4
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/agent_runner.py +41 -31
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/daemon.py +22 -16
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/skill/irc_client.py +98 -57
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/supervisor.py +22 -14
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/agent_runner.py +26 -17
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/daemon.py +22 -16
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/skill/irc_client.py +98 -57
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/supervisor.py +25 -15
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/observer.py +55 -90
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/overview/collector.py +64 -41
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/overview/renderer_text.py +67 -39
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/overview/renderer_web.py +22 -14
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/persistence.py +34 -19
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/client.py +146 -154
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/ircd.py +16 -11
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/server_link.py +125 -133
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/skills/rooms.py +34 -24
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/skill/irc_client.py +98 -57
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/pyproject.toml +1 -1
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/uv.lock +1 -1
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.flake8 +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.gitignore +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.pr_agent.toml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/.pylintrc +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/CLAUDE.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/CNAME +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/Gemfile +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/Gemfile.lock +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/LICENSE +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/README.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/SECURITY.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/_config.yml +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/__main__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/aio.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/bots/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/bots/bot.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/bots/config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/_helpers.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/agent.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/bot.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/channel.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/mesh.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/server.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/cli/skills.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/irc_transport.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/daemon.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/app.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/client.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/commands.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/credentials.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/learn_prompt.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/mesh_config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/overview/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/overview/model.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/overview/web/style.css +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/pidfile.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/commands.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/message.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/protocol/replies.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/__main__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/channel.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/remote_client.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/room_store.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/skill.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/skills/history.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/skills/icon.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/skills/threads.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/server/thread_store.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/agent-client.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/agent-harness-spec.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/harness-conformance.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/index.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/layer2-attention.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/layer3-skills.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/layer4-federation.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/server-architecture.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/architecture/threads.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/channel-polling.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/culture-cli.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/getting-started.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/index.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/SECURITY.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/bots.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/ci.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/cli.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/docs-site.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/index.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/ops-tooling.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/overview.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/operations/publishing.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/rooms.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/server-rename.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/use-cases-index.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/docs/what-is-culture.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/daemon.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/sonar-project.properties +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/__init__.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/conftest.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_archive.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_bot.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_bot_config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_channel.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_connection.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_console_client.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_console_commands.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_console_connection.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_console_icons.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_console_integration.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_daemon.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_discovery.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_federation.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_history.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_http_listener.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_ipc.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_mentions.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_message.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_messaging.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_modes.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_overview_model.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_overview_web.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_persistence.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_pidfile.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_rooms.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_skill_client.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_skills.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_socket_server.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_supervisor.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_template_engine.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_threads.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_wait_for_port.py +0 -0
- {agentirc_cli-4.3.2 → agentirc_cli-4.3.3}/tests/test_webhook.py +0 -0
|
@@ -4,6 +4,13 @@ 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
|
+
## [4.3.3] - 2026-04-07
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Reduced cognitive complexity in 40 functions across 25 files to meet SonarCloud threshold (≤15)
|
|
13
|
+
|
|
7
14
|
## [4.3.2] - 2026-04-07
|
|
8
15
|
|
|
9
16
|
|
|
@@ -220,6 +220,48 @@ class ACPAgentRunner:
|
|
|
220
220
|
self._process.stdin.write(line.encode())
|
|
221
221
|
await self._process.stdin.drain()
|
|
222
222
|
|
|
223
|
+
def _dispatch_jsonrpc_message(self, msg: dict) -> bool:
|
|
224
|
+
"""Route a JSON-RPC response to its pending future.
|
|
225
|
+
|
|
226
|
+
Returns True if the message was a response (handled here),
|
|
227
|
+
False if it should be treated as a notification.
|
|
228
|
+
"""
|
|
229
|
+
if "id" in msg and ("result" in msg or "error" in msg):
|
|
230
|
+
req_id = msg["id"]
|
|
231
|
+
future = self._pending.pop(req_id, None)
|
|
232
|
+
if future and not future.done():
|
|
233
|
+
future.set_result(msg)
|
|
234
|
+
return True
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
async def _cleanup_process(self) -> None:
|
|
238
|
+
"""Wait for process exit, fail pending futures, cancel companion tasks, fire on_exit."""
|
|
239
|
+
returncode = -1
|
|
240
|
+
if self._process:
|
|
241
|
+
try:
|
|
242
|
+
returncode = await asyncio.wait_for(self._process.wait(), timeout=5)
|
|
243
|
+
except asyncio.TimeoutError:
|
|
244
|
+
try:
|
|
245
|
+
self._process.kill()
|
|
246
|
+
except ProcessLookupError:
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
# Fail any still-pending requests
|
|
250
|
+
for future in self._pending.values():
|
|
251
|
+
if not future.done():
|
|
252
|
+
future.set_exception(ConnectionError("Process exited"))
|
|
253
|
+
self._pending.clear()
|
|
254
|
+
|
|
255
|
+
self._running = False
|
|
256
|
+
|
|
257
|
+
# Cancel companion tasks so they don't outlive the process
|
|
258
|
+
for task in (self._task, self._stderr_task):
|
|
259
|
+
if task and not task.done():
|
|
260
|
+
task.cancel()
|
|
261
|
+
|
|
262
|
+
if not self._stopping and self.on_exit:
|
|
263
|
+
await self.on_exit(returncode)
|
|
264
|
+
|
|
223
265
|
async def _read_loop(self) -> None:
|
|
224
266
|
"""Read JSON-RPC messages from stdout."""
|
|
225
267
|
if not self._process or not self._process.stdout:
|
|
@@ -234,16 +276,9 @@ class ACPAgentRunner:
|
|
|
234
276
|
except json.JSONDecodeError:
|
|
235
277
|
continue
|
|
236
278
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
future = self._pending.pop(req_id, None)
|
|
241
|
-
if future and not future.done():
|
|
242
|
-
future.set_result(msg)
|
|
243
|
-
|
|
244
|
-
# Notification from server
|
|
245
|
-
elif "method" in msg:
|
|
246
|
-
await self._handle_notification(msg)
|
|
279
|
+
if not self._dispatch_jsonrpc_message(msg):
|
|
280
|
+
if "method" in msg:
|
|
281
|
+
await self._handle_notification(msg)
|
|
247
282
|
|
|
248
283
|
except asyncio.CancelledError:
|
|
249
284
|
raise
|
|
@@ -252,32 +287,7 @@ class ACPAgentRunner:
|
|
|
252
287
|
except Exception:
|
|
253
288
|
logger.exception("ACP read loop error")
|
|
254
289
|
finally:
|
|
255
|
-
|
|
256
|
-
returncode = -1
|
|
257
|
-
if self._process:
|
|
258
|
-
try:
|
|
259
|
-
returncode = await asyncio.wait_for(self._process.wait(), timeout=5)
|
|
260
|
-
except asyncio.TimeoutError:
|
|
261
|
-
try:
|
|
262
|
-
self._process.kill()
|
|
263
|
-
except ProcessLookupError:
|
|
264
|
-
pass
|
|
265
|
-
|
|
266
|
-
# Fail any still-pending requests
|
|
267
|
-
for future in self._pending.values():
|
|
268
|
-
if not future.done():
|
|
269
|
-
future.set_exception(ConnectionError("Process exited"))
|
|
270
|
-
self._pending.clear()
|
|
271
|
-
|
|
272
|
-
self._running = False
|
|
273
|
-
|
|
274
|
-
# Cancel companion tasks so they don't outlive the process
|
|
275
|
-
for task in (self._task, self._stderr_task):
|
|
276
|
-
if task and not task.done():
|
|
277
|
-
task.cancel()
|
|
278
|
-
|
|
279
|
-
if not self._stopping and self.on_exit:
|
|
280
|
-
await self.on_exit(returncode)
|
|
290
|
+
await self._cleanup_process()
|
|
281
291
|
|
|
282
292
|
async def _stderr_loop(self) -> None:
|
|
283
293
|
"""Log stderr output from the ACP agent process."""
|
|
@@ -281,27 +281,33 @@ class ACPDaemon:
|
|
|
281
281
|
while True:
|
|
282
282
|
try:
|
|
283
283
|
await asyncio.sleep(interval)
|
|
284
|
-
|
|
285
|
-
continue
|
|
286
|
-
for channel in self.agent.channels:
|
|
287
|
-
msgs = self._buffer.read(channel)
|
|
288
|
-
if not msgs:
|
|
289
|
-
continue
|
|
290
|
-
lines = "\n".join(f" <{m.nick}> {m.text}" for m in msgs)
|
|
291
|
-
prompt = (
|
|
292
|
-
f"[IRC Channel Poll: {channel}] Recent unread messages:\n"
|
|
293
|
-
f"{lines}\n\n"
|
|
294
|
-
f"Respond naturally if any messages need your attention."
|
|
295
|
-
)
|
|
296
|
-
self._mention_targets.append(channel)
|
|
297
|
-
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
298
|
-
self._background_tasks.add(task)
|
|
299
|
-
task.add_done_callback(self._background_tasks.discard)
|
|
284
|
+
self._process_poll_cycle()
|
|
300
285
|
except asyncio.CancelledError:
|
|
301
286
|
raise
|
|
302
287
|
except Exception:
|
|
303
288
|
logger.exception("Poll loop error")
|
|
304
289
|
|
|
290
|
+
def _process_poll_cycle(self) -> None:
|
|
291
|
+
if self._paused or not self._agent_runner or not self._agent_runner.is_running():
|
|
292
|
+
return
|
|
293
|
+
for channel in self.agent.channels:
|
|
294
|
+
self._send_channel_poll(channel)
|
|
295
|
+
|
|
296
|
+
def _send_channel_poll(self, channel) -> None:
|
|
297
|
+
msgs = self._buffer.read(channel)
|
|
298
|
+
if not msgs:
|
|
299
|
+
return
|
|
300
|
+
lines = "\n".join(f" <{m.nick}> {m.text}" for m in msgs)
|
|
301
|
+
prompt = (
|
|
302
|
+
f"[IRC Channel Poll: {channel}] Recent unread messages:\n"
|
|
303
|
+
f"{lines}\n\n"
|
|
304
|
+
f"Respond naturally if any messages need your attention."
|
|
305
|
+
)
|
|
306
|
+
self._mention_targets.append(channel)
|
|
307
|
+
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
308
|
+
self._background_tasks.add(task)
|
|
309
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
310
|
+
|
|
305
311
|
async def _graceful_shutdown(self) -> None:
|
|
306
312
|
"""Trigger a graceful shutdown, signaling any waiting stop event."""
|
|
307
313
|
logger.info("Graceful shutdown requested for %s", self.agent.nick)
|
|
@@ -83,14 +83,7 @@ class SkillClient:
|
|
|
83
83
|
msg = decode_message(line)
|
|
84
84
|
if msg is None:
|
|
85
85
|
continue
|
|
86
|
-
|
|
87
|
-
if msg_type == MSG_TYPE_RESPONSE:
|
|
88
|
-
req_id = msg.get("id", "")
|
|
89
|
-
future = self._pending.pop(req_id, None)
|
|
90
|
-
if future is not None and not future.done():
|
|
91
|
-
future.set_result(msg)
|
|
92
|
-
elif msg_type == MSG_TYPE_WHISPER:
|
|
93
|
-
self.pending_whispers.append(msg)
|
|
86
|
+
self._dispatch_message(msg)
|
|
94
87
|
except (asyncio.IncompleteReadError, ConnectionError, OSError):
|
|
95
88
|
pass
|
|
96
89
|
finally:
|
|
@@ -100,6 +93,17 @@ class SkillClient:
|
|
|
100
93
|
future.set_exception(ConnectionError("Connection lost"))
|
|
101
94
|
self._pending.clear()
|
|
102
95
|
|
|
96
|
+
def _dispatch_message(self, msg: dict[str, Any]) -> None:
|
|
97
|
+
"""Route a decoded message to the appropriate handler."""
|
|
98
|
+
msg_type = msg.get("type")
|
|
99
|
+
if msg_type == MSG_TYPE_RESPONSE:
|
|
100
|
+
req_id = msg.get("id", "")
|
|
101
|
+
future = self._pending.pop(req_id, None)
|
|
102
|
+
if future is not None and not future.done():
|
|
103
|
+
future.set_result(msg)
|
|
104
|
+
elif msg_type == MSG_TYPE_WHISPER:
|
|
105
|
+
self.pending_whispers.append(msg)
|
|
106
|
+
|
|
103
107
|
# ------------------------------------------------------------------
|
|
104
108
|
# Request dispatch
|
|
105
109
|
# ------------------------------------------------------------------
|
|
@@ -182,6 +186,86 @@ def _sock_path_from_env() -> str:
|
|
|
182
186
|
return os.path.join(runtime_dir, f"culture-{nick}.sock")
|
|
183
187
|
|
|
184
188
|
|
|
189
|
+
def _parse_ask_timeout(remaining: list[str]) -> tuple[int, list[str]]:
|
|
190
|
+
"""Extract --timeout N from args, returning (timeout, filtered_args)."""
|
|
191
|
+
if "--timeout" in remaining:
|
|
192
|
+
idx = remaining.index("--timeout")
|
|
193
|
+
if idx + 1 >= len(remaining):
|
|
194
|
+
print("ERROR: --timeout requires a value", file=sys.stderr)
|
|
195
|
+
sys.exit(2)
|
|
196
|
+
try:
|
|
197
|
+
timeout = int(remaining[idx + 1])
|
|
198
|
+
except ValueError:
|
|
199
|
+
print(
|
|
200
|
+
f"ERROR: --timeout value must be an integer, got {remaining[idx + 1]!r}",
|
|
201
|
+
file=sys.stderr,
|
|
202
|
+
)
|
|
203
|
+
sys.exit(2)
|
|
204
|
+
if timeout <= 0:
|
|
205
|
+
print("ERROR: --timeout must be positive", file=sys.stderr)
|
|
206
|
+
sys.exit(2)
|
|
207
|
+
remaining = remaining[:idx] + remaining[idx + 2 :]
|
|
208
|
+
else:
|
|
209
|
+
timeout = 30
|
|
210
|
+
return timeout, remaining
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
async def _cmd_send(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
214
|
+
channel = args[1]
|
|
215
|
+
message = " ".join(args[2:])
|
|
216
|
+
return await client.irc_send(channel, message)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
async def _cmd_read(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
220
|
+
channel = args[1]
|
|
221
|
+
limit = int(args[2]) if len(args) > 2 else 50
|
|
222
|
+
return await client.irc_read(channel, limit=limit)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
async def _cmd_ask(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
226
|
+
channel = args[1]
|
|
227
|
+
timeout, remaining = _parse_ask_timeout(args[2:])
|
|
228
|
+
question = " ".join(remaining)
|
|
229
|
+
return await client.irc_ask(channel, question, timeout=timeout)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
async def _cmd_join(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
233
|
+
return await client.irc_join(args[1])
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async def _cmd_part(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
237
|
+
return await client.irc_part(args[1])
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
async def _cmd_channels(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
241
|
+
return await client.irc_channels()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
async def _cmd_who(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
245
|
+
return await client.irc_who(args[1])
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
async def _cmd_compact(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
249
|
+
return await client.compact()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
async def _cmd_clear(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
253
|
+
return await client.clear()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
_SUBCOMMANDS: dict[str, Any] = {
|
|
257
|
+
"send": _cmd_send,
|
|
258
|
+
"read": _cmd_read,
|
|
259
|
+
"ask": _cmd_ask,
|
|
260
|
+
"join": _cmd_join,
|
|
261
|
+
"part": _cmd_part,
|
|
262
|
+
"channels": _cmd_channels,
|
|
263
|
+
"who": _cmd_who,
|
|
264
|
+
"compact": _cmd_compact,
|
|
265
|
+
"clear": _cmd_clear,
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
185
269
|
async def _main(args: list[str]) -> None:
|
|
186
270
|
"""CLI entry point. First arg is the subcommand."""
|
|
187
271
|
if not args:
|
|
@@ -195,59 +279,16 @@ async def _main(args: list[str]) -> None:
|
|
|
195
279
|
sock_path = _sock_path_from_env()
|
|
196
280
|
subcommand = args[0]
|
|
197
281
|
|
|
282
|
+
handler = _SUBCOMMANDS.get(subcommand)
|
|
283
|
+
if handler is None:
|
|
284
|
+
print(f"ERROR: Unknown subcommand: {subcommand!r}", file=sys.stderr)
|
|
285
|
+
sys.exit(1)
|
|
286
|
+
|
|
198
287
|
client = SkillClient(sock_path)
|
|
199
288
|
await client.connect()
|
|
200
289
|
|
|
201
290
|
try:
|
|
202
|
-
|
|
203
|
-
# send <channel> <message...>
|
|
204
|
-
channel = args[1]
|
|
205
|
-
message = " ".join(args[2:])
|
|
206
|
-
result = await client.irc_send(channel, message)
|
|
207
|
-
|
|
208
|
-
elif subcommand == "read":
|
|
209
|
-
# read <channel> [limit]
|
|
210
|
-
channel = args[1]
|
|
211
|
-
limit = int(args[2]) if len(args) > 2 else 50
|
|
212
|
-
result = await client.irc_read(channel, limit=limit)
|
|
213
|
-
|
|
214
|
-
elif subcommand == "ask":
|
|
215
|
-
# ask <channel> [--timeout N] <question...>
|
|
216
|
-
channel = args[1]
|
|
217
|
-
remaining = args[2:]
|
|
218
|
-
if "--timeout" in remaining:
|
|
219
|
-
idx = remaining.index("--timeout")
|
|
220
|
-
timeout = int(remaining[idx + 1])
|
|
221
|
-
remaining = remaining[:idx] + remaining[idx + 2 :]
|
|
222
|
-
else:
|
|
223
|
-
timeout = 30
|
|
224
|
-
question = " ".join(remaining)
|
|
225
|
-
result = await client.irc_ask(channel, question, timeout=timeout)
|
|
226
|
-
|
|
227
|
-
elif subcommand == "join":
|
|
228
|
-
channel = args[1]
|
|
229
|
-
result = await client.irc_join(channel)
|
|
230
|
-
|
|
231
|
-
elif subcommand == "part":
|
|
232
|
-
channel = args[1]
|
|
233
|
-
result = await client.irc_part(channel)
|
|
234
|
-
|
|
235
|
-
elif subcommand == "channels":
|
|
236
|
-
result = await client.irc_channels()
|
|
237
|
-
|
|
238
|
-
elif subcommand == "who":
|
|
239
|
-
target = args[1]
|
|
240
|
-
result = await client.irc_who(target)
|
|
241
|
-
|
|
242
|
-
elif subcommand == "compact":
|
|
243
|
-
result = await client.compact()
|
|
244
|
-
|
|
245
|
-
elif subcommand == "clear":
|
|
246
|
-
result = await client.clear()
|
|
247
|
-
|
|
248
|
-
else:
|
|
249
|
-
print(f"ERROR: Unknown subcommand: {subcommand!r}", file=sys.stderr)
|
|
250
|
-
sys.exit(1)
|
|
291
|
+
result = await handler(client, args)
|
|
251
292
|
|
|
252
293
|
# Print result as JSON
|
|
253
294
|
print(json.dumps(result, indent=2))
|
{agentirc_cli-4.3.2/culture/clients/claude → agentirc_cli-4.3.3/culture/clients/acp}/supervisor.py
RENAMED
|
@@ -117,6 +117,13 @@ def _format_window(window: list[dict[str, Any]], task: str) -> str:
|
|
|
117
117
|
return "\n".join(lines)
|
|
118
118
|
|
|
119
119
|
|
|
120
|
+
def _extract_verdict_text(response) -> str:
|
|
121
|
+
"""Extract text from an SDK response message."""
|
|
122
|
+
if isinstance(response, AssistantMessage):
|
|
123
|
+
return "".join(block.text for block in response.content if isinstance(block, TextBlock))
|
|
124
|
+
return ""
|
|
125
|
+
|
|
126
|
+
|
|
120
127
|
def make_sdk_evaluate_fn(
|
|
121
128
|
model: str = "claude-sonnet-4-6",
|
|
122
129
|
thinking: str | None = None,
|
|
@@ -137,10 +144,7 @@ def make_sdk_evaluate_fn(
|
|
|
137
144
|
if thinking:
|
|
138
145
|
opts.effort = thinking
|
|
139
146
|
async for message in query(prompt=prompt, options=opts):
|
|
140
|
-
|
|
141
|
-
for block in message.content:
|
|
142
|
-
if isinstance(block, TextBlock):
|
|
143
|
-
result_text += block.text
|
|
147
|
+
result_text += _extract_verdict_text(message)
|
|
144
148
|
return SupervisorVerdict.parse(result_text)
|
|
145
149
|
|
|
146
150
|
return evaluate
|
|
@@ -115,6 +115,18 @@ class AgentRunner:
|
|
|
115
115
|
opts.resume = self._session_id
|
|
116
116
|
return opts
|
|
117
117
|
|
|
118
|
+
def _handle_result_message(self, msg: ResultMessage) -> None:
|
|
119
|
+
"""Handle a ResultMessage — track session and log errors."""
|
|
120
|
+
self._session_id = msg.session_id
|
|
121
|
+
if msg.is_error:
|
|
122
|
+
logger.warning("SDK session error: %s", msg.result)
|
|
123
|
+
|
|
124
|
+
async def _handle_assistant_message(self, msg: AssistantMessage) -> None:
|
|
125
|
+
"""Handle an AssistantMessage — convert and fire callback."""
|
|
126
|
+
if self.on_message:
|
|
127
|
+
msg_dict = self._assistant_to_dict(msg)
|
|
128
|
+
await self.on_message(msg_dict)
|
|
129
|
+
|
|
118
130
|
async def _run_loop(self) -> None:
|
|
119
131
|
"""Main session loop: run turns, process prompt queue between turns."""
|
|
120
132
|
try:
|
|
@@ -132,13 +144,9 @@ class AgentRunner:
|
|
|
132
144
|
options=self._make_options(),
|
|
133
145
|
):
|
|
134
146
|
if isinstance(message, ResultMessage):
|
|
135
|
-
self.
|
|
136
|
-
if message.is_error:
|
|
137
|
-
logger.warning("SDK session error: %s", message.result)
|
|
147
|
+
self._handle_result_message(message)
|
|
138
148
|
elif isinstance(message, AssistantMessage):
|
|
139
|
-
|
|
140
|
-
msg_dict = self._assistant_to_dict(message)
|
|
141
|
-
await self.on_message(msg_dict)
|
|
149
|
+
await self._handle_assistant_message(message)
|
|
142
150
|
except Exception:
|
|
143
151
|
logger.exception("SDK session turn error")
|
|
144
152
|
if not self._stopping and self.on_exit:
|
|
@@ -83,14 +83,7 @@ class SkillClient:
|
|
|
83
83
|
msg = decode_message(line)
|
|
84
84
|
if msg is None:
|
|
85
85
|
continue
|
|
86
|
-
|
|
87
|
-
if msg_type == MSG_TYPE_RESPONSE:
|
|
88
|
-
req_id = msg.get("id", "")
|
|
89
|
-
future = self._pending.pop(req_id, None)
|
|
90
|
-
if future is not None and not future.done():
|
|
91
|
-
future.set_result(msg)
|
|
92
|
-
elif msg_type == MSG_TYPE_WHISPER:
|
|
93
|
-
self.pending_whispers.append(msg)
|
|
86
|
+
self._dispatch_message(msg)
|
|
94
87
|
except (asyncio.IncompleteReadError, ConnectionError, OSError):
|
|
95
88
|
pass
|
|
96
89
|
finally:
|
|
@@ -100,6 +93,17 @@ class SkillClient:
|
|
|
100
93
|
future.set_exception(ConnectionError("Connection lost"))
|
|
101
94
|
self._pending.clear()
|
|
102
95
|
|
|
96
|
+
def _dispatch_message(self, msg: dict[str, Any]) -> None:
|
|
97
|
+
"""Route a decoded message to the appropriate handler."""
|
|
98
|
+
msg_type = msg.get("type")
|
|
99
|
+
if msg_type == MSG_TYPE_RESPONSE:
|
|
100
|
+
req_id = msg.get("id", "")
|
|
101
|
+
future = self._pending.pop(req_id, None)
|
|
102
|
+
if future is not None and not future.done():
|
|
103
|
+
future.set_result(msg)
|
|
104
|
+
elif msg_type == MSG_TYPE_WHISPER:
|
|
105
|
+
self.pending_whispers.append(msg)
|
|
106
|
+
|
|
103
107
|
# ------------------------------------------------------------------
|
|
104
108
|
# Request dispatch
|
|
105
109
|
# ------------------------------------------------------------------
|
|
@@ -182,6 +186,86 @@ def _sock_path_from_env() -> str:
|
|
|
182
186
|
return os.path.join(runtime_dir, f"culture-{nick}.sock")
|
|
183
187
|
|
|
184
188
|
|
|
189
|
+
def _parse_ask_timeout(remaining: list[str]) -> tuple[int, list[str]]:
|
|
190
|
+
"""Extract --timeout N from args, returning (timeout, filtered_args)."""
|
|
191
|
+
if "--timeout" in remaining:
|
|
192
|
+
idx = remaining.index("--timeout")
|
|
193
|
+
if idx + 1 >= len(remaining):
|
|
194
|
+
print("ERROR: --timeout requires a value", file=sys.stderr)
|
|
195
|
+
sys.exit(2)
|
|
196
|
+
try:
|
|
197
|
+
timeout = int(remaining[idx + 1])
|
|
198
|
+
except ValueError:
|
|
199
|
+
print(
|
|
200
|
+
f"ERROR: --timeout value must be an integer, got {remaining[idx + 1]!r}",
|
|
201
|
+
file=sys.stderr,
|
|
202
|
+
)
|
|
203
|
+
sys.exit(2)
|
|
204
|
+
if timeout <= 0:
|
|
205
|
+
print("ERROR: --timeout must be positive", file=sys.stderr)
|
|
206
|
+
sys.exit(2)
|
|
207
|
+
remaining = remaining[:idx] + remaining[idx + 2 :]
|
|
208
|
+
else:
|
|
209
|
+
timeout = 30
|
|
210
|
+
return timeout, remaining
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
async def _cmd_send(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
214
|
+
channel = args[1]
|
|
215
|
+
message = " ".join(args[2:])
|
|
216
|
+
return await client.irc_send(channel, message)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
async def _cmd_read(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
220
|
+
channel = args[1]
|
|
221
|
+
limit = int(args[2]) if len(args) > 2 else 50
|
|
222
|
+
return await client.irc_read(channel, limit=limit)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
async def _cmd_ask(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
226
|
+
channel = args[1]
|
|
227
|
+
timeout, remaining = _parse_ask_timeout(args[2:])
|
|
228
|
+
question = " ".join(remaining)
|
|
229
|
+
return await client.irc_ask(channel, question, timeout=timeout)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
async def _cmd_join(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
233
|
+
return await client.irc_join(args[1])
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async def _cmd_part(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
237
|
+
return await client.irc_part(args[1])
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
async def _cmd_channels(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
241
|
+
return await client.irc_channels()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
async def _cmd_who(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
245
|
+
return await client.irc_who(args[1])
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
async def _cmd_compact(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
249
|
+
return await client.compact()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
async def _cmd_clear(client: SkillClient, args: list[str]) -> dict[str, Any]:
|
|
253
|
+
return await client.clear()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
_SUBCOMMANDS: dict[str, Any] = {
|
|
257
|
+
"send": _cmd_send,
|
|
258
|
+
"read": _cmd_read,
|
|
259
|
+
"ask": _cmd_ask,
|
|
260
|
+
"join": _cmd_join,
|
|
261
|
+
"part": _cmd_part,
|
|
262
|
+
"channels": _cmd_channels,
|
|
263
|
+
"who": _cmd_who,
|
|
264
|
+
"compact": _cmd_compact,
|
|
265
|
+
"clear": _cmd_clear,
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
185
269
|
async def _main(args: list[str]) -> None:
|
|
186
270
|
"""CLI entry point. First arg is the subcommand."""
|
|
187
271
|
if not args:
|
|
@@ -195,59 +279,16 @@ async def _main(args: list[str]) -> None:
|
|
|
195
279
|
sock_path = _sock_path_from_env()
|
|
196
280
|
subcommand = args[0]
|
|
197
281
|
|
|
282
|
+
handler = _SUBCOMMANDS.get(subcommand)
|
|
283
|
+
if handler is None:
|
|
284
|
+
print(f"ERROR: Unknown subcommand: {subcommand!r}", file=sys.stderr)
|
|
285
|
+
sys.exit(1)
|
|
286
|
+
|
|
198
287
|
client = SkillClient(sock_path)
|
|
199
288
|
await client.connect()
|
|
200
289
|
|
|
201
290
|
try:
|
|
202
|
-
|
|
203
|
-
# send <channel> <message...>
|
|
204
|
-
channel = args[1]
|
|
205
|
-
message = " ".join(args[2:])
|
|
206
|
-
result = await client.irc_send(channel, message)
|
|
207
|
-
|
|
208
|
-
elif subcommand == "read":
|
|
209
|
-
# read <channel> [limit]
|
|
210
|
-
channel = args[1]
|
|
211
|
-
limit = int(args[2]) if len(args) > 2 else 50
|
|
212
|
-
result = await client.irc_read(channel, limit=limit)
|
|
213
|
-
|
|
214
|
-
elif subcommand == "ask":
|
|
215
|
-
# ask <channel> [--timeout N] <question...>
|
|
216
|
-
channel = args[1]
|
|
217
|
-
remaining = args[2:]
|
|
218
|
-
if "--timeout" in remaining:
|
|
219
|
-
idx = remaining.index("--timeout")
|
|
220
|
-
timeout = int(remaining[idx + 1])
|
|
221
|
-
remaining = remaining[:idx] + remaining[idx + 2 :]
|
|
222
|
-
else:
|
|
223
|
-
timeout = 30
|
|
224
|
-
question = " ".join(remaining)
|
|
225
|
-
result = await client.irc_ask(channel, question, timeout=timeout)
|
|
226
|
-
|
|
227
|
-
elif subcommand == "join":
|
|
228
|
-
channel = args[1]
|
|
229
|
-
result = await client.irc_join(channel)
|
|
230
|
-
|
|
231
|
-
elif subcommand == "part":
|
|
232
|
-
channel = args[1]
|
|
233
|
-
result = await client.irc_part(channel)
|
|
234
|
-
|
|
235
|
-
elif subcommand == "channels":
|
|
236
|
-
result = await client.irc_channels()
|
|
237
|
-
|
|
238
|
-
elif subcommand == "who":
|
|
239
|
-
target = args[1]
|
|
240
|
-
result = await client.irc_who(target)
|
|
241
|
-
|
|
242
|
-
elif subcommand == "compact":
|
|
243
|
-
result = await client.compact()
|
|
244
|
-
|
|
245
|
-
elif subcommand == "clear":
|
|
246
|
-
result = await client.clear()
|
|
247
|
-
|
|
248
|
-
else:
|
|
249
|
-
print(f"ERROR: Unknown subcommand: {subcommand!r}", file=sys.stderr)
|
|
250
|
-
sys.exit(1)
|
|
291
|
+
result = await handler(client, args)
|
|
251
292
|
|
|
252
293
|
# Print result as JSON
|
|
253
294
|
print(json.dumps(result, indent=2))
|
{agentirc_cli-4.3.2/culture/clients/acp → agentirc_cli-4.3.3/culture/clients/claude}/supervisor.py
RENAMED
|
@@ -117,6 +117,13 @@ def _format_window(window: list[dict[str, Any]], task: str) -> str:
|
|
|
117
117
|
return "\n".join(lines)
|
|
118
118
|
|
|
119
119
|
|
|
120
|
+
def _extract_verdict_text(response) -> str:
|
|
121
|
+
"""Extract text from an SDK response message."""
|
|
122
|
+
if isinstance(response, AssistantMessage):
|
|
123
|
+
return "".join(block.text for block in response.content if isinstance(block, TextBlock))
|
|
124
|
+
return ""
|
|
125
|
+
|
|
126
|
+
|
|
120
127
|
def make_sdk_evaluate_fn(
|
|
121
128
|
model: str = "claude-sonnet-4-6",
|
|
122
129
|
thinking: str | None = None,
|
|
@@ -137,10 +144,7 @@ def make_sdk_evaluate_fn(
|
|
|
137
144
|
if thinking:
|
|
138
145
|
opts.effort = thinking
|
|
139
146
|
async for message in query(prompt=prompt, options=opts):
|
|
140
|
-
|
|
141
|
-
for block in message.content:
|
|
142
|
-
if isinstance(block, TextBlock):
|
|
143
|
-
result_text += block.text
|
|
147
|
+
result_text += _extract_verdict_text(message)
|
|
144
148
|
return SupervisorVerdict.parse(result_text)
|
|
145
149
|
|
|
146
150
|
return evaluate
|