agentirc-cli 4.3.4__tar.gz → 4.3.6__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.4 → agentirc_cli-4.3.6}/CHANGELOG.md +32 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/PKG-INFO +1 -1
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/__init__.py +4 -1
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/__init__.py +5 -3
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/agent.py +213 -141
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/bot.py +16 -5
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/channel.py +30 -3
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/mesh.py +84 -65
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/server.py +133 -47
- agentirc_cli-4.3.6/culture/cli/shared/formatting.py +5 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/agent_runner.py +79 -67
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/config.py +5 -5
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/daemon.py +43 -36
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/irc_transport.py +15 -6
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/skill/irc_client.py +8 -5
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/config.py +8 -8
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/daemon.py +41 -34
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/irc_transport.py +15 -6
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/agent_runner.py +83 -70
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/config.py +5 -5
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/daemon.py +43 -36
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/irc_transport.py +15 -6
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/supervisor.py +13 -11
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/agent_runner.py +14 -8
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/config.py +5 -5
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/daemon.py +43 -36
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/irc_transport.py +15 -6
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/skill/irc_client.py +8 -5
- agentirc_cli-4.3.6/culture/formatting.py +19 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/observer.py +29 -10
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/overview/collector.py +27 -8
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/overview/renderer_text.py +1 -13
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/overview/renderer_web.py +100 -40
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/persistence.py +130 -97
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/server_link.py +92 -57
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/skills/rooms.py +93 -61
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/skills/threads.py +114 -97
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/daemon.py +35 -21
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/pyproject.toml +1 -1
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/uv.lock +1 -1
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.flake8 +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.gitignore +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.pr_agent.toml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/.pylintrc +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/CLAUDE.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/CNAME +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/Gemfile +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/Gemfile.lock +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/LICENSE +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/README.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/SECURITY.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/_config.yml +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/__main__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/aio.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/bots/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/bots/bot.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/bots/config.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/shared/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/shared/constants.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/shared/display.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/shared/ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/shared/mesh.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/shared/process.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/cli/skills.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/app.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/commands.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/credentials.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/learn_prompt.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/mesh_config.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/overview/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/overview/model.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/overview/web/style.css +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/pidfile.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/commands.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/message.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/protocol/replies.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/__main__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/channel.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/config.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/ircd.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/remote_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/room_store.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/skill.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/skills/history.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/skills/icon.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/server/thread_store.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/agent-client.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/agent-harness-spec.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/harness-conformance.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/index.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/layer2-attention.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/layer3-skills.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/layer4-federation.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/server-architecture.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/architecture/threads.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/channel-polling.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/culture-cli.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/getting-started.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/index.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/SECURITY.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/bots.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/ci.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/cli.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/docs-site.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/index.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/ops-tooling.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/overview.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/operations/publishing.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/rooms.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/server-rename.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/use-cases-index.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/docs/what-is-culture.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/sonar-project.properties +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/__init__.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/conftest.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_archive.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_bot.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_bot_config.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_channel.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_connection.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_console_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_console_commands.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_console_connection.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_console_icons.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_console_integration.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_daemon.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_discovery.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_federation.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_history.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_http_listener.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_ipc.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_mentions.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_message.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_messaging.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_modes.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_overview_model.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_overview_web.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_persistence.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_pidfile.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_rooms.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_skill_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_skills.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_socket_server.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_supervisor.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_template_engine.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_threads.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_wait_for_port.py +0 -0
- {agentirc_cli-4.3.4 → agentirc_cli-4.3.6}/tests/test_webhook.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
|
+
## [4.3.6] - 2026-04-07
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- CLI module docstring updated with current subcommand sets (#147)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- agent message silently succeeds for nonexistent targets (#132)
|
|
18
|
+
- channel message silently succeeds for nonexistent channels (#133)
|
|
19
|
+
- agent sleep/wake error messages use wrong command names (#134)
|
|
20
|
+
- server subcommands ignore default server, hardcode culture (#135)
|
|
21
|
+
- agent start/stop inconsistent behavior with no nick argument (#137)
|
|
22
|
+
- channel message and bot create accept empty strings (#138)
|
|
23
|
+
- bot archive/unarchive missing --config flag (#139)
|
|
24
|
+
- inconsistent error message casing in agent archive vs unarchive (#140)
|
|
25
|
+
- channel commands show confusing timeout error when server is down (#141)
|
|
26
|
+
- uncaught PackageNotFoundError in version fallback (#142)
|
|
27
|
+
- culture --version flag not supported (#143)
|
|
28
|
+
- agent/channel message silently succeeds for nonexistent or empty targets (#144)
|
|
29
|
+
- channel read displays raw Unix timestamps instead of human-readable format (#145)
|
|
30
|
+
- server default accepts nonexistent server names without validation (#146)
|
|
31
|
+
|
|
32
|
+
## [4.3.5] - 2026-04-07
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Reduce cognitive complexity in 30+ functions across backend clients, server code, CLI submodules, and standalone files to meet SonarCloud threshold (≤15)
|
|
38
|
+
|
|
7
39
|
## [4.3.4] - 2026-04-07
|
|
8
40
|
|
|
9
41
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""Unified CLI entry point for culture.
|
|
2
2
|
|
|
3
3
|
Commands are organized into noun-based groups:
|
|
4
|
-
culture agent {create,join,start,stop,status,rename,assign,sleep,wake,learn,message,read}
|
|
5
|
-
culture server {start,stop,status,default,rename}
|
|
4
|
+
culture agent {create,join,start,stop,status,rename,assign,sleep,wake,learn,message,read,archive,unarchive,delete}
|
|
5
|
+
culture server {start,stop,status,default,rename,archive,unarchive}
|
|
6
6
|
culture mesh {overview,setup,update,console}
|
|
7
7
|
culture channel {list,read,message,who}
|
|
8
|
-
culture bot {create,start,stop,list,inspect}
|
|
8
|
+
culture bot {create,start,stop,list,inspect,archive,unarchive}
|
|
9
9
|
culture skills {install}
|
|
10
10
|
"""
|
|
11
11
|
|
|
@@ -15,6 +15,7 @@ import argparse
|
|
|
15
15
|
import logging
|
|
16
16
|
import sys
|
|
17
17
|
|
|
18
|
+
from culture import __version__
|
|
18
19
|
from culture.cli import agent, bot, channel, mesh, server, skills
|
|
19
20
|
|
|
20
21
|
GROUPS = [agent, server, mesh, channel, bot, skills]
|
|
@@ -25,6 +26,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
25
26
|
prog="culture",
|
|
26
27
|
description="culture — AI agent IRC mesh",
|
|
27
28
|
)
|
|
29
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
28
30
|
sub = parser.add_subparsers(dest="command")
|
|
29
31
|
for group in GROUPS:
|
|
30
32
|
group.register(sub)
|
|
@@ -201,59 +201,83 @@ def dispatch(args: argparse.Namespace) -> None:
|
|
|
201
201
|
# -----------------------------------------------------------------------
|
|
202
202
|
|
|
203
203
|
|
|
204
|
-
def
|
|
205
|
-
"""Build a
|
|
206
|
-
|
|
207
|
-
from culture.clients.codex.config import AgentConfig as CodexAgentConfig
|
|
208
|
-
|
|
209
|
-
return CodexAgentConfig(
|
|
210
|
-
nick=full_nick,
|
|
211
|
-
agent="codex",
|
|
212
|
-
directory=os.getcwd(),
|
|
213
|
-
channels=[DEFAULT_CHANNEL],
|
|
214
|
-
)
|
|
215
|
-
if args.agent == "copilot":
|
|
216
|
-
from culture.clients.copilot.config import AgentConfig as CopilotAgentConfig
|
|
217
|
-
|
|
218
|
-
return CopilotAgentConfig(
|
|
219
|
-
nick=full_nick,
|
|
220
|
-
agent="copilot",
|
|
221
|
-
directory=os.getcwd(),
|
|
222
|
-
channels=[DEFAULT_CHANNEL],
|
|
223
|
-
)
|
|
224
|
-
if args.agent == "acp":
|
|
225
|
-
import json as _json
|
|
204
|
+
def _create_codex_config(full_nick: str) -> AgentConfig:
|
|
205
|
+
"""Build a CodexAgentConfig."""
|
|
206
|
+
from culture.clients.codex.config import AgentConfig as CodexAgentConfig
|
|
226
207
|
|
|
227
|
-
|
|
208
|
+
return CodexAgentConfig(
|
|
209
|
+
nick=full_nick,
|
|
210
|
+
agent="codex",
|
|
211
|
+
directory=os.getcwd(),
|
|
212
|
+
channels=[DEFAULT_CHANNEL],
|
|
213
|
+
)
|
|
228
214
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
215
|
+
|
|
216
|
+
def _create_copilot_config(full_nick: str) -> AgentConfig:
|
|
217
|
+
"""Build a CopilotAgentConfig."""
|
|
218
|
+
from culture.clients.copilot.config import AgentConfig as CopilotAgentConfig
|
|
219
|
+
|
|
220
|
+
return CopilotAgentConfig(
|
|
221
|
+
nick=full_nick,
|
|
222
|
+
agent="copilot",
|
|
223
|
+
directory=os.getcwd(),
|
|
224
|
+
channels=[DEFAULT_CHANNEL],
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _parse_acp_command(raw_command: str | None) -> list[str]:
|
|
229
|
+
"""Parse and validate the ACP command from CLI args."""
|
|
230
|
+
import json as _json
|
|
231
|
+
|
|
232
|
+
acp_cmd = ["opencode", "acp"]
|
|
233
|
+
if raw_command:
|
|
234
|
+
try:
|
|
235
|
+
acp_cmd = _json.loads(raw_command)
|
|
236
|
+
except _json.JSONDecodeError:
|
|
237
|
+
acp_cmd = raw_command.split()
|
|
238
|
+
if not isinstance(acp_cmd, list) or not acp_cmd or not all(isinstance(s, str) for s in acp_cmd):
|
|
239
|
+
print("Error: --acp-command must be a non-empty list of strings", file=sys.stderr)
|
|
240
|
+
sys.exit(1)
|
|
241
|
+
return acp_cmd
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _create_acp_config(full_nick: str, args: argparse.Namespace) -> AgentConfig:
|
|
245
|
+
"""Build an ACPAgentConfig."""
|
|
246
|
+
from culture.clients.acp.config import AgentConfig as ACPAgentConfig
|
|
247
|
+
|
|
248
|
+
acp_cmd = _parse_acp_command(args.acp_command)
|
|
249
|
+
return ACPAgentConfig(
|
|
250
|
+
nick=full_nick,
|
|
251
|
+
agent="acp",
|
|
252
|
+
acp_command=acp_cmd,
|
|
253
|
+
directory=os.getcwd(),
|
|
254
|
+
channels=[DEFAULT_CHANNEL],
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _create_default_config(full_nick: str, backend: str) -> AgentConfig:
|
|
259
|
+
"""Build a default (claude) AgentConfig."""
|
|
249
260
|
return AgentConfig(
|
|
250
261
|
nick=full_nick,
|
|
251
|
-
agent=
|
|
262
|
+
agent=backend,
|
|
252
263
|
directory=os.getcwd(),
|
|
253
264
|
channels=[DEFAULT_CHANNEL],
|
|
254
265
|
)
|
|
255
266
|
|
|
256
267
|
|
|
268
|
+
def _create_agent_config(args: argparse.Namespace, full_nick: str) -> AgentConfig:
|
|
269
|
+
"""Build a backend-specific AgentConfig from CLI args."""
|
|
270
|
+
factories = {
|
|
271
|
+
"codex": lambda: _create_codex_config(full_nick),
|
|
272
|
+
"copilot": lambda: _create_copilot_config(full_nick),
|
|
273
|
+
"acp": lambda: _create_acp_config(full_nick, args),
|
|
274
|
+
}
|
|
275
|
+
factory = factories.get(args.agent)
|
|
276
|
+
if factory:
|
|
277
|
+
return factory()
|
|
278
|
+
return _create_default_config(full_nick, args.agent)
|
|
279
|
+
|
|
280
|
+
|
|
257
281
|
def _cmd_create(args: argparse.Namespace) -> None:
|
|
258
282
|
config = load_config_or_default(args.config)
|
|
259
283
|
|
|
@@ -387,6 +411,32 @@ def _probe_server_connection(host: str, port: int, server_name: str) -> None:
|
|
|
387
411
|
sys.exit(1)
|
|
388
412
|
|
|
389
413
|
|
|
414
|
+
def _start_foreground(config: DaemonConfig, agents: list[AgentConfig]) -> None:
|
|
415
|
+
"""Start a single agent in the foreground."""
|
|
416
|
+
if len(agents) != 1:
|
|
417
|
+
print("--foreground requires a single agent nick, not --all", file=sys.stderr)
|
|
418
|
+
sys.exit(1)
|
|
419
|
+
agent = agents[0]
|
|
420
|
+
print(f"Starting agent {agent.nick} in foreground...")
|
|
421
|
+
asyncio.run(_run_single_agent(config, agent))
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _start_background(config: DaemonConfig, agents: list[AgentConfig]) -> None:
|
|
425
|
+
"""Start agents in background mode (fork on Unix, single on Windows)."""
|
|
426
|
+
if sys.platform == "win32":
|
|
427
|
+
if len(agents) != 1:
|
|
428
|
+
print(
|
|
429
|
+
"Multi-agent daemon mode not supported on Windows. Start agents individually.",
|
|
430
|
+
file=sys.stderr,
|
|
431
|
+
)
|
|
432
|
+
sys.exit(1)
|
|
433
|
+
agent = agents[0]
|
|
434
|
+
print(f"Starting agent {agent.nick}...")
|
|
435
|
+
asyncio.run(_run_single_agent(config, agent))
|
|
436
|
+
else:
|
|
437
|
+
_run_multi_agents(config, agents)
|
|
438
|
+
|
|
439
|
+
|
|
390
440
|
def _cmd_start(args: argparse.Namespace) -> None:
|
|
391
441
|
config = load_config(args.config)
|
|
392
442
|
|
|
@@ -395,86 +445,88 @@ def _cmd_start(args: argparse.Namespace) -> None:
|
|
|
395
445
|
server_name = config.server.name
|
|
396
446
|
_probe_server_connection(config.server.host, config.server.port, server_name)
|
|
397
447
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
if foreground:
|
|
401
|
-
if len(agents) != 1:
|
|
402
|
-
print("--foreground requires a single agent nick, not --all", file=sys.stderr)
|
|
403
|
-
sys.exit(1)
|
|
404
|
-
agent = agents[0]
|
|
405
|
-
print(f"Starting agent {agent.nick} in foreground...")
|
|
406
|
-
asyncio.run(_run_single_agent(config, agent))
|
|
448
|
+
if getattr(args, "foreground", False):
|
|
449
|
+
_start_foreground(config, agents)
|
|
407
450
|
else:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
451
|
+
_start_background(config, agents)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def _make_backend_config(config: DaemonConfig, backend_daemon_config_cls):
|
|
455
|
+
"""Build a backend-specific DaemonConfig from the base config."""
|
|
456
|
+
return backend_daemon_config_cls(
|
|
457
|
+
server=config.server,
|
|
458
|
+
webhooks=config.webhooks,
|
|
459
|
+
buffer_size=config.buffer_size,
|
|
460
|
+
agents=config.agents,
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def _create_codex_daemon(config: DaemonConfig, agent: AgentConfig):
|
|
465
|
+
"""Create a Codex backend daemon."""
|
|
466
|
+
from culture.clients.codex.config import DaemonConfig as CodexDaemonConfig
|
|
467
|
+
from culture.clients.codex.daemon import CodexDaemon
|
|
468
|
+
|
|
469
|
+
return CodexDaemon(_make_backend_config(config, CodexDaemonConfig), agent)
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def _coerce_to_acp_agent(agent: AgentConfig):
|
|
473
|
+
"""Ensure agent is an ACPAgentConfig, converting if necessary."""
|
|
474
|
+
from culture.clients.acp.config import AgentConfig as ACPAgentConfig
|
|
475
|
+
|
|
476
|
+
if isinstance(agent, ACPAgentConfig):
|
|
477
|
+
return agent
|
|
478
|
+
return ACPAgentConfig(
|
|
479
|
+
nick=agent.nick,
|
|
480
|
+
agent="acp",
|
|
481
|
+
acp_command=getattr(agent, "acp_command", None) or ["opencode", "acp"],
|
|
482
|
+
directory=agent.directory,
|
|
483
|
+
channels=agent.channels,
|
|
484
|
+
model=agent.model,
|
|
485
|
+
system_prompt=agent.system_prompt,
|
|
486
|
+
tags=agent.tags,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def _create_acp_daemon(config: DaemonConfig, agent: AgentConfig):
|
|
491
|
+
"""Create an ACP backend daemon."""
|
|
492
|
+
from culture.clients.acp.config import DaemonConfig as ACPDaemonConfig
|
|
493
|
+
from culture.clients.acp.daemon import ACPDaemon
|
|
494
|
+
|
|
495
|
+
return ACPDaemon(
|
|
496
|
+
_make_backend_config(config, ACPDaemonConfig),
|
|
497
|
+
_coerce_to_acp_agent(agent),
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def _create_copilot_daemon(config: DaemonConfig, agent: AgentConfig):
|
|
502
|
+
"""Create a Copilot backend daemon."""
|
|
503
|
+
from culture.clients.copilot.config import DaemonConfig as CopilotDaemonConfig
|
|
504
|
+
from culture.clients.copilot.daemon import CopilotDaemon
|
|
505
|
+
|
|
506
|
+
return CopilotDaemon(_make_backend_config(config, CopilotDaemonConfig), agent)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def _create_claude_daemon(config: DaemonConfig, agent: AgentConfig):
|
|
510
|
+
"""Create the default Claude backend daemon."""
|
|
511
|
+
from culture.clients.claude.daemon import AgentDaemon
|
|
512
|
+
|
|
513
|
+
return AgentDaemon(config, agent)
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
_BACKEND_DAEMON_FACTORIES = {
|
|
517
|
+
"codex": _create_codex_daemon,
|
|
518
|
+
"acp": _create_acp_daemon,
|
|
519
|
+
"opencode": _create_acp_daemon,
|
|
520
|
+
"copilot": _create_copilot_daemon,
|
|
521
|
+
}
|
|
421
522
|
|
|
422
523
|
|
|
423
524
|
async def _run_single_agent(config: DaemonConfig, agent: AgentConfig) -> None:
|
|
424
525
|
"""Run a single agent daemon in the foreground."""
|
|
425
526
|
backend = getattr(agent, "agent", "claude")
|
|
426
527
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
from culture.clients.codex.daemon import CodexDaemon
|
|
430
|
-
|
|
431
|
-
codex_config = CodexDaemonConfig(
|
|
432
|
-
server=config.server,
|
|
433
|
-
webhooks=config.webhooks,
|
|
434
|
-
buffer_size=config.buffer_size,
|
|
435
|
-
agents=config.agents,
|
|
436
|
-
)
|
|
437
|
-
daemon = CodexDaemon(codex_config, agent)
|
|
438
|
-
elif backend in ("acp", "opencode"):
|
|
439
|
-
from culture.clients.acp.config import AgentConfig as ACPAgentConfig
|
|
440
|
-
from culture.clients.acp.config import DaemonConfig as ACPDaemonConfig
|
|
441
|
-
from culture.clients.acp.daemon import ACPDaemon
|
|
442
|
-
|
|
443
|
-
acp_config = ACPDaemonConfig(
|
|
444
|
-
server=config.server,
|
|
445
|
-
webhooks=config.webhooks,
|
|
446
|
-
buffer_size=config.buffer_size,
|
|
447
|
-
agents=config.agents,
|
|
448
|
-
)
|
|
449
|
-
if not isinstance(agent, ACPAgentConfig):
|
|
450
|
-
acp_agent = ACPAgentConfig(
|
|
451
|
-
nick=agent.nick,
|
|
452
|
-
agent="acp",
|
|
453
|
-
acp_command=getattr(agent, "acp_command", None) or ["opencode", "acp"],
|
|
454
|
-
directory=agent.directory,
|
|
455
|
-
channels=agent.channels,
|
|
456
|
-
model=agent.model,
|
|
457
|
-
system_prompt=agent.system_prompt,
|
|
458
|
-
tags=agent.tags,
|
|
459
|
-
)
|
|
460
|
-
else:
|
|
461
|
-
acp_agent = agent
|
|
462
|
-
daemon = ACPDaemon(acp_config, acp_agent)
|
|
463
|
-
elif backend == "copilot":
|
|
464
|
-
from culture.clients.copilot.config import DaemonConfig as CopilotDaemonConfig
|
|
465
|
-
from culture.clients.copilot.daemon import CopilotDaemon
|
|
466
|
-
|
|
467
|
-
copilot_config = CopilotDaemonConfig(
|
|
468
|
-
server=config.server,
|
|
469
|
-
webhooks=config.webhooks,
|
|
470
|
-
buffer_size=config.buffer_size,
|
|
471
|
-
agents=config.agents,
|
|
472
|
-
)
|
|
473
|
-
daemon = CopilotDaemon(copilot_config, agent)
|
|
474
|
-
else:
|
|
475
|
-
from culture.clients.claude.daemon import AgentDaemon
|
|
476
|
-
|
|
477
|
-
daemon = AgentDaemon(config, agent)
|
|
528
|
+
factory = _BACKEND_DAEMON_FACTORIES.get(backend, _create_claude_daemon)
|
|
529
|
+
daemon = factory(config, agent)
|
|
478
530
|
|
|
479
531
|
stop_event = asyncio.Event()
|
|
480
532
|
daemon.set_stop_event(stop_event)
|
|
@@ -524,30 +576,38 @@ def _run_multi_agents(config: DaemonConfig, agents: list[AgentConfig]) -> None:
|
|
|
524
576
|
print(f"Started {agent.nick} (PID {pid})")
|
|
525
577
|
|
|
526
578
|
|
|
527
|
-
def
|
|
528
|
-
|
|
529
|
-
|
|
579
|
+
def _resolve_agents_to_stop(config, args) -> list:
|
|
580
|
+
"""Resolve which agents should be stopped, or exit with an error."""
|
|
530
581
|
if args.all:
|
|
531
|
-
|
|
532
|
-
|
|
582
|
+
return config.agents
|
|
583
|
+
if args.nick:
|
|
533
584
|
agent = config.get_agent(args.nick)
|
|
534
585
|
if not agent:
|
|
535
586
|
print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
|
|
536
587
|
sys.exit(1)
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
588
|
+
return [agent]
|
|
589
|
+
if len(config.agents) == 1:
|
|
590
|
+
return config.agents
|
|
591
|
+
if len(config.agents) == 0:
|
|
592
|
+
print(NO_AGENTS_MSG, file=sys.stderr)
|
|
593
|
+
sys.exit(1)
|
|
594
|
+
# Multiple agents: try to match by current working directory
|
|
595
|
+
cwd_real = os.path.realpath(os.getcwd())
|
|
596
|
+
cwd_matches = [a for a in config.agents if os.path.realpath(a.directory) == cwd_real]
|
|
597
|
+
if len(cwd_matches) == 1:
|
|
598
|
+
return cwd_matches
|
|
599
|
+
print(
|
|
600
|
+
"Multiple agents configured. Specify a nick or use --all.",
|
|
601
|
+
file=sys.stderr,
|
|
602
|
+
)
|
|
603
|
+
for a in config.agents:
|
|
604
|
+
print(f" {a.nick}", file=sys.stderr)
|
|
605
|
+
sys.exit(1)
|
|
550
606
|
|
|
607
|
+
|
|
608
|
+
def _cmd_stop(args: argparse.Namespace) -> None:
|
|
609
|
+
config = load_config_or_default(args.config)
|
|
610
|
+
agents = _resolve_agents_to_stop(config, args)
|
|
551
611
|
for agent in agents:
|
|
552
612
|
stop_agent(agent.nick)
|
|
553
613
|
|
|
@@ -710,13 +770,13 @@ def _cmd_assign(args: argparse.Namespace) -> None:
|
|
|
710
770
|
# -----------------------------------------------------------------------
|
|
711
771
|
|
|
712
772
|
|
|
713
|
-
def _resolve_ipc_targets(config, args,
|
|
773
|
+
def _resolve_ipc_targets(config, args, command_name: str) -> list:
|
|
714
774
|
"""Resolve which agents to send IPC messages to."""
|
|
715
775
|
if args.nick and args.all:
|
|
716
776
|
print("Cannot specify both nick and --all", file=sys.stderr)
|
|
717
777
|
sys.exit(1)
|
|
718
778
|
if not args.nick and not args.all:
|
|
719
|
-
print(f"Usage: culture agent {
|
|
779
|
+
print(f"Usage: culture agent {command_name} <nick> or --all", file=sys.stderr)
|
|
720
780
|
sys.exit(1)
|
|
721
781
|
if args.all:
|
|
722
782
|
return config.agents
|
|
@@ -737,20 +797,22 @@ def _send_ipc(agent, msg_type: str, action_verb: str) -> None:
|
|
|
737
797
|
print(f"{agent.nick}: failed (not running?)", file=sys.stderr)
|
|
738
798
|
|
|
739
799
|
|
|
740
|
-
def _ipc_to_agents(
|
|
800
|
+
def _ipc_to_agents(
|
|
801
|
+
args: argparse.Namespace, msg_type: str, action_verb: str, command_name: str
|
|
802
|
+
) -> None:
|
|
741
803
|
"""Send an IPC message (pause/resume) to one or all agents."""
|
|
742
804
|
config = load_config_or_default(args.config)
|
|
743
|
-
targets = _resolve_ipc_targets(config, args,
|
|
805
|
+
targets = _resolve_ipc_targets(config, args, command_name)
|
|
744
806
|
for agent in targets:
|
|
745
807
|
_send_ipc(agent, msg_type, action_verb)
|
|
746
808
|
|
|
747
809
|
|
|
748
810
|
def _cmd_sleep(args: argparse.Namespace) -> None:
|
|
749
|
-
_ipc_to_agents(args, "pause", "paused")
|
|
811
|
+
_ipc_to_agents(args, "pause", "paused", "sleep")
|
|
750
812
|
|
|
751
813
|
|
|
752
814
|
def _cmd_wake(args: argparse.Namespace) -> None:
|
|
753
|
-
_ipc_to_agents(args, "resume", "resumed")
|
|
815
|
+
_ipc_to_agents(args, "resume", "resumed", "wake")
|
|
754
816
|
|
|
755
817
|
|
|
756
818
|
def _cmd_learn(args: argparse.Namespace) -> None:
|
|
@@ -785,6 +847,16 @@ def _cmd_learn(args: argparse.Namespace) -> None:
|
|
|
785
847
|
|
|
786
848
|
|
|
787
849
|
def _cmd_message(args: argparse.Namespace) -> None:
|
|
850
|
+
if not args.target.strip():
|
|
851
|
+
print("Error: target nick cannot be empty", file=sys.stderr)
|
|
852
|
+
sys.exit(1)
|
|
853
|
+
if not args.text.strip():
|
|
854
|
+
print("Error: message text cannot be empty", file=sys.stderr)
|
|
855
|
+
sys.exit(1)
|
|
856
|
+
config = load_config_or_default(args.config)
|
|
857
|
+
if not config.get_agent(args.target):
|
|
858
|
+
print(f"Agent '{args.target}' not found in config", file=sys.stderr)
|
|
859
|
+
sys.exit(1)
|
|
788
860
|
observer = get_observer(args.config)
|
|
789
861
|
asyncio.run(observer.send_message(args.target, args.text))
|
|
790
862
|
print(f"Sent to {args.target}")
|
|
@@ -49,9 +49,11 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
49
49
|
bot_archive = bot_sub.add_parser("archive", help="Archive a bot")
|
|
50
50
|
bot_archive.add_argument("name", help="Bot name to archive")
|
|
51
51
|
bot_archive.add_argument("--reason", default="", help="Reason for archiving")
|
|
52
|
+
bot_archive.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
|
|
52
53
|
|
|
53
54
|
bot_unarchive = bot_sub.add_parser("unarchive", help="Restore an archived bot")
|
|
54
55
|
bot_unarchive.add_argument("name", help="Bot name to unarchive")
|
|
56
|
+
bot_unarchive.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
|
|
55
57
|
|
|
56
58
|
|
|
57
59
|
def dispatch(args: argparse.Namespace) -> None:
|
|
@@ -87,6 +89,9 @@ def dispatch(args: argparse.Namespace) -> None:
|
|
|
87
89
|
def _bot_create(args: argparse.Namespace) -> None:
|
|
88
90
|
from culture.bots.config import BOTS_DIR, BotConfig, save_bot_config
|
|
89
91
|
|
|
92
|
+
if not args.name.strip():
|
|
93
|
+
print("Error: bot name cannot be empty", file=sys.stderr)
|
|
94
|
+
sys.exit(1)
|
|
90
95
|
name = args.name
|
|
91
96
|
config = load_config_or_default(args.config)
|
|
92
97
|
server_name = config.server.name
|
|
@@ -152,6 +157,15 @@ def _bot_stop(args: argparse.Namespace) -> None:
|
|
|
152
157
|
print("(Live reload via IPC will be available in a future release.)")
|
|
153
158
|
|
|
154
159
|
|
|
160
|
+
def _should_include_bot(bot_config, owner: str | None, show_archived: bool) -> bool:
|
|
161
|
+
"""Return True if the bot should be included in the listing."""
|
|
162
|
+
if owner and bot_config.owner != owner:
|
|
163
|
+
return False
|
|
164
|
+
if not show_archived and bot_config.archived:
|
|
165
|
+
return False
|
|
166
|
+
return True
|
|
167
|
+
|
|
168
|
+
|
|
155
169
|
def _load_and_filter_bots(args) -> list:
|
|
156
170
|
"""Load bot configs, filtering by owner and archived status."""
|
|
157
171
|
from culture.bots.config import BOTS_DIR, load_bot_config
|
|
@@ -168,11 +182,8 @@ def _load_and_filter_bots(args) -> list:
|
|
|
168
182
|
config = load_bot_config(yaml_path)
|
|
169
183
|
except Exception:
|
|
170
184
|
continue
|
|
171
|
-
if
|
|
172
|
-
|
|
173
|
-
if not show_all and config.archived:
|
|
174
|
-
continue
|
|
175
|
-
bots.append(config)
|
|
185
|
+
if _should_include_bot(config, args.owner, show_all):
|
|
186
|
+
bots.append(config)
|
|
176
187
|
return bots
|
|
177
188
|
|
|
178
189
|
|
|
@@ -50,11 +50,26 @@ def dispatch(args: argparse.Namespace) -> None:
|
|
|
50
50
|
"who": _cmd_who,
|
|
51
51
|
}
|
|
52
52
|
handler = handlers.get(args.channel_command)
|
|
53
|
-
if handler:
|
|
54
|
-
handler(args)
|
|
55
|
-
else:
|
|
53
|
+
if not handler:
|
|
56
54
|
print(f"Unknown channel command: {args.channel_command}", file=sys.stderr)
|
|
57
55
|
sys.exit(1)
|
|
56
|
+
try:
|
|
57
|
+
handler(args)
|
|
58
|
+
except (ConnectionError, ConnectionRefusedError, TimeoutError, OSError) as exc:
|
|
59
|
+
msg = str(exc)
|
|
60
|
+
if (
|
|
61
|
+
"Timed out" in msg
|
|
62
|
+
or "Connection refused" in msg
|
|
63
|
+
or "Connect call failed" in msg
|
|
64
|
+
or not msg # TimeoutError from asyncio often has empty message
|
|
65
|
+
):
|
|
66
|
+
print(
|
|
67
|
+
"Error: cannot connect to IRC server. Is the server running?\n"
|
|
68
|
+
" Start it with: culture server start",
|
|
69
|
+
file=sys.stderr,
|
|
70
|
+
)
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
raise
|
|
58
73
|
|
|
59
74
|
|
|
60
75
|
# -----------------------------------------------------------------------
|
|
@@ -76,6 +91,9 @@ def _cmd_list(args: argparse.Namespace) -> None:
|
|
|
76
91
|
|
|
77
92
|
|
|
78
93
|
def _cmd_read(args: argparse.Namespace) -> None:
|
|
94
|
+
if not args.target.strip():
|
|
95
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
96
|
+
sys.exit(1)
|
|
79
97
|
observer = get_observer(args.config)
|
|
80
98
|
channel = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
81
99
|
messages = asyncio.run(observer.read_channel(channel, limit=args.limit))
|
|
@@ -89,6 +107,12 @@ def _cmd_read(args: argparse.Namespace) -> None:
|
|
|
89
107
|
|
|
90
108
|
|
|
91
109
|
def _cmd_message(args: argparse.Namespace) -> None:
|
|
110
|
+
if not args.target.strip():
|
|
111
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
112
|
+
sys.exit(1)
|
|
113
|
+
if not args.text.strip():
|
|
114
|
+
print("Error: message text cannot be empty", file=sys.stderr)
|
|
115
|
+
sys.exit(1)
|
|
92
116
|
observer = get_observer(args.config)
|
|
93
117
|
target = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
94
118
|
asyncio.run(observer.send_message(target, args.text))
|
|
@@ -96,6 +120,9 @@ def _cmd_message(args: argparse.Namespace) -> None:
|
|
|
96
120
|
|
|
97
121
|
|
|
98
122
|
def _cmd_who(args: argparse.Namespace) -> None:
|
|
123
|
+
if not args.target.strip():
|
|
124
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
125
|
+
sys.exit(1)
|
|
99
126
|
observer = get_observer(args.config)
|
|
100
127
|
target = args.target
|
|
101
128
|
nicks = asyncio.run(observer.who(target))
|