agentirc-cli 4.1.2__tar.gz → 4.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/CHANGELOG.md +7 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/PKG-INFO +1 -1
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/mesh.py +64 -11
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/mesh_config.py +9 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/cli.md +5 -2
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/pyproject.toml +1 -1
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_mesh_config.py +37 -0
- agentirc_cli-4.1.3/tests/test_setup_update_cli.py +185 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/uv.lock +1 -1
- agentirc_cli-4.1.2/tests/test_setup_update_cli.py +0 -45
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.flake8 +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.gitignore +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.pr_agent.toml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/.pylintrc +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/CLAUDE.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/CNAME +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/Gemfile +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/Gemfile.lock +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/LICENSE +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/README.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/SECURITY.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/_config.yml +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/__main__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/bots/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/bots/bot.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/bots/config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/_helpers.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/agent.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/bot.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/channel.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/server.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/cli/skills.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/agent_runner.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/irc_transport.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/skill/irc_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/skill/irc_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/app.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/commands.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/credentials.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/learn_prompt.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/observer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/overview/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/overview/collector.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/overview/model.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/overview/web/style.css +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/persistence.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/pidfile.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/commands.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/message.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/protocol/replies.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/__main__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/channel.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/ircd.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/remote_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/room_store.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/server_link.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/skill.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/skills/history.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/skills/icon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/skills/rooms.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/skills/threads.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/server/thread_store.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/agent-lifecycle.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/agent-client.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/agent-harness-spec.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/harness-conformance.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/index.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/layer1-core-irc.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/layer2-attention.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/layer3-skills.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/layer4-federation.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/layer5-agent-harness.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/server-architecture.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/architecture/threads.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/channel-polling.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/culture-cli.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/getting-started.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/index.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/SECURITY.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/bots.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/ci.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/docs-site.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/index.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/ops-tooling.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/overview.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/operations/publishing.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/rooms.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/server-rename.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/use-cases-index.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/docs/what-is-culture.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/sonar-project.properties +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/__init__.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/conftest.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_bot.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_bot_config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_channel.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_connection.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_console_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_console_commands.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_console_connection.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_console_icons.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_console_integration.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_daemon.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_discovery.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_federation.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_history.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_http_listener.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_ipc.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_mentions.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_message.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_messaging.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_modes.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_overview_model.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_overview_web.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_persistence.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_pidfile.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_rooms.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_skill_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_skills.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_socket_server.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_supervisor.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_template_engine.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_threads.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_wait_for_port.py +0 -0
- {agentirc_cli-4.1.2 → agentirc_cli-4.1.3}/tests/test_webhook.py +0 -0
|
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/).
|
|
6
6
|
|
|
7
|
+
## [4.1.3] - 2026-04-06
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- mesh update now discovers and restarts all running servers instead of only the one in mesh.yaml
|
|
13
|
+
|
|
7
14
|
## [4.1.2] - 2026-04-06
|
|
8
15
|
|
|
9
16
|
|
|
@@ -549,23 +549,76 @@ def _restart_mesh_services(
|
|
|
549
549
|
check=False,
|
|
550
550
|
)
|
|
551
551
|
|
|
552
|
-
print(
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
def
|
|
556
|
-
|
|
552
|
+
print()
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def _resolve_mesh_for_server(server_name: str, config_path: str):
|
|
556
|
+
"""Find or build a MeshConfig for *server_name*.
|
|
557
|
+
|
|
558
|
+
Resolution order:
|
|
559
|
+
1. mesh.yaml — use directly if its server.name matches.
|
|
560
|
+
2. agents.yaml — build via from_daemon_config(), preserving host, port,
|
|
561
|
+
and links from the old mesh.yaml. Saves the updated mesh.yaml so
|
|
562
|
+
future runs are consistent.
|
|
563
|
+
"""
|
|
564
|
+
from culture.mesh_config import (
|
|
565
|
+
from_daemon_config,
|
|
566
|
+
load_mesh_config,
|
|
567
|
+
merge_links,
|
|
568
|
+
save_mesh_config,
|
|
569
|
+
)
|
|
557
570
|
|
|
571
|
+
old_server = None
|
|
558
572
|
try:
|
|
559
|
-
|
|
573
|
+
old_mesh = load_mesh_config(config_path)
|
|
574
|
+
if old_mesh.server.name == server_name:
|
|
575
|
+
return old_mesh
|
|
576
|
+
old_server = old_mesh.server
|
|
560
577
|
except FileNotFoundError:
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
578
|
+
pass
|
|
579
|
+
|
|
580
|
+
if os.path.isfile(DEFAULT_CONFIG):
|
|
581
|
+
daemon_config = load_config(DEFAULT_CONFIG)
|
|
582
|
+
if daemon_config.server.name == server_name:
|
|
583
|
+
mesh = from_daemon_config(daemon_config)
|
|
584
|
+
if old_server is not None:
|
|
585
|
+
mesh.server.host = old_server.host
|
|
586
|
+
mesh.server.port = old_server.port
|
|
587
|
+
merge_links(mesh, old_server.links)
|
|
588
|
+
save_mesh_config(mesh, config_path)
|
|
589
|
+
return mesh
|
|
590
|
+
|
|
591
|
+
return None
|
|
564
592
|
|
|
565
|
-
|
|
593
|
+
|
|
594
|
+
def _cmd_update(args: argparse.Namespace) -> None:
|
|
595
|
+
from culture.mesh_config import load_mesh_config
|
|
596
|
+
from culture.pidfile import list_servers
|
|
566
597
|
|
|
567
598
|
if not _upgrade_culture_package(args):
|
|
568
599
|
return
|
|
569
600
|
|
|
570
601
|
culture_bin = shutil.which("culture") or "culture"
|
|
571
|
-
|
|
602
|
+
|
|
603
|
+
running = list_servers()
|
|
604
|
+
|
|
605
|
+
if running:
|
|
606
|
+
for srv in running:
|
|
607
|
+
mesh = _resolve_mesh_for_server(srv["name"], args.config)
|
|
608
|
+
if mesh is None:
|
|
609
|
+
print(
|
|
610
|
+
f" Warning: no config found for server '{srv['name']}', skipping",
|
|
611
|
+
file=sys.stderr,
|
|
612
|
+
)
|
|
613
|
+
continue
|
|
614
|
+
_restart_mesh_services(mesh, srv["name"], culture_bin, args.config, args.dry_run)
|
|
615
|
+
else:
|
|
616
|
+
try:
|
|
617
|
+
mesh = load_mesh_config(args.config)
|
|
618
|
+
except FileNotFoundError:
|
|
619
|
+
mesh = generate_mesh_from_agents(args.config)
|
|
620
|
+
if mesh is None:
|
|
621
|
+
sys.exit(1)
|
|
622
|
+
_restart_mesh_services(mesh, mesh.server.name, culture_bin, args.config, args.dry_run)
|
|
623
|
+
|
|
624
|
+
print("Update complete. All services restarted.")
|
|
@@ -108,6 +108,15 @@ def from_daemon_config(daemon_config: DaemonConfig) -> MeshConfig:
|
|
|
108
108
|
return MeshConfig(server=server, agents=agents)
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
def merge_links(target: MeshConfig, source_links: list[MeshLinkConfig]) -> None:
|
|
112
|
+
"""Copy link configs from *source_links* into *target* if not already present."""
|
|
113
|
+
existing = {link.name for link in target.server.links}
|
|
114
|
+
for link in source_links:
|
|
115
|
+
if link.name not in existing:
|
|
116
|
+
target.server.links.append(link)
|
|
117
|
+
existing.add(link.name)
|
|
118
|
+
|
|
119
|
+
|
|
111
120
|
def save_mesh_config(config: MeshConfig, path: str | Path = DEFAULT_MESH_PATH) -> None:
|
|
112
121
|
"""Serialize mesh config to YAML and write atomically."""
|
|
113
122
|
path = Path(path)
|
|
@@ -288,8 +288,11 @@ walkthrough.
|
|
|
288
288
|
|
|
289
289
|
### `culture update`
|
|
290
290
|
|
|
291
|
-
Upgrade the `culture` package and restart all
|
|
292
|
-
|
|
291
|
+
Upgrade the `culture` package and restart all running servers. The command
|
|
292
|
+
discovers running servers from PID files rather than relying solely on
|
|
293
|
+
`mesh.yaml`, so it restarts every server on the machine even if `mesh.yaml`
|
|
294
|
+
is stale or names a different server. When no servers are running, it falls
|
|
295
|
+
back to `mesh.yaml`.
|
|
293
296
|
|
|
294
297
|
```bash
|
|
295
298
|
culture update # upgrade package + restart everything
|
|
@@ -11,6 +11,7 @@ from culture.mesh_config import (
|
|
|
11
11
|
MeshServerConfig,
|
|
12
12
|
from_daemon_config,
|
|
13
13
|
load_mesh_config,
|
|
14
|
+
merge_links,
|
|
14
15
|
save_mesh_config,
|
|
15
16
|
)
|
|
16
17
|
|
|
@@ -153,3 +154,39 @@ def test_from_daemon_config_empty_agents():
|
|
|
153
154
|
assert mesh.server.name == "test"
|
|
154
155
|
assert mesh.server.port == 7000
|
|
155
156
|
assert mesh.agents == []
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_merge_links_appends_missing():
|
|
160
|
+
"""merge_links adds links not already present."""
|
|
161
|
+
target = MeshConfig(
|
|
162
|
+
server=MeshServerConfig(
|
|
163
|
+
name="spark",
|
|
164
|
+
links=[MeshLinkConfig(name="thor", host="1.2.3.4", port=6667)],
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
source = [
|
|
168
|
+
MeshLinkConfig(name="orin", host="5.6.7.8", port=6668),
|
|
169
|
+
]
|
|
170
|
+
merge_links(target, source)
|
|
171
|
+
assert len(target.server.links) == 2
|
|
172
|
+
assert target.server.links[1].name == "orin"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_merge_links_skips_duplicates():
|
|
176
|
+
"""merge_links does not duplicate links already present."""
|
|
177
|
+
target = MeshConfig(
|
|
178
|
+
server=MeshServerConfig(
|
|
179
|
+
name="spark",
|
|
180
|
+
links=[MeshLinkConfig(name="thor", host="1.2.3.4", port=6667)],
|
|
181
|
+
),
|
|
182
|
+
)
|
|
183
|
+
source = [
|
|
184
|
+
MeshLinkConfig(name="thor", host="9.9.9.9", port=9999),
|
|
185
|
+
MeshLinkConfig(name="orin", host="5.6.7.8", port=6668),
|
|
186
|
+
]
|
|
187
|
+
merge_links(target, source)
|
|
188
|
+
assert len(target.server.links) == 2
|
|
189
|
+
names = [l.name for l in target.server.links]
|
|
190
|
+
assert names == ["thor", "orin"]
|
|
191
|
+
# Original thor link is unchanged
|
|
192
|
+
assert target.server.links[0].host == "1.2.3.4"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# tests/test_setup_update_cli.py
|
|
2
|
+
"""Lightweight parser tests for setup and update subcommands."""
|
|
3
|
+
|
|
4
|
+
from unittest.mock import patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from culture.cli import _build_parser
|
|
9
|
+
from culture.mesh_config import MeshAgentConfig, MeshConfig, MeshLinkConfig, MeshServerConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_setup_parser():
|
|
13
|
+
"""setup subcommand parses --config and --uninstall."""
|
|
14
|
+
p = _build_parser()
|
|
15
|
+
args = p.parse_args(["mesh", "setup", "--uninstall"])
|
|
16
|
+
assert args.command == "mesh"
|
|
17
|
+
assert args.mesh_command == "setup"
|
|
18
|
+
assert args.uninstall is True
|
|
19
|
+
|
|
20
|
+
args = p.parse_args(["mesh", "setup", "--config", "/tmp/mesh.yaml"])
|
|
21
|
+
assert args.config == "/tmp/mesh.yaml"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_update_parser():
|
|
25
|
+
"""update subcommand parses --dry-run, --skip-upgrade, --config."""
|
|
26
|
+
p = _build_parser()
|
|
27
|
+
args = p.parse_args(["mesh", "update", "--dry-run", "--skip-upgrade"])
|
|
28
|
+
assert args.command == "mesh"
|
|
29
|
+
assert args.mesh_command == "update"
|
|
30
|
+
assert args.dry_run is True
|
|
31
|
+
assert args.skip_upgrade is True
|
|
32
|
+
|
|
33
|
+
args = p.parse_args(["mesh", "update", "--config", "/tmp/mesh.yaml"])
|
|
34
|
+
assert args.config == "/tmp/mesh.yaml"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_setup_in_dispatch():
|
|
38
|
+
"""setup command is wired into the mesh module."""
|
|
39
|
+
from culture.cli import mesh
|
|
40
|
+
|
|
41
|
+
assert hasattr(mesh, "_cmd_setup")
|
|
42
|
+
assert callable(mesh._cmd_setup)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_update_in_dispatch():
|
|
46
|
+
"""update command is wired into the mesh module."""
|
|
47
|
+
from culture.cli import mesh
|
|
48
|
+
|
|
49
|
+
assert hasattr(mesh, "_cmd_update")
|
|
50
|
+
assert callable(mesh._cmd_update)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---- _cmd_update behaviour tests ----
|
|
54
|
+
|
|
55
|
+
_MESH_MOD = "culture.cli.mesh"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.fixture
|
|
59
|
+
def update_args(tmp_path):
|
|
60
|
+
"""Minimal argparse namespace for _cmd_update."""
|
|
61
|
+
p = _build_parser()
|
|
62
|
+
config = str(tmp_path / "mesh.yaml")
|
|
63
|
+
return p.parse_args(["mesh", "update", "--skip-upgrade", "--dry-run", "--config", config])
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@patch("culture.pidfile.list_servers")
|
|
67
|
+
@patch(f"{_MESH_MOD}._resolve_mesh_for_server")
|
|
68
|
+
@patch(f"{_MESH_MOD}._restart_mesh_services")
|
|
69
|
+
@patch(f"{_MESH_MOD}._upgrade_culture_package", return_value=True)
|
|
70
|
+
def test_update_discovers_running_servers(
|
|
71
|
+
_mock_upgrade, mock_restart, mock_resolve, mock_list, update_args
|
|
72
|
+
):
|
|
73
|
+
"""_cmd_update restarts every running server, not just mesh.yaml."""
|
|
74
|
+
from culture.cli.mesh import _cmd_update
|
|
75
|
+
|
|
76
|
+
spark_mesh = MeshConfig(server=MeshServerConfig(name="spark"))
|
|
77
|
+
mock_list.return_value = [{"name": "spark", "pid": 1, "port": 6667}]
|
|
78
|
+
mock_resolve.return_value = spark_mesh
|
|
79
|
+
|
|
80
|
+
_cmd_update(update_args)
|
|
81
|
+
|
|
82
|
+
mock_resolve.assert_called_once_with("spark", update_args.config)
|
|
83
|
+
mock_restart.assert_called_once()
|
|
84
|
+
assert mock_restart.call_args[0][1] == "spark"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@patch("culture.pidfile.list_servers", return_value=[])
|
|
88
|
+
@patch("culture.mesh_config.load_mesh_config")
|
|
89
|
+
@patch(f"{_MESH_MOD}._restart_mesh_services")
|
|
90
|
+
@patch(f"{_MESH_MOD}._upgrade_culture_package", return_value=True)
|
|
91
|
+
def test_update_falls_back_to_mesh_yaml_when_no_servers(
|
|
92
|
+
_mock_upgrade, mock_restart, mock_load, _mock_list, update_args
|
|
93
|
+
):
|
|
94
|
+
"""When no servers are running, fall back to mesh.yaml."""
|
|
95
|
+
from culture.cli.mesh import _cmd_update
|
|
96
|
+
|
|
97
|
+
mesh = MeshConfig(server=MeshServerConfig(name="culture"))
|
|
98
|
+
mock_load.return_value = mesh
|
|
99
|
+
|
|
100
|
+
_cmd_update(update_args)
|
|
101
|
+
|
|
102
|
+
mock_load.assert_called_once_with(update_args.config)
|
|
103
|
+
mock_restart.assert_called_once()
|
|
104
|
+
assert mock_restart.call_args[0][1] == "culture"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@patch("culture.pidfile.list_servers")
|
|
108
|
+
@patch(f"{_MESH_MOD}._restart_mesh_services")
|
|
109
|
+
@patch(f"{_MESH_MOD}._upgrade_culture_package", return_value=True)
|
|
110
|
+
def test_update_skips_server_without_config(
|
|
111
|
+
_mock_upgrade, mock_restart, mock_list, update_args, capsys
|
|
112
|
+
):
|
|
113
|
+
"""Servers with no matching config are skipped with a warning."""
|
|
114
|
+
from culture.cli.mesh import _cmd_update
|
|
115
|
+
|
|
116
|
+
mock_list.return_value = [{"name": "unknown", "pid": 1, "port": 6667}]
|
|
117
|
+
|
|
118
|
+
with patch(f"{_MESH_MOD}._resolve_mesh_for_server", return_value=None):
|
|
119
|
+
_cmd_update(update_args)
|
|
120
|
+
|
|
121
|
+
mock_restart.assert_not_called()
|
|
122
|
+
assert "no config found" in capsys.readouterr().err
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# ---- _resolve_mesh_for_server tests ----
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_resolve_uses_mesh_yaml_when_name_matches(tmp_path):
|
|
129
|
+
"""_resolve_mesh_for_server returns mesh.yaml config when server name matches."""
|
|
130
|
+
from culture.cli.mesh import _resolve_mesh_for_server
|
|
131
|
+
|
|
132
|
+
mesh = MeshConfig(
|
|
133
|
+
server=MeshServerConfig(name="spark", links=[MeshLinkConfig(name="thor", host="1.2.3.4")]),
|
|
134
|
+
agents=[MeshAgentConfig(nick="claude", workdir="/tmp")],
|
|
135
|
+
)
|
|
136
|
+
config_path = str(tmp_path / "mesh.yaml")
|
|
137
|
+
from culture.mesh_config import save_mesh_config
|
|
138
|
+
|
|
139
|
+
save_mesh_config(mesh, config_path)
|
|
140
|
+
|
|
141
|
+
result = _resolve_mesh_for_server("spark", config_path)
|
|
142
|
+
assert result is not None
|
|
143
|
+
assert result.server.name == "spark"
|
|
144
|
+
assert len(result.server.links) == 1
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_resolve_rebuilds_from_agents_yaml_preserving_links(tmp_path):
|
|
148
|
+
"""When mesh.yaml has wrong name, rebuild from agents.yaml and keep links."""
|
|
149
|
+
from culture.cli.mesh import _resolve_mesh_for_server
|
|
150
|
+
from culture.clients.claude.config import AgentConfig, DaemonConfig, ServerConnConfig
|
|
151
|
+
from culture.mesh_config import save_mesh_config
|
|
152
|
+
|
|
153
|
+
# mesh.yaml says "culture" but running server is "spark"
|
|
154
|
+
old_mesh = MeshConfig(
|
|
155
|
+
server=MeshServerConfig(
|
|
156
|
+
name="culture",
|
|
157
|
+
host="127.0.0.1",
|
|
158
|
+
port=7000,
|
|
159
|
+
links=[MeshLinkConfig(name="thor", host="1.2.3.4")],
|
|
160
|
+
),
|
|
161
|
+
)
|
|
162
|
+
config_path = str(tmp_path / "mesh.yaml")
|
|
163
|
+
save_mesh_config(old_mesh, config_path)
|
|
164
|
+
|
|
165
|
+
# agents.yaml says "spark"
|
|
166
|
+
daemon = DaemonConfig(
|
|
167
|
+
server=ServerConnConfig(name="spark", host="localhost", port=6667),
|
|
168
|
+
agents=[AgentConfig(nick="spark-claude", agent="claude", directory="/tmp")],
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
with patch(f"{_MESH_MOD}.DEFAULT_CONFIG", str(tmp_path / "agents.yaml")):
|
|
172
|
+
from culture.clients.claude.config import save_config
|
|
173
|
+
|
|
174
|
+
save_config(str(tmp_path / "agents.yaml"), daemon)
|
|
175
|
+
result = _resolve_mesh_for_server("spark", config_path)
|
|
176
|
+
|
|
177
|
+
assert result is not None
|
|
178
|
+
assert result.server.name == "spark"
|
|
179
|
+
assert len(result.agents) == 1
|
|
180
|
+
assert result.agents[0].nick == "claude"
|
|
181
|
+
# Server settings from old mesh.yaml are preserved
|
|
182
|
+
assert result.server.host == "127.0.0.1"
|
|
183
|
+
assert result.server.port == 7000
|
|
184
|
+
assert len(result.server.links) == 1
|
|
185
|
+
assert result.server.links[0].name == "thor"
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# tests/test_setup_update_cli.py
|
|
2
|
-
"""Lightweight parser tests for setup and update subcommands."""
|
|
3
|
-
|
|
4
|
-
from culture.cli import _build_parser
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_setup_parser():
|
|
8
|
-
"""setup subcommand parses --config and --uninstall."""
|
|
9
|
-
p = _build_parser()
|
|
10
|
-
args = p.parse_args(["mesh", "setup", "--uninstall"])
|
|
11
|
-
assert args.command == "mesh"
|
|
12
|
-
assert args.mesh_command == "setup"
|
|
13
|
-
assert args.uninstall is True
|
|
14
|
-
|
|
15
|
-
args = p.parse_args(["mesh", "setup", "--config", "/tmp/mesh.yaml"])
|
|
16
|
-
assert args.config == "/tmp/mesh.yaml"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def test_update_parser():
|
|
20
|
-
"""update subcommand parses --dry-run, --skip-upgrade, --config."""
|
|
21
|
-
p = _build_parser()
|
|
22
|
-
args = p.parse_args(["mesh", "update", "--dry-run", "--skip-upgrade"])
|
|
23
|
-
assert args.command == "mesh"
|
|
24
|
-
assert args.mesh_command == "update"
|
|
25
|
-
assert args.dry_run is True
|
|
26
|
-
assert args.skip_upgrade is True
|
|
27
|
-
|
|
28
|
-
args = p.parse_args(["mesh", "update", "--config", "/tmp/mesh.yaml"])
|
|
29
|
-
assert args.config == "/tmp/mesh.yaml"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def test_setup_in_dispatch():
|
|
33
|
-
"""setup command is wired into the mesh module."""
|
|
34
|
-
from culture.cli import mesh
|
|
35
|
-
|
|
36
|
-
assert hasattr(mesh, "_cmd_setup")
|
|
37
|
-
assert callable(mesh._cmd_setup)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def test_update_in_dispatch():
|
|
41
|
-
"""update command is wired into the mesh module."""
|
|
42
|
-
from culture.cli import mesh
|
|
43
|
-
|
|
44
|
-
assert hasattr(mesh, "_cmd_update")
|
|
45
|
-
assert callable(mesh._cmd_update)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|