agentirc-cli 4.4.0__tar.gz → 4.4.1__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.4.0 → agentirc_cli-4.4.1}/CHANGELOG.md +13 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/PKG-INFO +1 -1
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/agent.py +5 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/shared/display.py +2 -1
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/shared/ipc.py +1 -1
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/agent_runner.py +23 -3
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/config.py +67 -38
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/irc_transport.py +4 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/config.py +107 -74
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/irc_transport.py +4 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/config.py +64 -37
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/irc_transport.py +4 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/config.py +64 -37
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/irc_transport.py +4 -0
- agentirc_cli-4.4.1/packages/agent-harness/irc_transport.py +238 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/pyproject.toml +1 -1
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_acp_daemon.py +61 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_archive.py +167 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_daemon_config.py +90 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_mention_alias.py +29 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/uv.lock +1 -1
- agentirc_cli-4.4.0/packages/agent-harness/irc_transport.py +0 -229
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.flake8 +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.gitignore +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.pr_agent.toml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/.pylintrc +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/CLAUDE.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/CNAME +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/Gemfile +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/Gemfile.lock +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/LICENSE +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/README.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/SECURITY.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/_config.yml +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/__main__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/aio.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/bots/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/bots/bot.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/bots/config.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/bot.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/channel.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/mesh.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/server.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/shared/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/shared/constants.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/shared/formatting.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/shared/mesh.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/shared/process.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/cli/skills.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/skill/irc_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/skill/irc_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/app.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/commands.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/credentials.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/formatting.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/learn_prompt.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/mesh_config.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/observer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/overview/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/overview/collector.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/overview/model.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/overview/web/style.css +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/persistence.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/pidfile.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/commands.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/message.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/protocol/replies.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/__main__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/channel.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/config.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/history_store.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/ircd.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/remote_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/room_store.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/server_link.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/skill.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/skills/history.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/skills/icon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/skills/rooms.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/skills/threads.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/server/thread_store.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/agent-lifecycle.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/agent-client.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/agent-harness-spec.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/harness-conformance.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/index.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/layer1-core-irc.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/layer2-attention.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/layer3-skills.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/layer4-federation.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/layer5-agent-harness.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/server-architecture.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/architecture/threads.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/channel-polling.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/culture-cli.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/getting-started.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/index.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/SECURITY.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/bots.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/ci.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/cli.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/docs-site.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/index.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/ops-tooling.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/overview.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/operations/publishing.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/persistent-history.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/rooms.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/server-rename.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/use-cases-index.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/docs/what-is-culture.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/sonar-project.properties +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/__init__.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/conftest.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_bot.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_bot_config.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_channel.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_connection.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_console_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_console_commands.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_console_connection.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_console_icons.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_console_integration.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_daemon.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_discovery.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_federation.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_history.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_http_listener.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_ipc.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_mentions.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_message.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_messaging.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_modes.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_overview_model.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_overview_web.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_persistence.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_pidfile.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_rooms.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_skill_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_skills.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_socket_server.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_supervisor.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_template_engine.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_threads.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_wait_for_port.py +0 -0
- {agentirc_cli-4.4.0 → agentirc_cli-4.4.1}/tests/test_webhook.py +0 -0
|
@@ -4,6 +4,19 @@ 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.4.1] - 2026-04-07
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Config save operations no longer strip backend-specific fields like acp_command (#150)
|
|
13
|
+
- Agent status detail uses cached description by default, --full for live query; IPC deadline increased to 15s (#152)
|
|
14
|
+
- DMs now activate agents — _detect_and_fire_mention handles direct messages in all backends (#153)
|
|
15
|
+
- ACP agent runner preserves HOME/XDG_CONFIG_HOME for auth tokens; warns on authMethods, fails fast on session creation failure (#154)
|
|
16
|
+
- _coerce_to_acp_agent now copies the icon field (#155)
|
|
17
|
+
- _make_backend_config passes supervisor, poll_interval, sleep_start, sleep_end to non-claude backends (#156)
|
|
18
|
+
- ACP load_config strips unknown fields, matching claude/codex/copilot pattern (#157)
|
|
19
|
+
|
|
7
20
|
## [4.4.0] - 2026-04-07
|
|
8
21
|
|
|
9
22
|
|
|
@@ -455,8 +455,12 @@ def _make_backend_config(config: DaemonConfig, backend_daemon_config_cls):
|
|
|
455
455
|
"""Build a backend-specific DaemonConfig from the base config."""
|
|
456
456
|
return backend_daemon_config_cls(
|
|
457
457
|
server=config.server,
|
|
458
|
+
supervisor=config.supervisor,
|
|
458
459
|
webhooks=config.webhooks,
|
|
459
460
|
buffer_size=config.buffer_size,
|
|
461
|
+
poll_interval=config.poll_interval,
|
|
462
|
+
sleep_start=config.sleep_start,
|
|
463
|
+
sleep_end=config.sleep_end,
|
|
460
464
|
agents=config.agents,
|
|
461
465
|
)
|
|
462
466
|
|
|
@@ -484,6 +488,7 @@ def _coerce_to_acp_agent(agent: AgentConfig):
|
|
|
484
488
|
model=agent.model,
|
|
485
489
|
system_prompt=agent.system_prompt,
|
|
486
490
|
tags=agent.tags,
|
|
491
|
+
icon=agent.icon,
|
|
487
492
|
)
|
|
488
493
|
|
|
489
494
|
|
|
@@ -37,7 +37,8 @@ def print_agent_detail(agent, config_path: str, args: argparse.Namespace) -> Non
|
|
|
37
37
|
print(f" PID: {pid or '-'}")
|
|
38
38
|
|
|
39
39
|
if status == "running":
|
|
40
|
-
|
|
40
|
+
query = getattr(args, "full", False)
|
|
41
|
+
resp = asyncio.run(ipc_request(agent_socket_path(agent.nick), "status", query=query))
|
|
41
42
|
if resp and resp.get("ok"):
|
|
42
43
|
data = resp.get("data", {})
|
|
43
44
|
print(f" Activity: {data.get('description', 'nothing')}")
|
|
@@ -31,7 +31,7 @@ async def ipc_request(socket_path: str, msg_type: str, **kwargs) -> dict | None:
|
|
|
31
31
|
writer.write(encode_message(req))
|
|
32
32
|
await writer.drain()
|
|
33
33
|
loop = asyncio.get_running_loop()
|
|
34
|
-
deadline = loop.time() +
|
|
34
|
+
deadline = loop.time() + 15.0
|
|
35
35
|
while True:
|
|
36
36
|
remaining = deadline - loop.time()
|
|
37
37
|
if remaining <= 0:
|
|
@@ -70,11 +70,12 @@ class ACPAgentRunner:
|
|
|
70
70
|
"""Start the ACP agent as a subprocess and initialize a session."""
|
|
71
71
|
self._stopping = False
|
|
72
72
|
|
|
73
|
-
# Isolate
|
|
73
|
+
# Isolate data/state dirs to prevent session interference, but
|
|
74
|
+
# preserve HOME and XDG_CONFIG_HOME so the agent finds auth tokens.
|
|
74
75
|
self._isolated_home = tempfile.mkdtemp(prefix="culture-acp-")
|
|
75
76
|
isolated_env = dict(os.environ)
|
|
76
|
-
isolated_env["
|
|
77
|
-
isolated_env.
|
|
77
|
+
isolated_env["XDG_DATA_HOME"] = os.path.join(self._isolated_home, ".local", "share")
|
|
78
|
+
isolated_env["XDG_STATE_HOME"] = os.path.join(self._isolated_home, ".local", "state")
|
|
78
79
|
|
|
79
80
|
cmd_label = " ".join(self.acp_command)
|
|
80
81
|
try:
|
|
@@ -108,6 +109,18 @@ class ACPAgentRunner:
|
|
|
108
109
|
)
|
|
109
110
|
logger.info("ACP initialized (%s): %s", cmd_label, resp)
|
|
110
111
|
|
|
112
|
+
# Log available auth methods as a hint
|
|
113
|
+
init_result = resp.get("result", {})
|
|
114
|
+
auth_methods = init_result.get("authMethods", [])
|
|
115
|
+
if auth_methods:
|
|
116
|
+
descriptions = [m.get("description", m.get("id", "unknown")) for m in auth_methods]
|
|
117
|
+
logger.warning(
|
|
118
|
+
"ACP agent (%s) reports auth methods: %s. "
|
|
119
|
+
"If prompts fail, configure auth tokens.",
|
|
120
|
+
cmd_label,
|
|
121
|
+
", ".join(descriptions),
|
|
122
|
+
)
|
|
123
|
+
|
|
111
124
|
# Create a session with model selection
|
|
112
125
|
session_params = {
|
|
113
126
|
"cwd": self.directory,
|
|
@@ -120,6 +133,13 @@ class ACPAgentRunner:
|
|
|
120
133
|
logger.info("ACP session/new raw response: %s", json.dumps(resp)[:500])
|
|
121
134
|
result = resp.get("result", {})
|
|
122
135
|
self._session_id = result.get("sessionId")
|
|
136
|
+
if not self._session_id:
|
|
137
|
+
# Session creation failed — likely auth or model issue
|
|
138
|
+
error = resp.get("error", {})
|
|
139
|
+
error_msg = error.get("message", "unknown error")
|
|
140
|
+
if auth_methods:
|
|
141
|
+
error_msg += f". Auth may be required: {', '.join(descriptions)}"
|
|
142
|
+
raise RuntimeError(f"ACP agent ({cmd_label}) session creation failed: {error_msg}")
|
|
123
143
|
self._running = True
|
|
124
144
|
logger.info("ACP session started (%s): %s", cmd_label, self._session_id)
|
|
125
145
|
|
|
@@ -93,8 +93,10 @@ def load_config(path: str | Path) -> DaemonConfig:
|
|
|
93
93
|
webhooks = WebhookConfig(**raw.get("webhooks", {}))
|
|
94
94
|
|
|
95
95
|
agents = []
|
|
96
|
+
known_agent_fields = {f.name for f in AgentConfig.__dataclass_fields__.values()}
|
|
96
97
|
for agent_raw in raw.get("agents", []):
|
|
97
|
-
|
|
98
|
+
filtered = {k: v for k, v in agent_raw.items() if k in known_agent_fields}
|
|
99
|
+
agents.append(AgentConfig(**filtered))
|
|
98
100
|
|
|
99
101
|
return DaemonConfig(
|
|
100
102
|
server=server,
|
|
@@ -157,6 +159,32 @@ def save_config(path: str | Path, config: DaemonConfig) -> None:
|
|
|
157
159
|
raise
|
|
158
160
|
|
|
159
161
|
|
|
162
|
+
def _load_raw_yaml(path: str | Path) -> dict:
|
|
163
|
+
"""Load raw YAML from a config file, returning empty dict if missing."""
|
|
164
|
+
path = Path(path)
|
|
165
|
+
if not path.exists():
|
|
166
|
+
return {}
|
|
167
|
+
with open(path) as f:
|
|
168
|
+
return yaml.safe_load(f) or {}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _save_raw_yaml(path: str | Path, raw: dict) -> None:
|
|
172
|
+
"""Write raw YAML dict atomically."""
|
|
173
|
+
path = Path(path)
|
|
174
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
175
|
+
fd, tmp_path = tempfile.mkstemp(dir=str(path.parent), suffix=".yaml.tmp")
|
|
176
|
+
try:
|
|
177
|
+
with os.fdopen(fd, "w") as f:
|
|
178
|
+
yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
|
|
179
|
+
os.replace(tmp_path, str(path))
|
|
180
|
+
except BaseException:
|
|
181
|
+
try:
|
|
182
|
+
os.unlink(tmp_path)
|
|
183
|
+
except OSError:
|
|
184
|
+
pass
|
|
185
|
+
raise
|
|
186
|
+
|
|
187
|
+
|
|
160
188
|
def add_agent_to_config(
|
|
161
189
|
path: str | Path,
|
|
162
190
|
agent: AgentConfig,
|
|
@@ -166,20 +194,21 @@ def add_agent_to_config(
|
|
|
166
194
|
|
|
167
195
|
If server_name is provided, updates config.server.name.
|
|
168
196
|
Raises ValueError if an agent with the same nick already exists.
|
|
197
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
169
198
|
"""
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if server_name is not None:
|
|
173
|
-
config.server.name = server_name
|
|
199
|
+
raw = _load_raw_yaml(path)
|
|
200
|
+
agents = raw.setdefault("agents", [])
|
|
174
201
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if existing.nick == agent.nick:
|
|
202
|
+
for existing in agents:
|
|
203
|
+
if existing.get("nick") == agent.nick:
|
|
178
204
|
raise ValueError(f"Agent with nick {agent.nick!r} already exists in config")
|
|
179
205
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
206
|
+
if server_name is not None:
|
|
207
|
+
raw.setdefault("server", {})["name"] = server_name
|
|
208
|
+
|
|
209
|
+
agents.append(asdict(agent))
|
|
210
|
+
_save_raw_yaml(path, raw)
|
|
211
|
+
return load_config(path)
|
|
183
212
|
|
|
184
213
|
|
|
185
214
|
def rename_server(
|
|
@@ -189,23 +218,26 @@ def rename_server(
|
|
|
189
218
|
"""Rename the server and update all agent nick prefixes.
|
|
190
219
|
|
|
191
220
|
Returns (old_name, [(old_nick, new_nick), ...]).
|
|
221
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
192
222
|
"""
|
|
193
|
-
|
|
194
|
-
|
|
223
|
+
raw = _load_raw_yaml(path)
|
|
224
|
+
server = raw.get("server", {})
|
|
225
|
+
old_name = server.get("name", ServerConnConfig().name)
|
|
195
226
|
|
|
196
227
|
if old_name == new_name:
|
|
197
228
|
return old_name, []
|
|
198
229
|
|
|
199
|
-
|
|
230
|
+
agents = raw.get("agents", [])
|
|
200
231
|
prefix = f"{old_name}-"
|
|
201
232
|
plan: list[tuple[int, str, str]] = []
|
|
202
|
-
for i,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
233
|
+
for i, agent_raw in enumerate(agents):
|
|
234
|
+
nick = agent_raw.get("nick", "")
|
|
235
|
+
if nick.startswith(prefix):
|
|
236
|
+
new_nick = f"{new_name}-{nick[len(prefix):]}"
|
|
237
|
+
plan.append((i, nick, new_nick))
|
|
206
238
|
|
|
207
239
|
planned_nicks = {new_nick for _, _, new_nick in plan}
|
|
208
|
-
existing_nicks = {a.nick for a in
|
|
240
|
+
existing_nicks = {a.get("nick", "") for a in agents} - {old for _, old, _ in plan}
|
|
209
241
|
collisions = planned_nicks & existing_nicks
|
|
210
242
|
if collisions:
|
|
211
243
|
raise ValueError(
|
|
@@ -213,14 +245,15 @@ def rename_server(
|
|
|
213
245
|
f"duplicate nick(s): {', '.join(sorted(collisions))}"
|
|
214
246
|
)
|
|
215
247
|
|
|
216
|
-
|
|
248
|
+
server["name"] = new_name
|
|
249
|
+
raw["server"] = server
|
|
217
250
|
|
|
218
251
|
renamed: list[tuple[str, str]] = []
|
|
219
252
|
for i, old_nick, new_nick in plan:
|
|
220
|
-
|
|
253
|
+
agents[i]["nick"] = new_nick
|
|
221
254
|
renamed.append((old_nick, new_nick))
|
|
222
255
|
|
|
223
|
-
|
|
256
|
+
_save_raw_yaml(path, raw)
|
|
224
257
|
return old_name, renamed
|
|
225
258
|
|
|
226
259
|
|
|
@@ -232,19 +265,19 @@ def rename_agent(
|
|
|
232
265
|
"""Rename an agent's nick in the config.
|
|
233
266
|
|
|
234
267
|
Raises ValueError if old_nick is not found or new_nick already exists.
|
|
268
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
235
269
|
"""
|
|
236
|
-
|
|
270
|
+
raw = _load_raw_yaml(path)
|
|
271
|
+
agents = raw.get("agents", [])
|
|
237
272
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if agent.nick == new_nick:
|
|
273
|
+
for agent_raw in agents:
|
|
274
|
+
if agent_raw.get("nick") == new_nick:
|
|
241
275
|
raise ValueError(f"Agent with nick {new_nick!r} already exists in config")
|
|
242
276
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
save_config(path, config)
|
|
277
|
+
for agent_raw in agents:
|
|
278
|
+
if agent_raw.get("nick") == old_nick:
|
|
279
|
+
agent_raw["nick"] = new_nick
|
|
280
|
+
_save_raw_yaml(path, raw)
|
|
248
281
|
return
|
|
249
282
|
|
|
250
283
|
raise ValueError(f"Agent {old_nick!r} not found in config")
|
|
@@ -260,18 +293,14 @@ def remove_agent(
|
|
|
260
293
|
agents that the typed schema would strip.
|
|
261
294
|
Raises ValueError if the agent is not found.
|
|
262
295
|
"""
|
|
263
|
-
|
|
264
|
-
if not
|
|
296
|
+
raw = _load_raw_yaml(path)
|
|
297
|
+
if not raw:
|
|
265
298
|
raise ValueError(f"Agent {nick!r} not found in config")
|
|
266
299
|
|
|
267
|
-
with open(path) as f:
|
|
268
|
-
raw = yaml.safe_load(f) or {}
|
|
269
|
-
|
|
270
300
|
agents = raw.get("agents", [])
|
|
271
301
|
for i, agent_raw in enumerate(agents):
|
|
272
302
|
if agent_raw.get("nick") == nick:
|
|
273
303
|
agents.pop(i)
|
|
274
|
-
|
|
275
|
-
yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
|
|
304
|
+
_save_raw_yaml(path, raw)
|
|
276
305
|
return
|
|
277
306
|
raise ValueError(f"Agent {nick!r} not found in config")
|
|
@@ -213,6 +213,10 @@ class IRCTransport:
|
|
|
213
213
|
"""Check if the message mentions this agent and fire the callback."""
|
|
214
214
|
if not self.on_mention:
|
|
215
215
|
return
|
|
216
|
+
# DMs always activate (target is the agent's own nick)
|
|
217
|
+
if target == self.nick:
|
|
218
|
+
self.on_mention(target, sender, text)
|
|
219
|
+
return
|
|
216
220
|
short = self.nick.split("-", 1)[1] if "-" in self.nick else None
|
|
217
221
|
if re.search(rf"@{re.escape(self.nick)}\b", text) or (
|
|
218
222
|
short and re.search(rf"@{re.escape(short)}\b", text)
|
|
@@ -167,6 +167,32 @@ def save_config(path: str | Path, config: DaemonConfig) -> None:
|
|
|
167
167
|
raise
|
|
168
168
|
|
|
169
169
|
|
|
170
|
+
def _load_raw_yaml(path: str | Path) -> dict:
|
|
171
|
+
"""Load raw YAML from a config file, returning empty dict if missing."""
|
|
172
|
+
path = Path(path)
|
|
173
|
+
if not path.exists():
|
|
174
|
+
return {}
|
|
175
|
+
with open(path) as f:
|
|
176
|
+
return yaml.safe_load(f) or {}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _save_raw_yaml(path: str | Path, raw: dict) -> None:
|
|
180
|
+
"""Write raw YAML dict atomically."""
|
|
181
|
+
path = Path(path)
|
|
182
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
183
|
+
fd, tmp_path = tempfile.mkstemp(dir=str(path.parent), suffix=".yaml.tmp")
|
|
184
|
+
try:
|
|
185
|
+
with os.fdopen(fd, "w") as f:
|
|
186
|
+
yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
|
|
187
|
+
os.replace(tmp_path, str(path))
|
|
188
|
+
except BaseException:
|
|
189
|
+
try:
|
|
190
|
+
os.unlink(tmp_path)
|
|
191
|
+
except OSError:
|
|
192
|
+
pass
|
|
193
|
+
raise
|
|
194
|
+
|
|
195
|
+
|
|
170
196
|
def add_agent_to_config(
|
|
171
197
|
path: str | Path,
|
|
172
198
|
agent: AgentConfig,
|
|
@@ -176,20 +202,21 @@ def add_agent_to_config(
|
|
|
176
202
|
|
|
177
203
|
If server_name is provided, updates config.server.name.
|
|
178
204
|
Raises ValueError if an agent with the same nick already exists.
|
|
205
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
179
206
|
"""
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if server_name is not None:
|
|
183
|
-
config.server.name = server_name
|
|
207
|
+
raw = _load_raw_yaml(path)
|
|
208
|
+
agents = raw.setdefault("agents", [])
|
|
184
209
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if existing.nick == agent.nick:
|
|
210
|
+
for existing in agents:
|
|
211
|
+
if existing.get("nick") == agent.nick:
|
|
188
212
|
raise ValueError(f"Agent with nick {agent.nick!r} already exists in config")
|
|
189
213
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
214
|
+
if server_name is not None:
|
|
215
|
+
raw.setdefault("server", {})["name"] = server_name
|
|
216
|
+
|
|
217
|
+
agents.append(asdict(agent))
|
|
218
|
+
_save_raw_yaml(path, raw)
|
|
219
|
+
return load_config(path)
|
|
193
220
|
|
|
194
221
|
|
|
195
222
|
def rename_server(
|
|
@@ -199,23 +226,26 @@ def rename_server(
|
|
|
199
226
|
"""Rename the server and update all agent nick prefixes.
|
|
200
227
|
|
|
201
228
|
Returns (old_name, [(old_nick, new_nick), ...]).
|
|
229
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
202
230
|
"""
|
|
203
|
-
|
|
204
|
-
|
|
231
|
+
raw = _load_raw_yaml(path)
|
|
232
|
+
server = raw.get("server", {})
|
|
233
|
+
old_name = server.get("name", ServerConnConfig().name)
|
|
205
234
|
|
|
206
235
|
if old_name == new_name:
|
|
207
236
|
return old_name, []
|
|
208
237
|
|
|
209
|
-
|
|
238
|
+
agents = raw.get("agents", [])
|
|
210
239
|
prefix = f"{old_name}-"
|
|
211
240
|
plan: list[tuple[int, str, str]] = []
|
|
212
|
-
for i,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
241
|
+
for i, agent_raw in enumerate(agents):
|
|
242
|
+
nick = agent_raw.get("nick", "")
|
|
243
|
+
if nick.startswith(prefix):
|
|
244
|
+
new_nick = f"{new_name}-{nick[len(prefix):]}"
|
|
245
|
+
plan.append((i, nick, new_nick))
|
|
216
246
|
|
|
217
247
|
planned_nicks = {new_nick for _, _, new_nick in plan}
|
|
218
|
-
existing_nicks = {a.nick for a in
|
|
248
|
+
existing_nicks = {a.get("nick", "") for a in agents} - {old for _, old, _ in plan}
|
|
219
249
|
collisions = planned_nicks & existing_nicks
|
|
220
250
|
if collisions:
|
|
221
251
|
raise ValueError(
|
|
@@ -223,14 +253,15 @@ def rename_server(
|
|
|
223
253
|
f"duplicate nick(s): {', '.join(sorted(collisions))}"
|
|
224
254
|
)
|
|
225
255
|
|
|
226
|
-
|
|
256
|
+
server["name"] = new_name
|
|
257
|
+
raw["server"] = server
|
|
227
258
|
|
|
228
259
|
renamed: list[tuple[str, str]] = []
|
|
229
260
|
for i, old_nick, new_nick in plan:
|
|
230
|
-
|
|
261
|
+
agents[i]["nick"] = new_nick
|
|
231
262
|
renamed.append((old_nick, new_nick))
|
|
232
263
|
|
|
233
|
-
|
|
264
|
+
_save_raw_yaml(path, raw)
|
|
234
265
|
return old_name, renamed
|
|
235
266
|
|
|
236
267
|
|
|
@@ -242,19 +273,19 @@ def rename_agent(
|
|
|
242
273
|
"""Rename an agent's nick in the config.
|
|
243
274
|
|
|
244
275
|
Raises ValueError if old_nick is not found or new_nick already exists.
|
|
276
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
245
277
|
"""
|
|
246
|
-
|
|
278
|
+
raw = _load_raw_yaml(path)
|
|
279
|
+
agents = raw.get("agents", [])
|
|
247
280
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if agent.nick == new_nick:
|
|
281
|
+
for agent_raw in agents:
|
|
282
|
+
if agent_raw.get("nick") == new_nick:
|
|
251
283
|
raise ValueError(f"Agent with nick {new_nick!r} already exists in config")
|
|
252
284
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
save_config(path, config)
|
|
285
|
+
for agent_raw in agents:
|
|
286
|
+
if agent_raw.get("nick") == old_nick:
|
|
287
|
+
agent_raw["nick"] = new_nick
|
|
288
|
+
_save_raw_yaml(path, raw)
|
|
258
289
|
return
|
|
259
290
|
|
|
260
291
|
raise ValueError(f"Agent {old_nick!r} not found in config")
|
|
@@ -268,16 +299,17 @@ def archive_agent(
|
|
|
268
299
|
"""Set the archived flag on an agent.
|
|
269
300
|
|
|
270
301
|
Raises ValueError if the agent is not found.
|
|
302
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
271
303
|
"""
|
|
272
304
|
import time
|
|
273
305
|
|
|
274
|
-
|
|
275
|
-
for
|
|
276
|
-
if
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
306
|
+
raw = _load_raw_yaml(path)
|
|
307
|
+
for agent_raw in raw.get("agents", []):
|
|
308
|
+
if agent_raw.get("nick") == nick:
|
|
309
|
+
agent_raw["archived"] = True
|
|
310
|
+
agent_raw["archived_at"] = time.strftime("%Y-%m-%d")
|
|
311
|
+
agent_raw["archived_reason"] = reason
|
|
312
|
+
_save_raw_yaml(path, raw)
|
|
281
313
|
return
|
|
282
314
|
raise ValueError(f"Agent {nick!r} not found in config")
|
|
283
315
|
|
|
@@ -289,16 +321,17 @@ def unarchive_agent(
|
|
|
289
321
|
"""Clear the archived flag on an agent.
|
|
290
322
|
|
|
291
323
|
Raises ValueError if not found or not currently archived.
|
|
324
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
292
325
|
"""
|
|
293
|
-
|
|
294
|
-
for
|
|
295
|
-
if
|
|
296
|
-
if not
|
|
326
|
+
raw = _load_raw_yaml(path)
|
|
327
|
+
for agent_raw in raw.get("agents", []):
|
|
328
|
+
if agent_raw.get("nick") == nick:
|
|
329
|
+
if not agent_raw.get("archived"):
|
|
297
330
|
raise ValueError(f"Agent {nick!r} is not archived")
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
331
|
+
agent_raw["archived"] = False
|
|
332
|
+
agent_raw["archived_at"] = ""
|
|
333
|
+
agent_raw["archived_reason"] = ""
|
|
334
|
+
_save_raw_yaml(path, raw)
|
|
302
335
|
return
|
|
303
336
|
raise ValueError(f"Agent {nick!r} not found in config")
|
|
304
337
|
|
|
@@ -313,19 +346,15 @@ def remove_agent(
|
|
|
313
346
|
acp_command) on other agents that the typed schema would strip.
|
|
314
347
|
Raises ValueError if the agent is not found.
|
|
315
348
|
"""
|
|
316
|
-
|
|
317
|
-
if not
|
|
349
|
+
raw = _load_raw_yaml(path)
|
|
350
|
+
if not raw:
|
|
318
351
|
raise ValueError(f"Agent {nick!r} not found in config")
|
|
319
352
|
|
|
320
|
-
with open(path) as f:
|
|
321
|
-
raw = yaml.safe_load(f) or {}
|
|
322
|
-
|
|
323
353
|
agents = raw.get("agents", [])
|
|
324
354
|
for i, agent_raw in enumerate(agents):
|
|
325
355
|
if agent_raw.get("nick") == nick:
|
|
326
356
|
agents.pop(i)
|
|
327
|
-
|
|
328
|
-
yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
|
|
357
|
+
_save_raw_yaml(path, raw)
|
|
329
358
|
return
|
|
330
359
|
raise ValueError(f"Agent {nick!r} not found in config")
|
|
331
360
|
|
|
@@ -337,24 +366,26 @@ def archive_server(
|
|
|
337
366
|
"""Set the archived flag on the server and all its agents.
|
|
338
367
|
|
|
339
368
|
Returns a list of archived agent nicks.
|
|
369
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
340
370
|
"""
|
|
341
371
|
import time
|
|
342
372
|
|
|
343
|
-
|
|
373
|
+
raw = _load_raw_yaml(path)
|
|
344
374
|
today = time.strftime("%Y-%m-%d")
|
|
345
375
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
376
|
+
server = raw.setdefault("server", {})
|
|
377
|
+
server["archived"] = True
|
|
378
|
+
server["archived_at"] = today
|
|
379
|
+
server["archived_reason"] = reason
|
|
349
380
|
|
|
350
381
|
archived_nicks = []
|
|
351
|
-
for
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
archived_nicks.append(
|
|
382
|
+
for agent_raw in raw.get("agents", []):
|
|
383
|
+
agent_raw["archived"] = True
|
|
384
|
+
agent_raw["archived_at"] = today
|
|
385
|
+
agent_raw["archived_reason"] = reason
|
|
386
|
+
archived_nicks.append(agent_raw.get("nick", ""))
|
|
356
387
|
|
|
357
|
-
|
|
388
|
+
_save_raw_yaml(path, raw)
|
|
358
389
|
return archived_nicks
|
|
359
390
|
|
|
360
391
|
|
|
@@ -364,20 +395,22 @@ def unarchive_server(
|
|
|
364
395
|
"""Clear the archived flag on the server and all its agents.
|
|
365
396
|
|
|
366
397
|
Returns a list of unarchived agent nicks.
|
|
398
|
+
Operates on raw YAML to preserve backend-specific fields.
|
|
367
399
|
"""
|
|
368
|
-
|
|
400
|
+
raw = _load_raw_yaml(path)
|
|
369
401
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
402
|
+
server = raw.setdefault("server", {})
|
|
403
|
+
server["archived"] = False
|
|
404
|
+
server["archived_at"] = ""
|
|
405
|
+
server["archived_reason"] = ""
|
|
373
406
|
|
|
374
407
|
unarchived_nicks = []
|
|
375
|
-
for
|
|
376
|
-
if
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
unarchived_nicks.append(
|
|
381
|
-
|
|
382
|
-
|
|
408
|
+
for agent_raw in raw.get("agents", []):
|
|
409
|
+
if agent_raw.get("archived"):
|
|
410
|
+
agent_raw["archived"] = False
|
|
411
|
+
agent_raw["archived_at"] = ""
|
|
412
|
+
agent_raw["archived_reason"] = ""
|
|
413
|
+
unarchived_nicks.append(agent_raw.get("nick", ""))
|
|
414
|
+
|
|
415
|
+
_save_raw_yaml(path, raw)
|
|
383
416
|
return unarchived_nicks
|
|
@@ -213,6 +213,10 @@ class IRCTransport:
|
|
|
213
213
|
"""Check if the message mentions this agent and fire the callback."""
|
|
214
214
|
if not self.on_mention:
|
|
215
215
|
return
|
|
216
|
+
# DMs always activate (target is the agent's own nick)
|
|
217
|
+
if target == self.nick:
|
|
218
|
+
self.on_mention(target, sender, text)
|
|
219
|
+
return
|
|
216
220
|
short = self.nick.split("-", 1)[1] if "-" in self.nick else None
|
|
217
221
|
if re.search(rf"@{re.escape(self.nick)}\b", text) or (
|
|
218
222
|
short and re.search(rf"@{re.escape(short)}\b", text)
|