agentirc-cli 1.0.3__tar.gz → 1.0.4__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-1.0.3 → agentirc_cli-1.0.4}/CHANGELOG.md +7 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/PKG-INFO +1 -1
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/cli.py +199 -141
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/daemon.py +78 -95
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/daemon.py +82 -101
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/daemon.py +78 -95
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/daemon.py +78 -95
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/ircd.py +62 -35
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/server_link.py +129 -87
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/skills/threads.py +161 -118
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/daemon.py +108 -101
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/pyproject.toml +1 -1
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/sonar-project.properties +4 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_daemon_ipc.py +6 -6
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/uv.lock +1 -1
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.flake8 +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.gitignore +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.pr_agent.toml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/.pylintrc +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/CLAUDE.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/CNAME +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/Gemfile +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/Gemfile.lock +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/LICENSE +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/README.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/SECURITY.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/_config.yml +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/__main__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/bots/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/bots/bot.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/bots/config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/agent_runner.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/irc_transport.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/skill/irc_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/skill/irc_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/credentials.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/learn_prompt.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/mesh_config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/observer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/overview/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/overview/collector.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/overview/model.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/overview/web/style.css +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/persistence.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/pidfile.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/commands.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/message.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/protocol/replies.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/__main__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/channel.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/remote_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/room_store.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/skill.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/skills/history.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/skills/rooms.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/server/thread_store.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/SECURITY.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/agent-client.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/agent-harness-spec.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/bots.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/ci.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/cli.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/codex-backend.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/copilot-backend.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/docs-site.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/getting-started.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/grow-your-agent.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/harness-conformance.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/layer1-core-irc.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/layer2-attention.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/layer3-skills.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/layer4-federation.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/layer5-agent-harness.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/ops-tooling.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/overview.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/publishing.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/rooms.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/server-architecture.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/threads.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases/10-grow-your-agent.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/docs/use-cases-index.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/index.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/__init__.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/conftest.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_bot.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_bot_config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_channel.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_connection.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_daemon.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_discovery.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_federation.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_history.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_http_listener.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_ipc.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_mentions.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_message.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_messaging.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_modes.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_overview_model.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_overview_web.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_persistence.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_rooms.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_skill_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_skills.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_socket_server.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_supervisor.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_template_engine.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_threads.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-1.0.3 → agentirc_cli-1.0.4}/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
|
+
## [1.0.4] - 2026-04-05
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Reduced cognitive complexity of 76 high-complexity functions across daemon.py (5 files), server_link.py, threads.py, cli.py, and ircd.py by replacing if/elif chains with dispatch tables and extracting named logic units
|
|
13
|
+
|
|
7
14
|
## [1.0.3] - 2026-04-05
|
|
8
15
|
|
|
9
16
|
|
|
@@ -622,9 +622,8 @@ def _cmd_init(args: argparse.Namespace) -> None:
|
|
|
622
622
|
# -----------------------------------------------------------------------
|
|
623
623
|
|
|
624
624
|
|
|
625
|
-
def
|
|
626
|
-
|
|
627
|
-
|
|
625
|
+
def _resolve_agents_to_start(config, args) -> list:
|
|
626
|
+
"""Return the list of agents to start, or exit with an error message."""
|
|
628
627
|
if args.all:
|
|
629
628
|
agents = config.agents
|
|
630
629
|
elif args.nick:
|
|
@@ -653,11 +652,13 @@ def _cmd_start(args: argparse.Namespace) -> None:
|
|
|
653
652
|
print("No agents configured", file=sys.stderr)
|
|
654
653
|
sys.exit(1)
|
|
655
654
|
|
|
656
|
-
|
|
655
|
+
return agents
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def _probe_server_connection(host: str, port: int, server_name: str) -> None:
|
|
659
|
+
"""Check that the IRC server is reachable; exit with an error message if not."""
|
|
657
660
|
import socket as _socket
|
|
658
661
|
|
|
659
|
-
server_name = config.server.name
|
|
660
|
-
host, port = config.server.host, config.server.port
|
|
661
662
|
try:
|
|
662
663
|
with _socket.create_connection((host, port), timeout=2):
|
|
663
664
|
pass
|
|
@@ -673,6 +674,16 @@ def _cmd_start(args: argparse.Namespace) -> None:
|
|
|
673
674
|
)
|
|
674
675
|
sys.exit(1)
|
|
675
676
|
|
|
677
|
+
|
|
678
|
+
def _cmd_start(args: argparse.Namespace) -> None:
|
|
679
|
+
config = load_config(args.config)
|
|
680
|
+
|
|
681
|
+
agents = _resolve_agents_to_start(config, args)
|
|
682
|
+
|
|
683
|
+
# Best-effort check that the IRC server is reachable before starting agent(s)
|
|
684
|
+
server_name = config.server.name
|
|
685
|
+
_probe_server_connection(config.server.host, config.server.port, server_name)
|
|
686
|
+
|
|
676
687
|
foreground = getattr(args, "foreground", False)
|
|
677
688
|
|
|
678
689
|
if foreground:
|
|
@@ -977,53 +988,36 @@ def _agent_process_status(agent) -> tuple[str, int | None]:
|
|
|
977
988
|
return "stopped", None
|
|
978
989
|
|
|
979
990
|
|
|
980
|
-
def
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
991
|
+
def _print_agent_detail(agent, config_path: str, args: argparse.Namespace) -> None:
|
|
992
|
+
"""Print detailed status for a single agent, including live IPC activity query."""
|
|
993
|
+
status, pid = _agent_process_status(agent)
|
|
994
|
+
print(agent.nick)
|
|
995
|
+
print(f" Status: {status}")
|
|
996
|
+
print(f" PID: {pid or '-'}")
|
|
986
997
|
|
|
987
|
-
#
|
|
988
|
-
if
|
|
989
|
-
agent =
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
|
|
996
|
-
sys.exit(1)
|
|
997
|
-
|
|
998
|
-
status, pid = _agent_process_status(agent)
|
|
999
|
-
print(agent.nick)
|
|
1000
|
-
print(f" Status: {status}")
|
|
1001
|
-
print(f" PID: {pid or '-'}")
|
|
1002
|
-
|
|
1003
|
-
# Query IPC for activity if running — ask the agent directly
|
|
1004
|
-
if status == "running":
|
|
1005
|
-
resp = asyncio.run(_ipc_request(_agent_socket_path(agent.nick), "status", query=True))
|
|
1006
|
-
if resp and resp.get("ok"):
|
|
1007
|
-
data = resp.get("data", {})
|
|
1008
|
-
print(f" Activity: {data.get('description', 'nothing')}")
|
|
1009
|
-
print(f" Turns: {data.get('turn_count', 0)}")
|
|
1010
|
-
print(f" Paused: {'yes' if data.get('paused') else 'no'}")
|
|
1011
|
-
else:
|
|
1012
|
-
print(" Activity: unknown (daemon may need restart)")
|
|
998
|
+
# Query IPC for activity if running — ask the agent directly
|
|
999
|
+
if status == "running":
|
|
1000
|
+
resp = asyncio.run(_ipc_request(_agent_socket_path(agent.nick), "status", query=True))
|
|
1001
|
+
if resp and resp.get("ok"):
|
|
1002
|
+
data = resp.get("data", {})
|
|
1003
|
+
print(f" Activity: {data.get('description', 'nothing')}")
|
|
1004
|
+
print(f" Turns: {data.get('turn_count', 0)}")
|
|
1005
|
+
print(f" Paused: {'yes' if data.get('paused') else 'no'}")
|
|
1013
1006
|
else:
|
|
1014
|
-
print(" Activity:
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1007
|
+
print(" Activity: unknown (daemon may need restart)")
|
|
1008
|
+
else:
|
|
1009
|
+
print(" Activity: -")
|
|
1010
|
+
|
|
1011
|
+
channels = agent.channels if isinstance(agent.channels, list) else []
|
|
1012
|
+
print(f" Directory: {agent.directory}")
|
|
1013
|
+
print(f" Backend: {agent.agent}")
|
|
1014
|
+
print(f" Channels: {', '.join(channels)}")
|
|
1015
|
+
print(f" Model: {agent.model}")
|
|
1016
|
+
print(f" Config: {config_path}")
|
|
1023
1017
|
|
|
1024
|
-
# All agents view
|
|
1025
|
-
show_activity = args.full
|
|
1026
1018
|
|
|
1019
|
+
def _print_agents_overview(agents: list, show_activity: bool) -> None:
|
|
1020
|
+
"""Print a table of all agents with status, PID, and optionally activity."""
|
|
1027
1021
|
if show_activity:
|
|
1028
1022
|
print(f"{'NICK':<30} {'STATUS':<12} {'PID':<10} {'ACTIVITY'}")
|
|
1029
1023
|
print("-" * 72)
|
|
@@ -1031,7 +1025,7 @@ def _cmd_status(args: argparse.Namespace) -> None:
|
|
|
1031
1025
|
print(f"{'NICK':<30} {'STATUS':<12} {'PID':<10}")
|
|
1032
1026
|
print("-" * 52)
|
|
1033
1027
|
|
|
1034
|
-
for agent in
|
|
1028
|
+
for agent in agents:
|
|
1035
1029
|
status, pid = _agent_process_status(agent)
|
|
1036
1030
|
activity = "-"
|
|
1037
1031
|
|
|
@@ -1046,7 +1040,9 @@ def _cmd_status(args: argparse.Namespace) -> None:
|
|
|
1046
1040
|
else:
|
|
1047
1041
|
print(f"{agent.nick:<30} {status:<12} {str(pid or '-'):<10}")
|
|
1048
1042
|
|
|
1049
|
-
|
|
1043
|
+
|
|
1044
|
+
def _print_bot_listing() -> None:
|
|
1045
|
+
"""Print a table of configured bots (if any exist)."""
|
|
1050
1046
|
from culture.bots.config import BOTS_DIR, load_bot_config
|
|
1051
1047
|
|
|
1052
1048
|
if BOTS_DIR.is_dir():
|
|
@@ -1067,6 +1063,34 @@ def _cmd_status(args: argparse.Namespace) -> None:
|
|
|
1067
1063
|
print(f"{bc.name:<30} {bc.trigger_type:<12} {channels}")
|
|
1068
1064
|
|
|
1069
1065
|
|
|
1066
|
+
def _cmd_status(args: argparse.Namespace) -> None:
|
|
1067
|
+
config = load_config_or_default(args.config)
|
|
1068
|
+
|
|
1069
|
+
if not config.agents:
|
|
1070
|
+
print("No agents configured")
|
|
1071
|
+
return
|
|
1072
|
+
|
|
1073
|
+
# Single agent detailed view
|
|
1074
|
+
if args.nick:
|
|
1075
|
+
agent = None
|
|
1076
|
+
for a in config.agents:
|
|
1077
|
+
if a.nick == args.nick:
|
|
1078
|
+
agent = a
|
|
1079
|
+
break
|
|
1080
|
+
if not agent:
|
|
1081
|
+
print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
|
|
1082
|
+
sys.exit(1)
|
|
1083
|
+
|
|
1084
|
+
_print_agent_detail(agent, args.config, args)
|
|
1085
|
+
return
|
|
1086
|
+
|
|
1087
|
+
# All agents view
|
|
1088
|
+
_print_agents_overview(config.agents, args.full)
|
|
1089
|
+
|
|
1090
|
+
# Show bots
|
|
1091
|
+
_print_bot_listing()
|
|
1092
|
+
|
|
1093
|
+
|
|
1070
1094
|
# -----------------------------------------------------------------------
|
|
1071
1095
|
# Observation subcommands
|
|
1072
1096
|
# -----------------------------------------------------------------------
|
|
@@ -1454,39 +1478,10 @@ def _build_server_start_cmd(mesh, culture_bin: str, mesh_config_path: str) -> li
|
|
|
1454
1478
|
# -----------------------------------------------------------------------
|
|
1455
1479
|
|
|
1456
1480
|
|
|
1457
|
-
def
|
|
1481
|
+
def _store_mesh_credentials(mesh) -> None:
|
|
1482
|
+
"""Prompt for link passwords and store them in the OS keyring (never in files)."""
|
|
1458
1483
|
import getpass
|
|
1459
1484
|
|
|
1460
|
-
from culture.mesh_config import load_mesh_config
|
|
1461
|
-
from culture.persistence import install_service, list_services, uninstall_service
|
|
1462
|
-
|
|
1463
|
-
try:
|
|
1464
|
-
mesh = load_mesh_config(args.config)
|
|
1465
|
-
except FileNotFoundError:
|
|
1466
|
-
print(f"Mesh config not found: {args.config}", file=sys.stderr)
|
|
1467
|
-
print("Create it manually or ask your AI agent to generate it.", file=sys.stderr)
|
|
1468
|
-
sys.exit(1)
|
|
1469
|
-
|
|
1470
|
-
server_name = mesh.server.name
|
|
1471
|
-
|
|
1472
|
-
if args.uninstall:
|
|
1473
|
-
print("Uninstalling culture services...")
|
|
1474
|
-
# Only remove services for this node (not other mesh nodes)
|
|
1475
|
-
expected = {f"culture-server-{server_name}"}
|
|
1476
|
-
for agent in mesh.agents:
|
|
1477
|
-
expected.add(f"culture-agent-{server_name}-{agent.nick}")
|
|
1478
|
-
for svc in list_services():
|
|
1479
|
-
if svc in expected:
|
|
1480
|
-
print(f" Removing {svc}")
|
|
1481
|
-
uninstall_service(svc)
|
|
1482
|
-
_server_stop_by_name(server_name)
|
|
1483
|
-
for agent in mesh.agents:
|
|
1484
|
-
full_nick = f"{server_name}-{agent.nick}"
|
|
1485
|
-
_stop_agent(full_nick)
|
|
1486
|
-
print("Done.")
|
|
1487
|
-
return
|
|
1488
|
-
|
|
1489
|
-
# Prompt for link passwords and store in OS keyring (never in files)
|
|
1490
1485
|
from culture.credentials import lookup_credential, store_credential
|
|
1491
1486
|
|
|
1492
1487
|
for link in mesh.server.links:
|
|
@@ -1505,7 +1500,9 @@ def _cmd_setup(args: argparse.Namespace) -> None:
|
|
|
1505
1500
|
file=sys.stderr,
|
|
1506
1501
|
)
|
|
1507
1502
|
|
|
1508
|
-
|
|
1503
|
+
|
|
1504
|
+
def _generate_agent_configs(mesh, server_name: str) -> None:
|
|
1505
|
+
"""Generate agents.yaml for each agent workdir defined in the mesh config."""
|
|
1509
1506
|
from culture.clients.claude.config import AgentConfig as BaseAgentConfig
|
|
1510
1507
|
from culture.clients.claude.config import (
|
|
1511
1508
|
DaemonConfig,
|
|
@@ -1542,9 +1539,12 @@ def _cmd_setup(args: argparse.Namespace) -> None:
|
|
|
1542
1539
|
save_config(config_path, daemon_config)
|
|
1543
1540
|
print(f" Wrote {config_path}")
|
|
1544
1541
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1542
|
+
|
|
1543
|
+
def _install_mesh_services(mesh, server_name: str, culture_bin: str, config_path: str) -> None:
|
|
1544
|
+
"""Install auto-start service entries for the server and all agents."""
|
|
1545
|
+
from culture.persistence import install_service
|
|
1546
|
+
|
|
1547
|
+
server_cmd = _build_server_start_cmd(mesh, culture_bin, config_path)
|
|
1548
1548
|
svc_name = f"culture-server-{server_name}"
|
|
1549
1549
|
path = install_service(svc_name, server_cmd, f"culture server {server_name}")
|
|
1550
1550
|
print(f" Installed {svc_name} → {path}")
|
|
@@ -1552,12 +1552,50 @@ def _cmd_setup(args: argparse.Namespace) -> None:
|
|
|
1552
1552
|
for agent in mesh.agents:
|
|
1553
1553
|
full_nick = f"{server_name}-{agent.nick}"
|
|
1554
1554
|
workdir = os.path.expanduser(agent.workdir)
|
|
1555
|
-
|
|
1556
|
-
agent_cmd = [culture_bin, "start", full_nick, "--foreground", "--config",
|
|
1555
|
+
agent_config_path = os.path.join(workdir, ".culture", "agents.yaml")
|
|
1556
|
+
agent_cmd = [culture_bin, "start", full_nick, "--foreground", "--config", agent_config_path]
|
|
1557
1557
|
agent_svc = f"culture-agent-{full_nick}"
|
|
1558
1558
|
path = install_service(agent_svc, agent_cmd, f"culture agent {full_nick}")
|
|
1559
1559
|
print(f" Installed {agent_svc} → {path}")
|
|
1560
1560
|
|
|
1561
|
+
|
|
1562
|
+
def _cmd_setup(args: argparse.Namespace) -> None:
|
|
1563
|
+
from culture.mesh_config import load_mesh_config
|
|
1564
|
+
from culture.persistence import list_services, uninstall_service
|
|
1565
|
+
|
|
1566
|
+
try:
|
|
1567
|
+
mesh = load_mesh_config(args.config)
|
|
1568
|
+
except FileNotFoundError:
|
|
1569
|
+
print(f"Mesh config not found: {args.config}", file=sys.stderr)
|
|
1570
|
+
print("Create it manually or ask your AI agent to generate it.", file=sys.stderr)
|
|
1571
|
+
sys.exit(1)
|
|
1572
|
+
|
|
1573
|
+
server_name = mesh.server.name
|
|
1574
|
+
|
|
1575
|
+
if args.uninstall:
|
|
1576
|
+
print("Uninstalling culture services...")
|
|
1577
|
+
# Only remove services for this node (not other mesh nodes)
|
|
1578
|
+
expected = {f"culture-server-{server_name}"}
|
|
1579
|
+
for agent in mesh.agents:
|
|
1580
|
+
expected.add(f"culture-agent-{server_name}-{agent.nick}")
|
|
1581
|
+
for svc in list_services():
|
|
1582
|
+
if svc in expected:
|
|
1583
|
+
print(f" Removing {svc}")
|
|
1584
|
+
uninstall_service(svc)
|
|
1585
|
+
_server_stop_by_name(server_name)
|
|
1586
|
+
for agent in mesh.agents:
|
|
1587
|
+
full_nick = f"{server_name}-{agent.nick}"
|
|
1588
|
+
_stop_agent(full_nick)
|
|
1589
|
+
print("Done.")
|
|
1590
|
+
return
|
|
1591
|
+
|
|
1592
|
+
_store_mesh_credentials(mesh)
|
|
1593
|
+
|
|
1594
|
+
_generate_agent_configs(mesh, server_name)
|
|
1595
|
+
|
|
1596
|
+
culture_bin = shutil.which("culture") or "culture"
|
|
1597
|
+
_install_mesh_services(mesh, server_name, culture_bin, args.config)
|
|
1598
|
+
|
|
1561
1599
|
print(f"\nSetup complete for mesh node '{server_name}'.")
|
|
1562
1600
|
print("Services installed. Start with your service manager or reboot.")
|
|
1563
1601
|
|
|
@@ -1597,65 +1635,67 @@ def _server_stop_by_name(name: str) -> None:
|
|
|
1597
1635
|
# -----------------------------------------------------------------------
|
|
1598
1636
|
|
|
1599
1637
|
|
|
1600
|
-
def
|
|
1601
|
-
|
|
1638
|
+
def _upgrade_culture_package(args: argparse.Namespace) -> bool:
|
|
1639
|
+
"""Upgrade the culture-cli package via uv or pip, then re-exec with --skip-upgrade.
|
|
1602
1640
|
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
server_name = mesh.server.name
|
|
1610
|
-
|
|
1611
|
-
if not args.skip_upgrade:
|
|
1612
|
-
if args.dry_run:
|
|
1613
|
-
print("[dry-run] Would run: uv tool upgrade culture-cli")
|
|
1614
|
-
print("[dry-run] Would re-exec with --skip-upgrade")
|
|
1615
|
-
return
|
|
1641
|
+
Returns True if the caller should proceed with the restart phase
|
|
1642
|
+
(``--skip-upgrade`` was set). Returns False for dry-run (caller should stop).
|
|
1643
|
+
On success, re-execs the process and never returns.
|
|
1644
|
+
"""
|
|
1645
|
+
if args.skip_upgrade:
|
|
1646
|
+
return True
|
|
1616
1647
|
|
|
1617
|
-
|
|
1618
|
-
uv
|
|
1619
|
-
|
|
1620
|
-
|
|
1648
|
+
if args.dry_run:
|
|
1649
|
+
print("[dry-run] Would run: uv tool upgrade culture-cli")
|
|
1650
|
+
print("[dry-run] Would re-exec with --skip-upgrade")
|
|
1651
|
+
return False
|
|
1652
|
+
|
|
1653
|
+
# Upgrade the package
|
|
1654
|
+
uv = shutil.which("uv")
|
|
1655
|
+
if uv:
|
|
1656
|
+
print("Upgrading via uv...")
|
|
1657
|
+
result = subprocess.run(
|
|
1658
|
+
[uv, "tool", "upgrade", "culture-cli"],
|
|
1659
|
+
capture_output=True,
|
|
1660
|
+
text=True,
|
|
1661
|
+
)
|
|
1662
|
+
print(result.stdout.strip() if result.stdout else "")
|
|
1663
|
+
if result.returncode != 0:
|
|
1664
|
+
print(f"uv upgrade failed: {result.stderr}", file=sys.stderr)
|
|
1665
|
+
sys.exit(1)
|
|
1666
|
+
else:
|
|
1667
|
+
pip = shutil.which("pip") or shutil.which("pip3")
|
|
1668
|
+
if pip:
|
|
1669
|
+
print("Upgrading via pip...")
|
|
1621
1670
|
result = subprocess.run(
|
|
1622
|
-
[
|
|
1671
|
+
[pip, "install", "--upgrade", "culture-cli"],
|
|
1623
1672
|
capture_output=True,
|
|
1624
1673
|
text=True,
|
|
1625
1674
|
)
|
|
1626
|
-
print(result.stdout.strip() if result.stdout else "")
|
|
1627
1675
|
if result.returncode != 0:
|
|
1628
|
-
print(f"
|
|
1676
|
+
print(f"pip upgrade failed: {result.stderr}", file=sys.stderr)
|
|
1629
1677
|
sys.exit(1)
|
|
1630
1678
|
else:
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
print("Upgrading via pip...")
|
|
1634
|
-
result = subprocess.run(
|
|
1635
|
-
[pip, "install", "--upgrade", "culture-cli"],
|
|
1636
|
-
capture_output=True,
|
|
1637
|
-
text=True,
|
|
1638
|
-
)
|
|
1639
|
-
if result.returncode != 0:
|
|
1640
|
-
print(f"pip upgrade failed: {result.stderr}", file=sys.stderr)
|
|
1641
|
-
sys.exit(1)
|
|
1642
|
-
else:
|
|
1643
|
-
print("Neither uv nor pip found", file=sys.stderr)
|
|
1644
|
-
sys.exit(1)
|
|
1679
|
+
print("Neither uv nor pip found", file=sys.stderr)
|
|
1680
|
+
sys.exit(1)
|
|
1645
1681
|
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1682
|
+
# Re-exec with new binary so restart uses new code
|
|
1683
|
+
culture_bin = shutil.which("culture") or "culture"
|
|
1684
|
+
reexec_args = [culture_bin, "update", "--skip-upgrade", "--config", args.config]
|
|
1685
|
+
print("Re-executing with updated code...")
|
|
1686
|
+
if sys.platform == "win32":
|
|
1687
|
+
sys.exit(subprocess.run(reexec_args).returncode)
|
|
1688
|
+
else:
|
|
1689
|
+
os.execvp(culture_bin, reexec_args)
|
|
1654
1690
|
|
|
1655
|
-
|
|
1691
|
+
|
|
1692
|
+
def _restart_mesh_services(
|
|
1693
|
+
mesh, server_name: str, culture_bin: str, config_path: str, dry_run: bool
|
|
1694
|
+
) -> None:
|
|
1695
|
+
"""Stop agents and server, regenerate service entries, then restart everything."""
|
|
1656
1696
|
print(f"Restarting mesh node '{server_name}'...")
|
|
1657
1697
|
|
|
1658
|
-
if
|
|
1698
|
+
if dry_run:
|
|
1659
1699
|
for agent in mesh.agents:
|
|
1660
1700
|
print(f"[dry-run] Would stop agent {server_name}-{agent.nick}")
|
|
1661
1701
|
print(f"[dry-run] Would stop server {server_name}")
|
|
@@ -1678,15 +1718,14 @@ def _cmd_update(args: argparse.Namespace) -> None:
|
|
|
1678
1718
|
# Regenerate auto-start entries
|
|
1679
1719
|
from culture.persistence import install_service
|
|
1680
1720
|
|
|
1681
|
-
|
|
1682
|
-
server_cmd = _build_server_start_cmd(mesh, culture_bin, args.config)
|
|
1721
|
+
server_cmd = _build_server_start_cmd(mesh, culture_bin, config_path)
|
|
1683
1722
|
install_service(f"culture-server-{server_name}", server_cmd, f"culture server {server_name}")
|
|
1684
1723
|
|
|
1685
1724
|
for agent in mesh.agents:
|
|
1686
1725
|
full_nick = f"{server_name}-{agent.nick}"
|
|
1687
1726
|
workdir = os.path.expanduser(agent.workdir)
|
|
1688
|
-
|
|
1689
|
-
agent_cmd = [culture_bin, "start", full_nick, "--foreground", "--config",
|
|
1727
|
+
agent_config_path = os.path.join(workdir, ".culture", "agents.yaml")
|
|
1728
|
+
agent_cmd = [culture_bin, "start", full_nick, "--foreground", "--config", agent_config_path]
|
|
1690
1729
|
install_service(f"culture-agent-{full_nick}", agent_cmd, f"culture agent {full_nick}")
|
|
1691
1730
|
|
|
1692
1731
|
# Restart services via platform service manager
|
|
@@ -1715,7 +1754,7 @@ def _cmd_update(args: argparse.Namespace) -> None:
|
|
|
1715
1754
|
"--port",
|
|
1716
1755
|
str(mesh.server.port),
|
|
1717
1756
|
"--mesh-config",
|
|
1718
|
-
|
|
1757
|
+
config_path,
|
|
1719
1758
|
],
|
|
1720
1759
|
check=False,
|
|
1721
1760
|
)
|
|
@@ -1737,15 +1776,34 @@ def _cmd_update(args: argparse.Namespace) -> None:
|
|
|
1737
1776
|
if not restart_service(agent_svc):
|
|
1738
1777
|
# Fallback: start via CLI
|
|
1739
1778
|
workdir = os.path.expanduser(agent.workdir)
|
|
1740
|
-
|
|
1779
|
+
agent_config_path = os.path.join(workdir, ".culture", "agents.yaml")
|
|
1741
1780
|
subprocess.run(
|
|
1742
|
-
[culture_bin, "start", full_nick, "--config",
|
|
1781
|
+
[culture_bin, "start", full_nick, "--config", agent_config_path],
|
|
1743
1782
|
check=False,
|
|
1744
1783
|
)
|
|
1745
1784
|
|
|
1746
1785
|
print("\nUpdate complete. All services restarted.")
|
|
1747
1786
|
|
|
1748
1787
|
|
|
1788
|
+
def _cmd_update(args: argparse.Namespace) -> None:
|
|
1789
|
+
from culture.mesh_config import load_mesh_config
|
|
1790
|
+
|
|
1791
|
+
try:
|
|
1792
|
+
mesh = load_mesh_config(args.config)
|
|
1793
|
+
except FileNotFoundError:
|
|
1794
|
+
print(f"Mesh config not found: {args.config}", file=sys.stderr)
|
|
1795
|
+
sys.exit(1)
|
|
1796
|
+
|
|
1797
|
+
server_name = mesh.server.name
|
|
1798
|
+
|
|
1799
|
+
if not _upgrade_culture_package(args):
|
|
1800
|
+
return
|
|
1801
|
+
|
|
1802
|
+
# --skip-upgrade path: restart everything
|
|
1803
|
+
culture_bin = shutil.which("culture") or "culture"
|
|
1804
|
+
_restart_mesh_services(mesh, server_name, culture_bin, args.config, args.dry_run)
|
|
1805
|
+
|
|
1806
|
+
|
|
1749
1807
|
# -----------------------------------------------------------------------
|
|
1750
1808
|
# Bot subcommands
|
|
1751
1809
|
# -----------------------------------------------------------------------
|