agentirc-cli 4.3.5__tar.gz → 4.3.7__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.5 → agentirc_cli-4.3.7}/CHANGELOG.md +37 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/PKG-INFO +1 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/__init__.py +4 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/bots/bot_manager.py +7 -3
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/bots/config.py +1 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/__init__.py +5 -3
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/agent.py +26 -7
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/bot.py +5 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/channel.py +30 -3
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/mesh.py +1 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/server.py +53 -7
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/shared/constants.py +2 -1
- agentirc_cli-4.3.7/culture/cli/shared/formatting.py +5 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/shared/ipc.py +3 -3
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/agent_runner.py +8 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/config.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/daemon.py +20 -14
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/irc_transport.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/socket_server.py +4 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/agent_runner.py +2 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/config.py +8 -8
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/daemon.py +20 -14
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/irc_transport.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/socket_server.py +4 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/agent_runner.py +8 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/config.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/daemon.py +20 -14
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/irc_transport.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/socket_server.py +4 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/config.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/daemon.py +20 -14
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/irc_transport.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/socket_server.py +4 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/client.py +1 -1
- agentirc_cli-4.3.7/culture/formatting.py +19 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/observer.py +10 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/overview/collector.py +18 -18
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/overview/renderer_text.py +1 -13
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/overview/web/style.css +1 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/pidfile.py +1 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/client.py +1 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/ircd.py +2 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/server_link.py +6 -6
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/skill.py +3 -3
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/daemon.py +11 -10
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/irc_transport.py +5 -5
- agentirc_cli-4.3.7/packages/agent-harness/message_buffer.py +63 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/socket_server.py +4 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/pyproject.toml +1 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/conftest.py +8 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_acp_daemon.py +0 -6
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_agent_runner.py +2 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_console_commands.py +0 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_console_connection.py +0 -4
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_console_icons.py +1 -2
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_federation.py +40 -34
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_link_reconnect.py +16 -15
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_mentions.py +3 -7
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_rooms.py +5 -5
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_supervisor.py +2 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_webhook.py +1 -1
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/uv.lock +1 -1
- agentirc_cli-4.3.5/packages/agent-harness/message_buffer.py +0 -65
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.flake8 +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.gitignore +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.pr_agent.toml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/.pylintrc +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/CLAUDE.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/CNAME +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/Gemfile +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/Gemfile.lock +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/LICENSE +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/README.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/SECURITY.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/_config.yml +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/__main__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/aio.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/bots/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/bots/bot.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/shared/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/shared/display.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/shared/mesh.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/shared/process.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/cli/skills.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/app.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/commands.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/credentials.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/learn_prompt.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/mesh_config.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/overview/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/overview/model.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/persistence.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/commands.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/message.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/protocol/replies.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/__main__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/channel.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/config.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/remote_client.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/room_store.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/skills/history.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/skills/icon.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/skills/rooms.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/skills/threads.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/server/thread_store.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/agent-client.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/agent-harness-spec.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/harness-conformance.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/index.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/layer2-attention.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/layer3-skills.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/layer4-federation.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/server-architecture.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/architecture/threads.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/channel-polling.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/culture-cli.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/getting-started.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/index.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/SECURITY.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/bots.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/ci.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/cli.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/docs-site.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/index.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/ops-tooling.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/overview.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/operations/publishing.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/rooms.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/server-rename.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/use-cases-index.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/docs/what-is-culture.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/sonar-project.properties +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/__init__.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_archive.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_bot.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_bot_config.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_channel.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_connection.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_console_client.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_console_integration.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_daemon.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_discovery.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_history.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_http_listener.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_ipc.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_message.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_messaging.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_modes.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_overview_model.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_overview_web.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_persistence.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_pidfile.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_skill_client.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_skills.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_socket_server.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_template_engine.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_threads.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-4.3.5 → agentirc_cli-4.3.7}/tests/test_wait_for_port.py +0 -0
|
@@ -4,6 +4,43 @@ 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.7] - 2026-04-07
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Extract duplicate string constants (S1192, #85)
|
|
13
|
+
- Remove redundant exception classes in except clauses (S5713, #86)
|
|
14
|
+
- Clean up unused variables and function parameters (S1481/S1172, #88)
|
|
15
|
+
- Remove f-strings without replacement fields (S3457, #89)
|
|
16
|
+
- Address hardcoded credential warnings with test constants (S2068, #90)
|
|
17
|
+
- Fix miscellaneous code quality issues: asyncio.timeout, nested ternaries, empty methods, CSS contrast (S7483/S3358/S1186/S7924, #91)
|
|
18
|
+
|
|
19
|
+
## [4.3.6] - 2026-04-07
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- CLI module docstring updated with current subcommand sets (#147)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- agent message silently succeeds for nonexistent targets (#132)
|
|
30
|
+
- channel message silently succeeds for nonexistent channels (#133)
|
|
31
|
+
- agent sleep/wake error messages use wrong command names (#134)
|
|
32
|
+
- server subcommands ignore default server, hardcode culture (#135)
|
|
33
|
+
- agent start/stop inconsistent behavior with no nick argument (#137)
|
|
34
|
+
- channel message and bot create accept empty strings (#138)
|
|
35
|
+
- bot archive/unarchive missing --config flag (#139)
|
|
36
|
+
- inconsistent error message casing in agent archive vs unarchive (#140)
|
|
37
|
+
- channel commands show confusing timeout error when server is down (#141)
|
|
38
|
+
- uncaught PackageNotFoundError in version fallback (#142)
|
|
39
|
+
- culture --version flag not supported (#143)
|
|
40
|
+
- agent/channel message silently succeeds for nonexistent or empty targets (#144)
|
|
41
|
+
- channel read displays raw Unix timestamps instead of human-readable format (#145)
|
|
42
|
+
- server default accepts nonexistent server names without validation (#146)
|
|
43
|
+
|
|
7
44
|
## [4.3.5] - 2026-04-07
|
|
8
45
|
|
|
9
46
|
|
|
@@ -6,15 +6,19 @@ import logging
|
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from culture.bots.bot import Bot
|
|
9
|
-
from culture.bots.config import
|
|
9
|
+
from culture.bots.config import (
|
|
10
|
+
BOT_CONFIG_FILE,
|
|
11
|
+
BOTS_DIR,
|
|
12
|
+
BotConfig,
|
|
13
|
+
load_bot_config,
|
|
14
|
+
save_bot_config,
|
|
15
|
+
)
|
|
10
16
|
|
|
11
17
|
if TYPE_CHECKING:
|
|
12
18
|
from culture.server.ircd import IRCd
|
|
13
19
|
|
|
14
20
|
logger = logging.getLogger(__name__)
|
|
15
21
|
|
|
16
|
-
BOT_CONFIG_FILE = "bot.yaml"
|
|
17
|
-
|
|
18
22
|
|
|
19
23
|
class BotManager:
|
|
20
24
|
"""Loads, starts, stops, and dispatches webhooks to bots."""
|
|
@@ -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)
|
|
@@ -399,7 +399,7 @@ def _probe_server_connection(host: str, port: int, server_name: str) -> None:
|
|
|
399
399
|
try:
|
|
400
400
|
with _socket.create_connection((host, port), timeout=2):
|
|
401
401
|
pass
|
|
402
|
-
except
|
|
402
|
+
except OSError:
|
|
403
403
|
hint = ""
|
|
404
404
|
server_pid = read_pid(f"server-{server_name}")
|
|
405
405
|
if not server_pid or not is_process_alive(server_pid):
|
|
@@ -591,10 +591,17 @@ def _resolve_agents_to_stop(config, args) -> list:
|
|
|
591
591
|
if len(config.agents) == 0:
|
|
592
592
|
print(NO_AGENTS_MSG, file=sys.stderr)
|
|
593
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
|
|
594
599
|
print(
|
|
595
600
|
"Multiple agents configured. Specify a nick or use --all.",
|
|
596
601
|
file=sys.stderr,
|
|
597
602
|
)
|
|
603
|
+
for a in config.agents:
|
|
604
|
+
print(f" {a.nick}", file=sys.stderr)
|
|
598
605
|
sys.exit(1)
|
|
599
606
|
|
|
600
607
|
|
|
@@ -763,13 +770,13 @@ def _cmd_assign(args: argparse.Namespace) -> None:
|
|
|
763
770
|
# -----------------------------------------------------------------------
|
|
764
771
|
|
|
765
772
|
|
|
766
|
-
def _resolve_ipc_targets(config, args,
|
|
773
|
+
def _resolve_ipc_targets(config, args, command_name: str) -> list:
|
|
767
774
|
"""Resolve which agents to send IPC messages to."""
|
|
768
775
|
if args.nick and args.all:
|
|
769
776
|
print("Cannot specify both nick and --all", file=sys.stderr)
|
|
770
777
|
sys.exit(1)
|
|
771
778
|
if not args.nick and not args.all:
|
|
772
|
-
print(f"Usage: culture agent {
|
|
779
|
+
print(f"Usage: culture agent {command_name} <nick> or --all", file=sys.stderr)
|
|
773
780
|
sys.exit(1)
|
|
774
781
|
if args.all:
|
|
775
782
|
return config.agents
|
|
@@ -790,20 +797,22 @@ def _send_ipc(agent, msg_type: str, action_verb: str) -> None:
|
|
|
790
797
|
print(f"{agent.nick}: failed (not running?)", file=sys.stderr)
|
|
791
798
|
|
|
792
799
|
|
|
793
|
-
def _ipc_to_agents(
|
|
800
|
+
def _ipc_to_agents(
|
|
801
|
+
args: argparse.Namespace, msg_type: str, action_verb: str, command_name: str
|
|
802
|
+
) -> None:
|
|
794
803
|
"""Send an IPC message (pause/resume) to one or all agents."""
|
|
795
804
|
config = load_config_or_default(args.config)
|
|
796
|
-
targets = _resolve_ipc_targets(config, args,
|
|
805
|
+
targets = _resolve_ipc_targets(config, args, command_name)
|
|
797
806
|
for agent in targets:
|
|
798
807
|
_send_ipc(agent, msg_type, action_verb)
|
|
799
808
|
|
|
800
809
|
|
|
801
810
|
def _cmd_sleep(args: argparse.Namespace) -> None:
|
|
802
|
-
_ipc_to_agents(args, "pause", "paused")
|
|
811
|
+
_ipc_to_agents(args, "pause", "paused", "sleep")
|
|
803
812
|
|
|
804
813
|
|
|
805
814
|
def _cmd_wake(args: argparse.Namespace) -> None:
|
|
806
|
-
_ipc_to_agents(args, "resume", "resumed")
|
|
815
|
+
_ipc_to_agents(args, "resume", "resumed", "wake")
|
|
807
816
|
|
|
808
817
|
|
|
809
818
|
def _cmd_learn(args: argparse.Namespace) -> None:
|
|
@@ -838,6 +847,16 @@ def _cmd_learn(args: argparse.Namespace) -> None:
|
|
|
838
847
|
|
|
839
848
|
|
|
840
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)
|
|
841
860
|
observer = get_observer(args.config)
|
|
842
861
|
asyncio.run(observer.send_message(args.target, args.text))
|
|
843
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
|
|
@@ -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 (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))
|
|
@@ -15,7 +15,6 @@ from culture.clients.claude.config import (
|
|
|
15
15
|
load_config,
|
|
16
16
|
load_config_or_default,
|
|
17
17
|
)
|
|
18
|
-
from culture.pidfile import is_process_alive, read_pid
|
|
19
18
|
|
|
20
19
|
from .shared.constants import AGENTS_YAML, CULTURE_DIR, DEFAULT_CONFIG
|
|
21
20
|
from .shared.mesh import build_server_start_cmd, generate_mesh_from_agents
|
|
@@ -469,7 +468,7 @@ def _wait_for_server_port(port: int, retries: int = 50, interval: float = 0.1) -
|
|
|
469
468
|
try:
|
|
470
469
|
with _socket.create_connection(("localhost", port), timeout=1):
|
|
471
470
|
return
|
|
472
|
-
except
|
|
471
|
+
except OSError:
|
|
473
472
|
time.sleep(interval)
|
|
474
473
|
|
|
475
474
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Server subcommands: culture server {start,stop,status,default,rename}."""
|
|
1
|
+
"""Server subcommands: culture server {start,stop,status,default,rename,archive,unarchive}."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -14,6 +14,7 @@ import time
|
|
|
14
14
|
from culture.pidfile import (
|
|
15
15
|
is_culture_process,
|
|
16
16
|
is_process_alive,
|
|
17
|
+
read_default_server,
|
|
17
18
|
read_pid,
|
|
18
19
|
remove_pid,
|
|
19
20
|
write_pid,
|
|
@@ -32,13 +33,22 @@ logger = logging.getLogger("culture")
|
|
|
32
33
|
|
|
33
34
|
NAME = "server"
|
|
34
35
|
|
|
36
|
+
_DEFAULT_SERVER = "culture"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _resolve_server_name(args: argparse.Namespace) -> str:
|
|
40
|
+
"""Resolve the server name from args, default server file, or fallback."""
|
|
41
|
+
if args.name is not None:
|
|
42
|
+
return args.name
|
|
43
|
+
return read_default_server() or _DEFAULT_SERVER
|
|
44
|
+
|
|
35
45
|
|
|
36
46
|
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
37
47
|
server_parser = subparsers.add_parser("server", help="Manage the IRC server")
|
|
38
48
|
server_sub = server_parser.add_subparsers(dest="server_command")
|
|
39
49
|
|
|
40
50
|
srv_start = server_sub.add_parser("start", help="Start the IRC server daemon")
|
|
41
|
-
srv_start.add_argument("--name", default=
|
|
51
|
+
srv_start.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
|
|
42
52
|
srv_start.add_argument("--host", default="0.0.0.0", help="Listen address")
|
|
43
53
|
srv_start.add_argument("--port", type=int, default=6667, help="Listen port")
|
|
44
54
|
srv_start.add_argument(
|
|
@@ -66,10 +76,10 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
66
76
|
)
|
|
67
77
|
|
|
68
78
|
srv_stop = server_sub.add_parser("stop", help="Stop the IRC server daemon")
|
|
69
|
-
srv_stop.add_argument("--name", default=
|
|
79
|
+
srv_stop.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
|
|
70
80
|
|
|
71
81
|
srv_status = server_sub.add_parser("status", help="Check server daemon status")
|
|
72
|
-
srv_status.add_argument("--name", default=
|
|
82
|
+
srv_status.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
|
|
73
83
|
|
|
74
84
|
srv_default = server_sub.add_parser("default", help="Set default server")
|
|
75
85
|
srv_default.add_argument("name", help="Server name to set as default")
|
|
@@ -87,7 +97,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
87
97
|
srv_archive = server_sub.add_parser(
|
|
88
98
|
"archive", help="Archive the server and all its agents/bots"
|
|
89
99
|
)
|
|
90
|
-
srv_archive.add_argument("--name", default=
|
|
100
|
+
srv_archive.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
|
|
91
101
|
srv_archive.add_argument("--reason", default="", help="Reason for archiving")
|
|
92
102
|
srv_archive.add_argument(
|
|
93
103
|
"--config",
|
|
@@ -98,7 +108,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
98
108
|
srv_unarchive = server_sub.add_parser(
|
|
99
109
|
"unarchive", help="Restore an archived server and all its agents/bots"
|
|
100
110
|
)
|
|
101
|
-
srv_unarchive.add_argument("--name", default=
|
|
111
|
+
srv_unarchive.add_argument("--name", default=None, help=_SERVER_NAME_HELP)
|
|
102
112
|
srv_unarchive.add_argument(
|
|
103
113
|
"--config",
|
|
104
114
|
default=DEFAULT_CONFIG,
|
|
@@ -114,6 +124,10 @@ def dispatch(args: argparse.Namespace) -> None:
|
|
|
114
124
|
)
|
|
115
125
|
sys.exit(1)
|
|
116
126
|
|
|
127
|
+
# Resolve --name for commands that use it (all except default/rename)
|
|
128
|
+
if args.server_command not in ("default", "rename") and hasattr(args, "name"):
|
|
129
|
+
args.name = _resolve_server_name(args)
|
|
130
|
+
|
|
117
131
|
if args.server_command == "start":
|
|
118
132
|
_server_start(args)
|
|
119
133
|
elif args.server_command == "stop":
|
|
@@ -121,8 +135,40 @@ def dispatch(args: argparse.Namespace) -> None:
|
|
|
121
135
|
elif args.server_command == "status":
|
|
122
136
|
_server_status(args)
|
|
123
137
|
elif args.server_command == "default":
|
|
124
|
-
from
|
|
138
|
+
from pathlib import Path
|
|
139
|
+
|
|
140
|
+
from culture.pidfile import PID_DIR, list_servers, write_default_server
|
|
125
141
|
|
|
142
|
+
from .shared.constants import DEFAULT_CONFIG
|
|
143
|
+
|
|
144
|
+
# Accept the name if: it matches a running server, has a PID file,
|
|
145
|
+
# or matches the configured server name.
|
|
146
|
+
known_running = {s["name"] for s in list_servers()}
|
|
147
|
+
pid_dir = Path(PID_DIR)
|
|
148
|
+
known_pids = set()
|
|
149
|
+
if pid_dir.exists():
|
|
150
|
+
prefix = "server-"
|
|
151
|
+
for p in pid_dir.glob(f"{prefix}*.pid"):
|
|
152
|
+
known_pids.add(p.stem[len(prefix) :])
|
|
153
|
+
known_names = known_running | known_pids
|
|
154
|
+
|
|
155
|
+
# Also accept the configured server name
|
|
156
|
+
try:
|
|
157
|
+
from culture.clients.claude.config import load_config_or_default
|
|
158
|
+
|
|
159
|
+
config = load_config_or_default(DEFAULT_CONFIG)
|
|
160
|
+
known_names.add(config.server.name)
|
|
161
|
+
except Exception:
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
if args.name not in known_names:
|
|
165
|
+
print(f"Server '{args.name}' not found.", file=sys.stderr)
|
|
166
|
+
if known_names:
|
|
167
|
+
print(
|
|
168
|
+
f"Known servers: {', '.join(sorted(known_names))}",
|
|
169
|
+
file=sys.stderr,
|
|
170
|
+
)
|
|
171
|
+
sys.exit(1)
|
|
126
172
|
write_default_server(args.name)
|
|
127
173
|
print(f"Default server set to '{args.name}'")
|
|
128
174
|
elif args.server_command == "rename":
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
+
from culture.bots.config import BOT_CONFIG_FILE # noqa: F401
|
|
6
|
+
|
|
5
7
|
DEFAULT_CONFIG = os.path.expanduser("~/.culture/agents.yaml")
|
|
6
8
|
LOG_DIR = os.path.expanduser("~/.culture/logs")
|
|
7
9
|
|
|
@@ -9,7 +11,6 @@ _CONFIG_HELP = "Config file path"
|
|
|
9
11
|
_SERVER_NAME_HELP = "Server name"
|
|
10
12
|
_BOT_NAME_HELP = "Bot name"
|
|
11
13
|
|
|
12
|
-
BOT_CONFIG_FILE = "bot.yaml"
|
|
13
14
|
DEFAULT_CHANNEL = "#general"
|
|
14
15
|
NO_AGENTS_MSG = "No agents configured"
|
|
15
16
|
CULTURE_DIR = ".culture"
|
|
@@ -24,7 +24,7 @@ async def ipc_request(socket_path: str, msg_type: str, **kwargs) -> dict | None:
|
|
|
24
24
|
asyncio.open_unix_connection(socket_path),
|
|
25
25
|
timeout=3.0,
|
|
26
26
|
)
|
|
27
|
-
except
|
|
27
|
+
except OSError:
|
|
28
28
|
return None
|
|
29
29
|
try:
|
|
30
30
|
req = make_request(msg_type, **kwargs)
|
|
@@ -40,13 +40,13 @@ async def ipc_request(socket_path: str, msg_type: str, **kwargs) -> dict | None:
|
|
|
40
40
|
msg = decode_message(data)
|
|
41
41
|
if msg and msg.get("type") == "response":
|
|
42
42
|
return msg
|
|
43
|
-
except
|
|
43
|
+
except OSError:
|
|
44
44
|
return None
|
|
45
45
|
finally:
|
|
46
46
|
writer.close()
|
|
47
47
|
try:
|
|
48
48
|
await writer.wait_closed()
|
|
49
|
-
except
|
|
49
|
+
except OSError:
|
|
50
50
|
pass
|
|
51
51
|
|
|
52
52
|
|
|
@@ -151,7 +151,8 @@ class ACPAgentRunner:
|
|
|
151
151
|
return
|
|
152
152
|
try:
|
|
153
153
|
self._process.terminate()
|
|
154
|
-
|
|
154
|
+
async with asyncio.timeout(5):
|
|
155
|
+
await self._process.wait()
|
|
155
156
|
except (asyncio.TimeoutError, ProcessLookupError):
|
|
156
157
|
try:
|
|
157
158
|
self._process.kill()
|
|
@@ -209,7 +210,8 @@ class ACPAgentRunner:
|
|
|
209
210
|
await self._process.stdin.drain()
|
|
210
211
|
|
|
211
212
|
try:
|
|
212
|
-
|
|
213
|
+
async with asyncio.timeout(timeout):
|
|
214
|
+
return await future
|
|
213
215
|
except (asyncio.TimeoutError, asyncio.CancelledError):
|
|
214
216
|
self._pending.pop(req_id, None)
|
|
215
217
|
if not future.done():
|
|
@@ -244,14 +246,16 @@ class ACPAgentRunner:
|
|
|
244
246
|
if not self._process:
|
|
245
247
|
return -1
|
|
246
248
|
try:
|
|
247
|
-
|
|
249
|
+
async with asyncio.timeout(5):
|
|
250
|
+
return await self._process.wait()
|
|
248
251
|
except asyncio.TimeoutError:
|
|
249
252
|
try:
|
|
250
253
|
self._process.kill()
|
|
251
254
|
except ProcessLookupError:
|
|
252
255
|
pass
|
|
253
256
|
try:
|
|
254
|
-
|
|
257
|
+
async with asyncio.timeout(1):
|
|
258
|
+
return await self._process.wait()
|
|
255
259
|
except asyncio.TimeoutError:
|
|
256
260
|
return -1
|
|
257
261
|
|
|
@@ -175,7 +175,7 @@ def add_agent_to_config(
|
|
|
175
175
|
# Check for nick collision
|
|
176
176
|
for existing in config.agents:
|
|
177
177
|
if existing.nick == agent.nick:
|
|
178
|
-
raise ValueError(f"
|
|
178
|
+
raise ValueError(f"Agent with nick {agent.nick!r} already exists in config")
|
|
179
179
|
|
|
180
180
|
config.agents.append(agent)
|
|
181
181
|
save_config(path, config)
|
|
@@ -238,7 +238,7 @@ def rename_agent(
|
|
|
238
238
|
# Check new nick doesn't collide
|
|
239
239
|
for agent in config.agents:
|
|
240
240
|
if agent.nick == new_nick:
|
|
241
|
-
raise ValueError(f"
|
|
241
|
+
raise ValueError(f"Agent with nick {new_nick!r} already exists in config")
|
|
242
242
|
|
|
243
243
|
# Find and rename
|
|
244
244
|
for agent in config.agents:
|
|
@@ -247,7 +247,7 @@ def rename_agent(
|
|
|
247
247
|
save_config(path, config)
|
|
248
248
|
return
|
|
249
249
|
|
|
250
|
-
raise ValueError(f"
|
|
250
|
+
raise ValueError(f"Agent {old_nick!r} not found in config")
|
|
251
251
|
|
|
252
252
|
|
|
253
253
|
def remove_agent(
|
|
@@ -262,7 +262,7 @@ def remove_agent(
|
|
|
262
262
|
"""
|
|
263
263
|
path = Path(path)
|
|
264
264
|
if not path.exists():
|
|
265
|
-
raise ValueError(f"
|
|
265
|
+
raise ValueError(f"Agent {nick!r} not found in config")
|
|
266
266
|
|
|
267
267
|
with open(path) as f:
|
|
268
268
|
raw = yaml.safe_load(f) or {}
|
|
@@ -274,4 +274,4 @@ def remove_agent(
|
|
|
274
274
|
with open(path, "w") as f:
|
|
275
275
|
yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
|
|
276
276
|
return
|
|
277
|
-
raise ValueError(f"
|
|
277
|
+
raise ValueError(f"Agent {nick!r} not found in config")
|
|
@@ -31,6 +31,8 @@ logger = logging.getLogger(__name__)
|
|
|
31
31
|
|
|
32
32
|
# IPC validation error messages
|
|
33
33
|
_ERR_MISSING_CHANNEL = "Missing 'channel'"
|
|
34
|
+
_ERR_MISSING_CHANNEL_THREAD = "Missing 'channel' or 'thread'"
|
|
35
|
+
_ERR_MISSING_CHANNEL_THREAD_MSG = "Missing 'channel', 'thread', or 'message'"
|
|
34
36
|
|
|
35
37
|
MAX_CRASH_COUNT = 3
|
|
36
38
|
CRASH_WINDOW_SECONDS = 300
|
|
@@ -304,7 +306,7 @@ class ACPDaemon:
|
|
|
304
306
|
prompt = (
|
|
305
307
|
f"[IRC Channel Poll: {channel}] Recent unread messages:\n"
|
|
306
308
|
f"{lines}\n\n"
|
|
307
|
-
|
|
309
|
+
"Respond naturally if any messages need your attention."
|
|
308
310
|
)
|
|
309
311
|
self._mention_targets.append(channel)
|
|
310
312
|
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
@@ -485,10 +487,10 @@ class ACPDaemon:
|
|
|
485
487
|
return self.agent.system_prompt
|
|
486
488
|
return (
|
|
487
489
|
f"You are {self.agent.nick}, an AI agent on the culture IRC network.\n"
|
|
488
|
-
|
|
490
|
+
"You have IRC tools available via the irc skill. Use them to communicate.\n"
|
|
489
491
|
f"Your working directory is {self.agent.directory}.\n"
|
|
490
|
-
|
|
491
|
-
|
|
492
|
+
"Check IRC channels periodically with irc_read() for new messages.\n"
|
|
493
|
+
"When you finish a task, share results in the appropriate channel with irc_send()."
|
|
492
494
|
)
|
|
493
495
|
|
|
494
496
|
async def _record_crash_time(self, exit_code: int) -> None:
|
|
@@ -642,6 +644,13 @@ class ACPDaemon:
|
|
|
642
644
|
if query and running and not self._paused:
|
|
643
645
|
description = await self._query_agent_status()
|
|
644
646
|
|
|
647
|
+
if self._paused:
|
|
648
|
+
activity = "paused"
|
|
649
|
+
elif running:
|
|
650
|
+
activity = "working"
|
|
651
|
+
else:
|
|
652
|
+
activity = "idle"
|
|
653
|
+
|
|
645
654
|
return make_response(
|
|
646
655
|
req_id,
|
|
647
656
|
ok=True,
|
|
@@ -650,7 +659,7 @@ class ACPDaemon:
|
|
|
650
659
|
"paused": self._paused,
|
|
651
660
|
"turn_count": turn_count,
|
|
652
661
|
"last_activation": self._last_activation,
|
|
653
|
-
"activity":
|
|
662
|
+
"activity": activity,
|
|
654
663
|
"description": description,
|
|
655
664
|
},
|
|
656
665
|
)
|
|
@@ -687,7 +696,8 @@ class ACPDaemon:
|
|
|
687
696
|
"[SYSTEM] Briefly describe what you are currently working on "
|
|
688
697
|
"in one sentence. Reply with just the description, no preamble."
|
|
689
698
|
)
|
|
690
|
-
|
|
699
|
+
async with asyncio.timeout(10.0):
|
|
700
|
+
await self._status_query_event.wait()
|
|
691
701
|
return self._truncate_first_line(self._status_query_response) or "nothing"
|
|
692
702
|
except asyncio.TimeoutError:
|
|
693
703
|
return "busy (no response)"
|
|
@@ -744,9 +754,7 @@ class ACPDaemon:
|
|
|
744
754
|
thread_name = msg.get("thread", "")
|
|
745
755
|
text = msg.get("message", "")
|
|
746
756
|
if not channel or not thread_name or not text:
|
|
747
|
-
return make_response(
|
|
748
|
-
req_id, ok=False, error="Missing 'channel', 'thread', or 'message'"
|
|
749
|
-
)
|
|
757
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD_MSG)
|
|
750
758
|
assert self._transport is not None
|
|
751
759
|
await self._transport.send_thread_create(channel, thread_name, text)
|
|
752
760
|
return make_response(req_id, ok=True)
|
|
@@ -756,9 +764,7 @@ class ACPDaemon:
|
|
|
756
764
|
thread_name = msg.get("thread", "")
|
|
757
765
|
text = msg.get("message", "")
|
|
758
766
|
if not channel or not thread_name or not text:
|
|
759
|
-
return make_response(
|
|
760
|
-
req_id, ok=False, error="Missing 'channel', 'thread', or 'message'"
|
|
761
|
-
)
|
|
767
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD_MSG)
|
|
762
768
|
assert self._transport is not None
|
|
763
769
|
await self._transport.send_thread_reply(channel, thread_name, text)
|
|
764
770
|
return make_response(req_id, ok=True)
|
|
@@ -776,7 +782,7 @@ class ACPDaemon:
|
|
|
776
782
|
thread_name = msg.get("thread", "")
|
|
777
783
|
summary = msg.get("summary", "")
|
|
778
784
|
if not channel or not thread_name:
|
|
779
|
-
return make_response(req_id, ok=False, error=
|
|
785
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD)
|
|
780
786
|
assert self._transport is not None
|
|
781
787
|
await self._transport.send_thread_close(channel, thread_name, summary)
|
|
782
788
|
return make_response(req_id, ok=True)
|
|
@@ -786,7 +792,7 @@ class ACPDaemon:
|
|
|
786
792
|
thread_name = msg.get("thread", "")
|
|
787
793
|
limit = int(msg.get("limit", 50))
|
|
788
794
|
if not channel or not thread_name:
|
|
789
|
-
return make_response(req_id, ok=False, error=
|
|
795
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD)
|
|
790
796
|
assert self._buffer is not None
|
|
791
797
|
messages = self._buffer.read_thread(channel, thread_name, limit=limit)
|
|
792
798
|
return make_response(
|