agentirc-cli 5.0.1__tar.gz → 5.0.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-5.0.1 → agentirc_cli-5.0.3}/.claude/skills/pr-review/SKILL.md +1 -2
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/CHANGELOG.md +28 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/CLAUDE.md +1 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/PKG-INFO +1 -1
- agentirc_cli-5.0.3/culture/cli/channel.py +336 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/mesh.py +61 -11
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/skill/SKILL.md +19 -19
- {agentirc_cli-5.0.1/plugins/claude-code/skills/irc → agentirc_cli-5.0.3/culture/clients/claude/skill}/SKILL.md +20 -20
- {agentirc_cli-5.0.1/plugins/codex/skills/culture-irc → agentirc_cli-5.0.3/culture/clients/codex/skill}/SKILL.md +19 -19
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/skill/SKILL.md +19 -19
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/credentials.py +11 -6
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/learn_prompt.py +13 -13
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/agent-harness-spec.md +2 -5
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/getting-started.md +7 -7
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/cli.md +18 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/ops-tooling.md +15 -0
- agentirc_cli-5.0.3/packages/agent-harness/skill/SKILL.md +57 -0
- {agentirc_cli-5.0.1/culture/clients/claude/skill → agentirc_cli-5.0.3/plugins/claude-code/skills/irc}/SKILL.md +20 -20
- {agentirc_cli-5.0.1/culture/clients/codex/skill → agentirc_cli-5.0.3/plugins/codex/skills/culture-irc}/SKILL.md +19 -19
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/pyproject.toml +1 -1
- agentirc_cli-5.0.3/tests/test_channel_cli.py +224 -0
- agentirc_cli-5.0.3/tests/test_credentials.py +24 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_learn_prompt.py +7 -6
- agentirc_cli-5.0.3/tests/test_mesh_readiness.py +93 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/uv.lock +1 -1
- agentirc_cli-5.0.1/culture/cli/channel.py +0 -136
- agentirc_cli-5.0.1/packages/agent-harness/skill/SKILL.md +0 -57
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.flake8 +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.gitignore +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.pr_agent.toml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/.pylintrc +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/CNAME +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/Gemfile +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/Gemfile.lock +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/LICENSE +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/README.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/SECURITY.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/_config.yml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/_includes/head_custom.html +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/assets/images/apple-touch-icon.png +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/assets/images/favicon-16x16.png +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/assets/images/favicon-32x32.png +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/assets/images/favicon.ico +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/__main__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/aio.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/bots/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/bots/bot.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/bots/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/agent.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/bot.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/server.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/shared/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/shared/constants.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/shared/display.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/shared/formatting.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/shared/ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/shared/mesh.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/shared/process.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/cli/skills.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/agent_runner.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/culture.yaml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/irc_transport.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/skill/irc_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/culture.yaml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/culture.yaml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/culture.yaml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/skill/irc_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/app.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/commands.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/formatting.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/mesh_config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/observer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/overview/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/overview/collector.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/overview/model.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/overview/web/style.css +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/persistence.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/pidfile.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/commands.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/message.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/protocol/replies.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/__main__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/channel.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/history_store.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/ircd.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/remote_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/room_store.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/server_link.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/skill.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/skills/history.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/skills/icon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/skills/rooms.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/skills/threads.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/server/thread_store.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/agent-lifecycle.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/agents/decentralized-config.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/agent-client.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/harness-conformance.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/index.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/layer1-core-irc.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/layer2-attention.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/layer3-skills.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/layer4-federation.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/layer5-agent-harness.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/server-architecture.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/architecture/threads.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/channel-polling.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/acp/system-prompt.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/culture-cli.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/index.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/SECURITY.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/bots.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/ci.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/docs-site.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/index.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/overview.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/operations/publishing.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/persistent-history.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/reflective-development.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/rooms.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/server-rename.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/plans/2026-04-09-decentralized-agent-config.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-07-reflective-development-reframe-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-08-reflective-development-deepening-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/superpowers/specs/2026-04-09-decentralized-agent-config-design.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/use-cases-index.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/docs/what-is-culture.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/favicon.ico +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/culture.yaml +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/sonar-project.properties +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/__init__.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/conftest.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_archive.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_bot.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_bot_config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_channel.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_connection.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_console_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_console_commands.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_console_connection.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_console_icons.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_console_integration.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_culture_config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_daemon.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_discovery.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_display.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_federation.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_history.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_http_listener.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_ipc.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_mention_warning.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_mentions.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_message.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_messaging.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_migrate_cli.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_modes.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_overview_model.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_overview_web.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_persistence.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_pidfile.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_register_cli.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_rooms.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_skill_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_skill_docs.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_skills.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_socket_server.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_supervisor.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_template_engine.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_threads.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_wait_for_port.py +0 -0
- {agentirc_cli-5.0.1 → agentirc_cli-5.0.3}/tests/test_webhook.py +0 -0
|
@@ -179,8 +179,7 @@ Report completion back to the IRC channel:
|
|
|
179
179
|
|
|
180
180
|
```bash
|
|
181
181
|
# Using the IRC skill
|
|
182
|
-
CULTURE_NICK
|
|
183
|
-
send "#general" "PR #<N> — all review threads addressed and resolved. Ready for merge."
|
|
182
|
+
CULTURE_NICK="<agent-nick>" culture channel message "#general" "PR #<N> — all review threads addressed and resolved. Ready for merge."
|
|
184
183
|
```
|
|
185
184
|
|
|
186
185
|
## Script reference
|
|
@@ -4,6 +4,34 @@ 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
|
+
## [5.0.3] - 2026-04-10
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- New channel subcommands: join, part, ask, topic, compact, clear
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Channel CLI routes through agent daemon IPC when CULTURE_NICK is set
|
|
18
|
+
- All SKILL.md files and learn prompt use culture channel CLI instead of python3 -m
|
|
19
|
+
- Mesh update readiness probe verifies PID-based server identity
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- culture channel message sends as agent nick instead of temporary peek nick (#203)
|
|
25
|
+
- IRC skill references culture channel CLI instead of broken python3 -m path (#202)
|
|
26
|
+
|
|
27
|
+
## [5.0.2] - 2026-04-09
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Handle missing credential tool (secret-tool/security/powershell) gracefully instead of crashing the server
|
|
33
|
+
- Report restart failures in mesh update instead of claiming success
|
|
34
|
+
|
|
7
35
|
## [5.0.1] - 2026-04-09
|
|
8
36
|
|
|
9
37
|
|
|
@@ -59,6 +59,7 @@ When implementing features, write a corresponding markdown doc in `docs/` descri
|
|
|
59
59
|
|
|
60
60
|
## Testing
|
|
61
61
|
|
|
62
|
+
- Use `/run-tests` to run the test suite (parallel + verbose by default)
|
|
62
63
|
- `pytest` + `pytest-asyncio`, always run with `-n auto` for parallel execution
|
|
63
64
|
- No mocks for the server — tests spin up real server instances on random ports with real TCP connections
|
|
64
65
|
- Validate each layer with real IRC clients (weechat/irssi)
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
"""Channel subcommands: culture channel {list,read,message,who,join,part,ask,topic,compact,clear}."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from .shared.constants import _CONFIG_HELP, DEFAULT_CONFIG
|
|
12
|
+
from .shared.ipc import agent_socket_path, get_observer, ipc_request
|
|
13
|
+
|
|
14
|
+
NAME = "channel"
|
|
15
|
+
|
|
16
|
+
_ALL_CMDS = "list|read|message|who|join|part|ask|topic|compact|clear"
|
|
17
|
+
_CHANNEL_HELP = "Channel (e.g. #general)"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _valid_nick(nick: str) -> bool:
|
|
21
|
+
"""Check nick matches the required <server>-<agent> format."""
|
|
22
|
+
parts = nick.split("-", 1)
|
|
23
|
+
return len(parts) == 2 and all(parts)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _try_ipc(msg_type: str, **kwargs) -> dict | None:
|
|
27
|
+
"""Try to route a command through the agent daemon's IPC socket.
|
|
28
|
+
|
|
29
|
+
Returns the response dict if CULTURE_NICK is set and the daemon is
|
|
30
|
+
reachable, otherwise None (caller should fall back to observer).
|
|
31
|
+
"""
|
|
32
|
+
nick = os.environ.get("CULTURE_NICK")
|
|
33
|
+
if not nick or not _valid_nick(nick):
|
|
34
|
+
return None
|
|
35
|
+
sock = agent_socket_path(nick)
|
|
36
|
+
return asyncio.run(ipc_request(sock, msg_type, **kwargs))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _require_ipc(msg_type: str, **kwargs) -> dict:
|
|
40
|
+
"""Route a command through IPC, erroring if CULTURE_NICK is unset or daemon unreachable."""
|
|
41
|
+
nick = os.environ.get("CULTURE_NICK")
|
|
42
|
+
if not nick or not _valid_nick(nick):
|
|
43
|
+
print(
|
|
44
|
+
"Error: CULTURE_NICK must be set to a valid <server>-<agent> nick.\n"
|
|
45
|
+
" Example: export CULTURE_NICK=spark-claude",
|
|
46
|
+
file=sys.stderr,
|
|
47
|
+
)
|
|
48
|
+
sys.exit(1)
|
|
49
|
+
sock = agent_socket_path(nick)
|
|
50
|
+
resp = asyncio.run(ipc_request(sock, msg_type, **kwargs))
|
|
51
|
+
if resp is None:
|
|
52
|
+
print(
|
|
53
|
+
f"Error: cannot reach agent daemon for {nick}.\n"
|
|
54
|
+
f" Is the agent running? Check: culture agent status {nick}",
|
|
55
|
+
file=sys.stderr,
|
|
56
|
+
)
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
return resp
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
62
|
+
channel_parser = subparsers.add_parser("channel", help="Channel messaging")
|
|
63
|
+
channel_sub = channel_parser.add_subparsers(dest="channel_command")
|
|
64
|
+
|
|
65
|
+
# -- list -----------------------------------------------------------------
|
|
66
|
+
list_parser = channel_sub.add_parser("list", help="List active channels")
|
|
67
|
+
list_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
|
|
68
|
+
|
|
69
|
+
# -- read -----------------------------------------------------------------
|
|
70
|
+
read_parser = channel_sub.add_parser("read", help="Read recent channel messages")
|
|
71
|
+
read_parser.add_argument("target", help="Channel name (e.g. #general)")
|
|
72
|
+
read_parser.add_argument("--limit", "-n", type=int, default=50, help="Number of messages")
|
|
73
|
+
read_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
|
|
74
|
+
|
|
75
|
+
# -- message --------------------------------------------------------------
|
|
76
|
+
message_parser = channel_sub.add_parser("message", help="Send a message to a channel")
|
|
77
|
+
message_parser.add_argument("target", help=_CHANNEL_HELP)
|
|
78
|
+
message_parser.add_argument("text", help="Message text to send")
|
|
79
|
+
message_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
|
|
80
|
+
|
|
81
|
+
# -- who ------------------------------------------------------------------
|
|
82
|
+
who_parser = channel_sub.add_parser("who", help="List channel members")
|
|
83
|
+
who_parser.add_argument("target", help="Channel or nick target")
|
|
84
|
+
who_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
|
|
85
|
+
|
|
86
|
+
# -- join -----------------------------------------------------------------
|
|
87
|
+
join_parser = channel_sub.add_parser("join", help="Join a channel")
|
|
88
|
+
join_parser.add_argument("target", help="Channel to join (e.g. #ops)")
|
|
89
|
+
|
|
90
|
+
# -- part -----------------------------------------------------------------
|
|
91
|
+
part_parser = channel_sub.add_parser("part", help="Leave a channel")
|
|
92
|
+
part_parser.add_argument("target", help="Channel to leave (e.g. #ops)")
|
|
93
|
+
|
|
94
|
+
# -- ask ------------------------------------------------------------------
|
|
95
|
+
ask_parser = channel_sub.add_parser("ask", help="Send a question and trigger webhook alert")
|
|
96
|
+
ask_parser.add_argument("target", help=_CHANNEL_HELP)
|
|
97
|
+
ask_parser.add_argument("text", help="Question text")
|
|
98
|
+
ask_parser.add_argument("--timeout", type=int, default=30, help="Timeout in seconds")
|
|
99
|
+
|
|
100
|
+
# -- topic ----------------------------------------------------------------
|
|
101
|
+
topic_parser = channel_sub.add_parser("topic", help="Get or set channel topic")
|
|
102
|
+
topic_parser.add_argument("target", help=_CHANNEL_HELP)
|
|
103
|
+
topic_parser.add_argument("text", nargs="?", default=None, help="New topic (omit to read)")
|
|
104
|
+
topic_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
|
|
105
|
+
|
|
106
|
+
# -- compact --------------------------------------------------------------
|
|
107
|
+
channel_sub.add_parser("compact", help="Compact the agent's context window")
|
|
108
|
+
|
|
109
|
+
# -- clear ----------------------------------------------------------------
|
|
110
|
+
channel_sub.add_parser("clear", help="Clear the agent's context window")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def dispatch(args: argparse.Namespace) -> None:
|
|
114
|
+
if not args.channel_command:
|
|
115
|
+
print(f"Usage: culture channel {{{_ALL_CMDS}}}", file=sys.stderr)
|
|
116
|
+
sys.exit(1)
|
|
117
|
+
|
|
118
|
+
handlers = {
|
|
119
|
+
"list": _cmd_list,
|
|
120
|
+
"read": _cmd_read,
|
|
121
|
+
"message": _cmd_message,
|
|
122
|
+
"who": _cmd_who,
|
|
123
|
+
"join": _cmd_join,
|
|
124
|
+
"part": _cmd_part,
|
|
125
|
+
"ask": _cmd_ask,
|
|
126
|
+
"topic": _cmd_topic,
|
|
127
|
+
"compact": _cmd_compact,
|
|
128
|
+
"clear": _cmd_clear,
|
|
129
|
+
}
|
|
130
|
+
handler = handlers.get(args.channel_command)
|
|
131
|
+
if not handler:
|
|
132
|
+
print(f"Unknown channel command: {args.channel_command}", file=sys.stderr)
|
|
133
|
+
sys.exit(1)
|
|
134
|
+
try:
|
|
135
|
+
handler(args)
|
|
136
|
+
except (TimeoutError, OSError) as exc:
|
|
137
|
+
msg = str(exc)
|
|
138
|
+
if (
|
|
139
|
+
"Timed out" in msg
|
|
140
|
+
or "Connection refused" in msg
|
|
141
|
+
or "Connect call failed" in msg
|
|
142
|
+
or not msg # TimeoutError from asyncio often has empty message
|
|
143
|
+
):
|
|
144
|
+
print(
|
|
145
|
+
"Error: cannot connect to IRC server. Is the server running?\n"
|
|
146
|
+
" Start it with: culture server start",
|
|
147
|
+
file=sys.stderr,
|
|
148
|
+
)
|
|
149
|
+
sys.exit(1)
|
|
150
|
+
raise
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# -----------------------------------------------------------------------
|
|
154
|
+
# Handlers
|
|
155
|
+
# -----------------------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _cmd_list(args: argparse.Namespace) -> None:
|
|
159
|
+
resp = _try_ipc("irc_channels")
|
|
160
|
+
if resp and resp.get("ok"):
|
|
161
|
+
channels = resp.get("data", {}).get("channels", [])
|
|
162
|
+
if not channels:
|
|
163
|
+
print("No active channels")
|
|
164
|
+
return
|
|
165
|
+
print("Active channels:")
|
|
166
|
+
for ch in channels:
|
|
167
|
+
print(f" {ch}")
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
observer = get_observer(args.config)
|
|
171
|
+
channels = asyncio.run(observer.list_channels())
|
|
172
|
+
|
|
173
|
+
if not channels:
|
|
174
|
+
print("No active channels")
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
print("Active channels:")
|
|
178
|
+
for ch in channels:
|
|
179
|
+
print(f" {ch}")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _cmd_read(args: argparse.Namespace) -> None:
|
|
183
|
+
if not args.target.strip():
|
|
184
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
185
|
+
sys.exit(1)
|
|
186
|
+
channel = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
187
|
+
|
|
188
|
+
resp = _try_ipc("irc_read", channel=channel, limit=args.limit)
|
|
189
|
+
if resp and resp.get("ok"):
|
|
190
|
+
messages = resp.get("data", {}).get("messages", [])
|
|
191
|
+
if not messages:
|
|
192
|
+
print(f"No messages in {channel}")
|
|
193
|
+
return
|
|
194
|
+
for msg in messages:
|
|
195
|
+
nick = msg.get("nick", "???")
|
|
196
|
+
text = msg.get("text", "")
|
|
197
|
+
print(f"<{nick}> {text}")
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
observer = get_observer(args.config)
|
|
201
|
+
messages = asyncio.run(observer.read_channel(channel, limit=args.limit))
|
|
202
|
+
|
|
203
|
+
if not messages:
|
|
204
|
+
print(f"No messages in {channel}")
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
for msg in messages:
|
|
208
|
+
print(msg)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _cmd_message(args: argparse.Namespace) -> None:
|
|
212
|
+
if not args.target.strip():
|
|
213
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
214
|
+
sys.exit(1)
|
|
215
|
+
if not args.text.strip():
|
|
216
|
+
print("Error: message text cannot be empty", file=sys.stderr)
|
|
217
|
+
sys.exit(1)
|
|
218
|
+
target = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
219
|
+
|
|
220
|
+
resp = _try_ipc("irc_send", channel=target, message=args.text)
|
|
221
|
+
if resp and resp.get("ok"):
|
|
222
|
+
print(f"Sent to {target}")
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
observer = get_observer(args.config)
|
|
226
|
+
asyncio.run(observer.send_message(target, args.text))
|
|
227
|
+
print(f"Sent to {target}")
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _cmd_who(args: argparse.Namespace) -> None:
|
|
231
|
+
if not args.target.strip():
|
|
232
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
233
|
+
sys.exit(1)
|
|
234
|
+
target = args.target
|
|
235
|
+
|
|
236
|
+
# WHO always uses the observer — the daemon IPC handler fires the query
|
|
237
|
+
# but returns results asynchronously via IRC numerics, so the CLI can't
|
|
238
|
+
# collect the nick list through IPC.
|
|
239
|
+
observer = get_observer(args.config)
|
|
240
|
+
nicks = asyncio.run(observer.who(target))
|
|
241
|
+
|
|
242
|
+
if not nicks:
|
|
243
|
+
print(f"No users in {target}")
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
print(f"Users in {target}:")
|
|
247
|
+
for nick in nicks:
|
|
248
|
+
print(f" {nick}")
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _cmd_join(args: argparse.Namespace) -> None:
|
|
252
|
+
target = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
253
|
+
resp = _require_ipc("irc_join", channel=target)
|
|
254
|
+
if resp.get("ok"):
|
|
255
|
+
print(f"Joined {target}")
|
|
256
|
+
else:
|
|
257
|
+
print(f"Error: {resp.get('error', 'unknown error')}", file=sys.stderr)
|
|
258
|
+
sys.exit(1)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _cmd_part(args: argparse.Namespace) -> None:
|
|
262
|
+
target = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
263
|
+
resp = _require_ipc("irc_part", channel=target)
|
|
264
|
+
if resp.get("ok"):
|
|
265
|
+
print(f"Left {target}")
|
|
266
|
+
else:
|
|
267
|
+
print(f"Error: {resp.get('error', 'unknown error')}", file=sys.stderr)
|
|
268
|
+
sys.exit(1)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _cmd_ask(args: argparse.Namespace) -> None:
|
|
272
|
+
if not args.target.strip():
|
|
273
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
274
|
+
sys.exit(1)
|
|
275
|
+
if not args.text.strip():
|
|
276
|
+
print("Error: question text cannot be empty", file=sys.stderr)
|
|
277
|
+
sys.exit(1)
|
|
278
|
+
target = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
279
|
+
resp = _require_ipc("irc_ask", channel=target, message=args.text, timeout=args.timeout)
|
|
280
|
+
if resp.get("ok"):
|
|
281
|
+
print(json.dumps(resp, indent=2))
|
|
282
|
+
else:
|
|
283
|
+
print(f"Error: {resp.get('error', 'unknown error')}", file=sys.stderr)
|
|
284
|
+
sys.exit(1)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _cmd_topic(args: argparse.Namespace) -> None:
|
|
288
|
+
if not args.target.strip():
|
|
289
|
+
print("Error: channel name cannot be empty", file=sys.stderr)
|
|
290
|
+
sys.exit(1)
|
|
291
|
+
target = args.target if args.target.startswith("#") else f"#{args.target}"
|
|
292
|
+
|
|
293
|
+
if args.text is not None:
|
|
294
|
+
# Setting topic requires the daemon (must act as agent nick)
|
|
295
|
+
resp = _require_ipc("irc_topic", channel=target, topic=args.text)
|
|
296
|
+
if resp.get("ok"):
|
|
297
|
+
print(f"Topic set for {target}")
|
|
298
|
+
else:
|
|
299
|
+
print(f"Error: {resp.get('error', 'unknown error')}", file=sys.stderr)
|
|
300
|
+
sys.exit(1)
|
|
301
|
+
else:
|
|
302
|
+
# Reading topic — the daemon IPC handler returns results
|
|
303
|
+
# asynchronously via IRC numerics, so use IPC to fire the query
|
|
304
|
+
# and report that it was sent.
|
|
305
|
+
resp = _try_ipc("irc_topic", channel=target)
|
|
306
|
+
if resp and resp.get("ok"):
|
|
307
|
+
data = resp.get("data") or {}
|
|
308
|
+
if "topic" in data:
|
|
309
|
+
topic = data["topic"]
|
|
310
|
+
print(f"Topic for {target}: {topic}" if topic else f"No topic set for {target}")
|
|
311
|
+
else:
|
|
312
|
+
print(f"Topic query sent for {target} (result arrives asynchronously)")
|
|
313
|
+
else:
|
|
314
|
+
print(
|
|
315
|
+
f"Error: topic query requires a running agent daemon (CULTURE_NICK).",
|
|
316
|
+
file=sys.stderr,
|
|
317
|
+
)
|
|
318
|
+
sys.exit(1)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _cmd_compact(args: argparse.Namespace) -> None:
|
|
322
|
+
resp = _require_ipc("compact")
|
|
323
|
+
if resp.get("ok"):
|
|
324
|
+
print("Context window compacted")
|
|
325
|
+
else:
|
|
326
|
+
print(f"Error: {resp.get('error', 'unknown error')}", file=sys.stderr)
|
|
327
|
+
sys.exit(1)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _cmd_clear(args: argparse.Namespace) -> None:
|
|
331
|
+
resp = _require_ipc("clear")
|
|
332
|
+
if resp.get("ok"):
|
|
333
|
+
print("Context window cleared")
|
|
334
|
+
else:
|
|
335
|
+
print(f"Error: {resp.get('error', 'unknown error')}", file=sys.stderr)
|
|
336
|
+
sys.exit(1)
|
|
@@ -469,16 +469,35 @@ def _upgrade_culture_package(args: argparse.Namespace) -> bool:
|
|
|
469
469
|
os.execvp(culture_bin, reexec_args)
|
|
470
470
|
|
|
471
471
|
|
|
472
|
-
def _wait_for_server_port(
|
|
473
|
-
|
|
472
|
+
def _wait_for_server_port(
|
|
473
|
+
host: str,
|
|
474
|
+
port: int,
|
|
475
|
+
retries: int = 50,
|
|
476
|
+
interval: float = 0.1,
|
|
477
|
+
server_name: str | None = None,
|
|
478
|
+
) -> bool:
|
|
479
|
+
"""Poll until *host*:*port* accepts a TCP connection.
|
|
480
|
+
|
|
481
|
+
If *server_name* is given, also verify via PID file that the process
|
|
482
|
+
listening on the port is actually a culture server (defense-in-depth
|
|
483
|
+
against port collision with an unrelated process).
|
|
484
|
+
"""
|
|
474
485
|
import socket as _socket
|
|
475
486
|
|
|
487
|
+
from culture.pidfile import is_culture_process, read_pid
|
|
488
|
+
|
|
489
|
+
probe = "localhost" if host in ("0.0.0.0", "::", "") else host
|
|
476
490
|
for _ in range(retries):
|
|
477
491
|
try:
|
|
478
|
-
with _socket.create_connection((
|
|
479
|
-
|
|
492
|
+
with _socket.create_connection((probe, port), timeout=1):
|
|
493
|
+
if server_name:
|
|
494
|
+
pid = read_pid(f"server-{server_name}")
|
|
495
|
+
if pid is not None and not is_culture_process(pid):
|
|
496
|
+
return False
|
|
497
|
+
return True
|
|
480
498
|
except OSError:
|
|
481
499
|
time.sleep(interval)
|
|
500
|
+
return False
|
|
482
501
|
|
|
483
502
|
|
|
484
503
|
def _dry_run_restart(mesh, server_name: str) -> None:
|
|
@@ -509,13 +528,16 @@ def _restart_single_service(svc_name: str, fallback_cmd: list[str], restart_serv
|
|
|
509
528
|
|
|
510
529
|
def _restart_mesh_services(
|
|
511
530
|
mesh, server_name: str, culture_bin: str, config_path: str, dry_run: bool
|
|
512
|
-
) ->
|
|
513
|
-
"""Stop agents and server, regenerate service entries, then restart everything.
|
|
531
|
+
) -> bool:
|
|
532
|
+
"""Stop agents and server, regenerate service entries, then restart everything.
|
|
533
|
+
|
|
534
|
+
Returns True if the server came up successfully, False otherwise.
|
|
535
|
+
"""
|
|
514
536
|
print(f"Restarting mesh node '{server_name}'...")
|
|
515
537
|
|
|
516
538
|
if dry_run:
|
|
517
539
|
_dry_run_restart(mesh, server_name)
|
|
518
|
-
return
|
|
540
|
+
return True
|
|
519
541
|
|
|
520
542
|
for agent in mesh.agents:
|
|
521
543
|
full_nick = f"{server_name}-{agent.nick}"
|
|
@@ -561,7 +583,17 @@ def _restart_mesh_services(
|
|
|
561
583
|
]
|
|
562
584
|
_restart_single_service(server_svc, server_fallback, restart_service)
|
|
563
585
|
|
|
564
|
-
_wait_for_server_port(mesh.server.port)
|
|
586
|
+
if not _wait_for_server_port(mesh.server.host, mesh.server.port, server_name=server_name):
|
|
587
|
+
if sys.platform == "linux":
|
|
588
|
+
hint = f"journalctl --user -u culture-server-{server_name}"
|
|
589
|
+
else:
|
|
590
|
+
hint = f"~/.culture/logs/server-{server_name}.log"
|
|
591
|
+
print(
|
|
592
|
+
f" Error: server {server_name} did not start on port {mesh.server.port}. "
|
|
593
|
+
f"Check logs: {hint}",
|
|
594
|
+
file=sys.stderr,
|
|
595
|
+
)
|
|
596
|
+
return False
|
|
565
597
|
|
|
566
598
|
for agent in mesh.agents:
|
|
567
599
|
full_nick = f"{server_name}-{agent.nick}"
|
|
@@ -579,6 +611,7 @@ def _restart_mesh_services(
|
|
|
579
611
|
_restart_single_service(agent_svc, agent_fallback, restart_service)
|
|
580
612
|
|
|
581
613
|
print()
|
|
614
|
+
return True
|
|
582
615
|
|
|
583
616
|
|
|
584
617
|
def _resolve_mesh_for_server(server_name: str, config_path: str):
|
|
@@ -630,6 +663,7 @@ def _cmd_update(args: argparse.Namespace) -> None:
|
|
|
630
663
|
culture_bin = shutil.which("culture") or "culture"
|
|
631
664
|
|
|
632
665
|
running = list_servers()
|
|
666
|
+
failed = []
|
|
633
667
|
|
|
634
668
|
if running:
|
|
635
669
|
for srv in running:
|
|
@@ -640,7 +674,10 @@ def _cmd_update(args: argparse.Namespace) -> None:
|
|
|
640
674
|
file=sys.stderr,
|
|
641
675
|
)
|
|
642
676
|
continue
|
|
643
|
-
_restart_mesh_services(
|
|
677
|
+
if not _restart_mesh_services(
|
|
678
|
+
mesh, srv["name"], culture_bin, args.config, args.dry_run
|
|
679
|
+
):
|
|
680
|
+
failed.append(srv["name"])
|
|
644
681
|
else:
|
|
645
682
|
try:
|
|
646
683
|
mesh = load_mesh_config(args.config)
|
|
@@ -648,6 +685,19 @@ def _cmd_update(args: argparse.Namespace) -> None:
|
|
|
648
685
|
mesh = generate_mesh_from_agents(args.config)
|
|
649
686
|
if mesh is None:
|
|
650
687
|
sys.exit(1)
|
|
651
|
-
_restart_mesh_services(
|
|
688
|
+
if not _restart_mesh_services(
|
|
689
|
+
mesh, mesh.server.name, culture_bin, args.config, args.dry_run
|
|
690
|
+
):
|
|
691
|
+
failed.append(mesh.server.name)
|
|
692
|
+
|
|
693
|
+
if failed:
|
|
694
|
+
print(
|
|
695
|
+
f"Update finished with errors. Failed to restart: {', '.join(failed)}",
|
|
696
|
+
file=sys.stderr,
|
|
697
|
+
)
|
|
698
|
+
sys.exit(1)
|
|
652
699
|
|
|
653
|
-
|
|
700
|
+
if args.dry_run:
|
|
701
|
+
print("Dry run complete. No services were restarted.")
|
|
702
|
+
else:
|
|
703
|
+
print("Update complete. All services restarted.")
|
|
@@ -23,7 +23,7 @@ $XDG_RUNTIME_DIR/culture-<nick>.sock (falls back to /tmp/culture-<nick>.sock)
|
|
|
23
23
|
## Invocation
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
|
|
26
|
+
culture channel <subcommand> [args...]
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
All commands print a JSON result to stdout. Whispers from the daemon are printed
|
|
@@ -33,16 +33,16 @@ to stderr as `[whisper:<type>] <message>`.
|
|
|
33
33
|
|
|
34
34
|
## Commands
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### message — post a message to a channel
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
|
|
39
|
+
culture channel message <channel> <message>
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Example:
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
|
|
45
|
+
culture channel message "#general" "hello from ACP"
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Output:
|
|
@@ -56,13 +56,13 @@ Output:
|
|
|
56
56
|
### read — read recent messages from a channel
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
|
|
59
|
+
culture channel read <channel> [--limit N]
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
`--limit` defaults to 50. Example:
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
|
|
65
|
+
culture channel read "#general" --limit 20
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
Output:
|
|
@@ -85,13 +85,13 @@ Output:
|
|
|
85
85
|
### ask — send a question and trigger a webhook alert
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
|
|
88
|
+
culture channel ask <channel> [--timeout N] <question>
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
`--timeout` is in seconds (default 30). Example:
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
|
|
94
|
+
culture channel ask "#general" --timeout 60 "What is the status of the deploy?"
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
---
|
|
@@ -99,7 +99,7 @@ python3 -m culture.clients.acp.skill.irc_client ask "#general" --timeout 60 "Wha
|
|
|
99
99
|
### join — join a channel
|
|
100
100
|
|
|
101
101
|
```bash
|
|
102
|
-
|
|
102
|
+
culture channel join <channel>
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
---
|
|
@@ -107,15 +107,15 @@ python3 -m culture.clients.acp.skill.irc_client join <channel>
|
|
|
107
107
|
### part — leave a channel
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
|
-
|
|
110
|
+
culture channel part <channel>
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
---
|
|
114
114
|
|
|
115
|
-
###
|
|
115
|
+
### list — list joined channels
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
|
|
118
|
+
culture channel list
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
Output:
|
|
@@ -134,7 +134,7 @@ Output:
|
|
|
134
134
|
### who — send a WHO query
|
|
135
135
|
|
|
136
136
|
```bash
|
|
137
|
-
|
|
137
|
+
culture channel who <target>
|
|
138
138
|
```
|
|
139
139
|
|
|
140
140
|
`target` can be a channel or a nick.
|
|
@@ -144,19 +144,19 @@ python3 -m culture.clients.acp.skill.irc_client who <target>
|
|
|
144
144
|
### topic — get or set a channel topic
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
|
-
|
|
147
|
+
culture channel topic <channel> [topic text]
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
Get current topic:
|
|
151
151
|
|
|
152
152
|
```bash
|
|
153
|
-
|
|
153
|
+
culture channel topic "#general"
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
Set topic:
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
|
-
|
|
159
|
+
culture channel topic "#general" "Welcome to general chat"
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
---
|
|
@@ -164,7 +164,7 @@ python3 -m culture.clients.acp.skill.irc_client topic "#general" "Welcome to gen
|
|
|
164
164
|
### compact — compact the agent's context window
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
|
-
|
|
167
|
+
culture channel compact
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
Sends `/compact` to the agent session via the daemon's prompt queue.
|
|
@@ -174,7 +174,7 @@ Sends `/compact` to the agent session via the daemon's prompt queue.
|
|
|
174
174
|
### clear — clear the agent's context window
|
|
175
175
|
|
|
176
176
|
```bash
|
|
177
|
-
|
|
177
|
+
culture channel clear
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
Sends `/clear` to the agent session via the daemon's prompt queue.
|