agentirc-cli 8.7.0__tar.gz → 8.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/CHANGELOG.md +15 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/PKG-INFO +1 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/channel.py +36 -1
- agentirc_cli-8.7.1/culture/cli/shared/constants.py +54 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/daemon.py +2 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/skill/irc_client.py +2 -2
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/daemon.py +2 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/skill/irc_client.py +2 -2
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/daemon.py +2 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/skill/irc_client.py +2 -2
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/daemon.py +2 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/skill/irc_client.py +2 -2
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/overview/collector.py +2 -2
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/architecture/agent-harness-spec.md +12 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/cli/index.md +13 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/daemon.py +2 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/skill/irc_client.py +2 -2
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/pyproject.toml +1 -1
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_channel_cli.py +78 -1
- agentirc_cli-8.7.1/tests/test_constants.py +86 -0
- agentirc_cli-8.7.1/tests/test_socket_path_convergence.py +153 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/uv.lock +1 -1
- agentirc_cli-8.7.0/culture/cli/shared/constants.py +0 -43
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.claude/agents/doc-test-alignment.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.flake8 +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.github/workflows/docs-check.yml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.gitignore +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.pr_agent.toml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/.pylintrc +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/CLAUDE.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/Gemfile +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/Gemfile.lock +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/LICENSE +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/README.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/SECURITY.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/_config.base.yml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/_config.culture.yml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/_data/sites.yml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/_includes/head_custom.html +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/_sass/color_schemes/dark-terminal.scss +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/assets/images/IMG_3183.png +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/assets/images/apple-touch-icon.png +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/assets/images/favicon-16x16.png +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/assets/images/favicon-32x32.png +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/assets/images/favicon.ico +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/assets/images/og-agentirc.png +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/assets/images/og-culture.png +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/__main__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/CLAUDE.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/__main__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/channel.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/client.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/docs/agentirc-architecture.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/docs/agentirc-features.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/docs/agentirc-skill.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/docs/agentirc.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/events.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/history_store.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/ircd.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/remote_client.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/room_store.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/rooms_util.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/server_link.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/skill.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/skills/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/skills/history.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/skills/icon.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/skills/rooms.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/skills/threads.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/agentirc/thread_store.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/aio.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/bot.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/filter_dsl.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/system/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/system/welcome/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/system/welcome/bot.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/system/welcome/handler.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/_passthrough.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/afi.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/agent.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/bot.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/devex.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/introspect.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/mesh.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/server.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/shared/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/shared/display.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/shared/formatting.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/shared/ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/shared/mesh.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/shared/process.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/cli/skills.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/agent_runner.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/culture.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/irc_transport.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/telemetry.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/culture.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/telemetry.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/culture.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/telemetry.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/culture.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/telemetry.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/app.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/client.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/commands.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/status.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/constants.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/credentials.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/formatting.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/learn_prompt.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/mesh_config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/observer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/overview/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/overview/model.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/overview/web/style.css +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/persistence.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/pidfile.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/commands.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/audit.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/events.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/extensions/tracing.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/message.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/protocol/replies.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/telemetry/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/telemetry/audit.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/telemetry/context.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/telemetry/metrics.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/culture/telemetry/tracing.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/README.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/architecture-overview.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/audit.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/bots.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/events.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/harness-telemetry.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/otelcol-template.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/telemetry.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/agentirc/why-agentirc.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/agent-lifecycle.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/choose-a-harness.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/features.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/mental-model.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/operate.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/patterns.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/quickstart.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/reflective-development.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/vision-patterns-index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/vision.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/culture/what-is-culture.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/architecture/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/architecture/layers.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/architecture/subsites.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/architecture/threads.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/cli/afi.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/cli/commands.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/cli/devex.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/console.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/harnesses/acp.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/harnesses/claude.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/harnesses/codex.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/harnesses/copilot.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/harnesses/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/server/architecture.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/server/config.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/server/deployment.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/server/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/reference/server/security.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/resources/positioning.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/concepts/federation.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/concepts/harnesses.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/concepts/humans-and-agents.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/concepts/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/concepts/persistence.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/concepts/rooms.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/demos/magic-demo.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/guides/first-session.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/guides/index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/guides/join-as-human.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/guides/local-setup.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/guides/multi-machine.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/shared/use-cases-index.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-09-decentralized-agent-config.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-12-console-enhancements.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-15-mesh-events.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-18-culture-dev-positioning.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-22-agex-integration.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-24-otel-foundation.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-25-otel-federation.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-26-otel-metrics.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-27-otel-audit.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/plans/2026-04-28-otel-harness.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-07-reflective-development-reframe-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-08-reflective-development-deepening-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-09-decentralized-agent-config-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-12-console-enhancements-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-15-mesh-events-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-17-sites-repositioning-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-18-culture-dev-positioning-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-22-agex-integration-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/docs/superpowers/specs/2026-04-24-otel-observability-design.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/favicon.ico +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/culture.yaml +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/telemetry.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/robots.txt +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/sitemap-agentirc.html +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/sitemap-main.html +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/sitemap.html +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/sonar-project.properties +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/conftest.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/conftest.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_agent_runner_acp.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_agent_runner_claude.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_agent_runner_codex.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_agent_runner_copilot.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_all_backends_parity.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_daemon_telemetry.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_irc_transport_propagation.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_record_llm_call.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/harness/test_telemetry_module.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/__init__.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/_fakes.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/_metrics_helpers.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/conftest.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_audit_emit.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_audit_federation.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_audit_lifecycle.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_audit_module.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_audit_parse_error.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_bot_event_dispatch_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_bot_run_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_config_load.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_context.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_dispatch_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_emit_event_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_federation_propagation.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_bots.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_clients.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_events.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_init.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_irc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_s2s.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_trace_inbound.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_metrics_webhook.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_outbound_inject.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_parse_error.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_privmsg_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_s2s_dispatch_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_s2s_relay_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_s2s_session_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_server_init.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_server_link_inject.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_session_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_tracing.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/telemetry/test_webhook_http_span.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_archive.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_bot.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_bot_config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_bot_config_fires_event_toplevel.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_channel.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_cli_afi.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_cli_devex.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_cli_introspect.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_cli_passthrough.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_connection.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_chat_markdown.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_client.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_commands.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_connection.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_fixes_224_227.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_icons.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_integration.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_console_status.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_credentials.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_culture_config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_daemon.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_discovery.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_display.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_basic.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_bot_chain.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_bot_trigger.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_cap_fallback.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_catalog.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_federation.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_history.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_lifecycle.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_events_reserved_nick.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_federation.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_filter_dsl.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_history.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_http_listener.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_ipc.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_irc_transport_tags.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_learn_prompt.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_manifest_config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_mention_warning.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_mentions.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_mesh_readiness.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_message.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_message_tags.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_messaging.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_migrate_cli.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_modes.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_overview_model.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_overview_web.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_persistence.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_persistence_timeout.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_pidfile.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_register_cli.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_rooms.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_skill_client.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_skill_docs.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_skills.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_socket_server.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_supervisor.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_template_engine.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_threads.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_wait_for_port.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_webhook.py +0 -0
- {agentirc_cli-8.7.0 → agentirc_cli-8.7.1}/tests/test_welcome_bot.py +0 -0
|
@@ -4,6 +4,21 @@ 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
|
+
## [8.7.1] - 2026-04-27
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `tests/test_socket_path_convergence.py`: parametric regression test asserting all 8 daemon+skill resolvers agree with the CLI's `agent_socket_path()` for both `XDG_RUNTIME_DIR` set and unset.
|
|
12
|
+
- `tests/test_constants.py`: unit tests pinning `culture_runtime_dir()` contract (env precedence, `~/.culture/run/` fallback, mode 0700).
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- `culture channel {message,list,read}`: when `CULTURE_NICK` is set but the daemon IPC is unreachable or rejects the request, the CLI now prints a stderr warning naming the nick, the socket path, and the GitHub issue tracker before falling back to the peek-nick observer. The fallback itself is preserved for human use (no `CULTURE_NICK`).
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Converged all socket-path resolvers (4 backend daemons, 4 skill irc_clients, overview collector, harness package reference impl) on `culture_runtime_dir()` so the CLI and daemon agree on the IPC socket path when `XDG_RUNTIME_DIR` is unset (macOS default). Previously the daemon listened on `/tmp/culture-<nick>.sock` while the CLI looked in `~/.culture/run/`, causing `culture channel message` to silently fall back to an anonymous `_peek<random>` nick (#302, regression of #203).
|
|
21
|
+
|
|
7
22
|
## [8.7.0] - 2026-04-26
|
|
8
23
|
|
|
9
24
|
### Added
|
|
@@ -24,11 +24,43 @@ def _valid_nick(nick: str) -> bool:
|
|
|
24
24
|
return len(parts) == 2 and all(parts)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
_ISSUE_TRACKER_URL = "https://github.com/agentculture/culture/issues"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _warn_observer_fallback(operation: str) -> None:
|
|
31
|
+
"""Warn on stderr when an observer-fallback command silently went anonymous.
|
|
32
|
+
|
|
33
|
+
Called only by the three commands that do fall back to the observer
|
|
34
|
+
connection (`message`, `list`, `read`). `topic` and the `_require_ipc`
|
|
35
|
+
commands exit on failure instead, so this helper is not used there —
|
|
36
|
+
a misleading "falling back" notice would contradict the actual error.
|
|
37
|
+
|
|
38
|
+
Issue #302: a daemon/CLI socket-path mismatch on macOS hid behind the
|
|
39
|
+
silent peek fallback for two releases. The warning names the issue
|
|
40
|
+
tracker so the next reproducer takes seconds to file.
|
|
41
|
+
"""
|
|
42
|
+
nick = os.environ.get("CULTURE_NICK")
|
|
43
|
+
if not nick or not _valid_nick(nick):
|
|
44
|
+
return # Human use without CULTURE_NICK — observer is the intended path.
|
|
45
|
+
sock = agent_socket_path(nick)
|
|
46
|
+
print(
|
|
47
|
+
f"Warning: agent daemon IPC for {nick} failed ({sock}).\n"
|
|
48
|
+
f" Falling back to observer connection — `{operation}` will not run\n"
|
|
49
|
+
f" through the agent daemon and the action will not appear under {nick}.\n"
|
|
50
|
+
f" Verify the daemon is running: culture agent status {nick}\n"
|
|
51
|
+
f" If it is running, this is a bug. Please open an issue:\n"
|
|
52
|
+
f" {_ISSUE_TRACKER_URL}",
|
|
53
|
+
file=sys.stderr,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
27
57
|
def _try_ipc(msg_type: str, **kwargs) -> dict | None:
|
|
28
58
|
"""Try to route a command through the agent daemon's IPC socket.
|
|
29
59
|
|
|
30
60
|
Returns the response dict if CULTURE_NICK is set and the daemon is
|
|
31
|
-
reachable, otherwise None (caller should fall back to observer
|
|
61
|
+
reachable, otherwise None (caller should fall back to observer or
|
|
62
|
+
surface its own error — see `_warn_observer_fallback` for the
|
|
63
|
+
observer-fallback path).
|
|
32
64
|
"""
|
|
33
65
|
nick = os.environ.get("CULTURE_NICK")
|
|
34
66
|
if not nick or not _valid_nick(nick):
|
|
@@ -169,6 +201,7 @@ def _cmd_list(args: argparse.Namespace) -> None:
|
|
|
169
201
|
print(f" {ch}")
|
|
170
202
|
return
|
|
171
203
|
|
|
204
|
+
_warn_observer_fallback("channel list")
|
|
172
205
|
observer = get_observer(args.config)
|
|
173
206
|
channels = asyncio.run(observer.list_channels())
|
|
174
207
|
|
|
@@ -199,6 +232,7 @@ def _cmd_read(args: argparse.Namespace) -> None:
|
|
|
199
232
|
print(f"<{nick}> {text}")
|
|
200
233
|
return
|
|
201
234
|
|
|
235
|
+
_warn_observer_fallback("channel read")
|
|
202
236
|
observer = get_observer(args.config)
|
|
203
237
|
messages = asyncio.run(observer.read_channel(channel, limit=args.limit))
|
|
204
238
|
|
|
@@ -267,6 +301,7 @@ def _cmd_message(args: argparse.Namespace) -> None:
|
|
|
267
301
|
print(f"Sent to {target}")
|
|
268
302
|
return
|
|
269
303
|
|
|
304
|
+
_warn_observer_fallback("channel message")
|
|
270
305
|
observer = get_observer(args.config)
|
|
271
306
|
asyncio.run(observer.send_message(target, text))
|
|
272
307
|
print(f"Sent to {target}")
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Shared constants for culture CLI modules."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import stat
|
|
5
|
+
|
|
6
|
+
from culture.bots.config import BOT_CONFIG_FILE # noqa: F401
|
|
7
|
+
|
|
8
|
+
DEFAULT_CONFIG = os.path.expanduser("~/.culture/server.yaml")
|
|
9
|
+
LOG_DIR = os.path.expanduser("~/.culture/logs")
|
|
10
|
+
|
|
11
|
+
_CONFIG_HELP = "Config file path"
|
|
12
|
+
_SERVER_NAME_HELP = "Server name"
|
|
13
|
+
_BOT_NAME_HELP = "Bot name"
|
|
14
|
+
|
|
15
|
+
DEFAULT_CHANNEL = "#general"
|
|
16
|
+
NO_AGENTS_MSG = "No agents configured"
|
|
17
|
+
CULTURE_DIR = ".culture"
|
|
18
|
+
AGENTS_YAML = "agents.yaml"
|
|
19
|
+
|
|
20
|
+
DEFAULT_SERVER_CONFIG = os.path.expanduser("~/.culture/server.yaml")
|
|
21
|
+
LEGACY_CONFIG = os.path.expanduser("~/.culture/agents.yaml")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def culture_runtime_dir() -> str:
|
|
25
|
+
"""Return a user-private directory for culture daemon sockets.
|
|
26
|
+
|
|
27
|
+
Resolution order:
|
|
28
|
+
|
|
29
|
+
1. ``$XDG_RUNTIME_DIR`` when set (Linux/systemd default — already
|
|
30
|
+
user-private at ``/run/user/<uid>``).
|
|
31
|
+
2. ``~/.culture/run/`` otherwise (typical macOS path), created mode
|
|
32
|
+
0700 if missing and re-tightened to 0700 on every call so a
|
|
33
|
+
hand-created or pre-existing dir cannot leak sockets.
|
|
34
|
+
|
|
35
|
+
Raises ``RuntimeError`` when neither ``XDG_RUNTIME_DIR`` nor a
|
|
36
|
+
resolvable home directory is available — silently writing a literal
|
|
37
|
+
``~/.culture/run`` directory in CWD would surprise callers and the
|
|
38
|
+
daemons (which now route through this resolver) would fail at
|
|
39
|
+
socket-bind time anyway.
|
|
40
|
+
"""
|
|
41
|
+
xdg = os.environ.get("XDG_RUNTIME_DIR")
|
|
42
|
+
if xdg:
|
|
43
|
+
return xdg
|
|
44
|
+
home = os.path.expanduser("~")
|
|
45
|
+
if not home or home == "~" or not os.path.isabs(home):
|
|
46
|
+
raise RuntimeError(
|
|
47
|
+
"culture_runtime_dir(): cannot resolve a home directory "
|
|
48
|
+
"(os.path.expanduser('~') returned %r). Set $HOME or "
|
|
49
|
+
"$XDG_RUNTIME_DIR before running culture commands." % home
|
|
50
|
+
)
|
|
51
|
+
fallback = os.path.join(home, ".culture", "run")
|
|
52
|
+
os.makedirs(fallback, mode=0o700, exist_ok=True)
|
|
53
|
+
os.chmod(fallback, stat.S_IRWXU)
|
|
54
|
+
return fallback
|
|
@@ -18,6 +18,7 @@ import time
|
|
|
18
18
|
from collections import deque
|
|
19
19
|
|
|
20
20
|
from culture.aio import maybe_await
|
|
21
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
21
22
|
from culture.clients.acp.agent_runner import ACPAgentRunner
|
|
22
23
|
from culture.clients.acp.config import AgentConfig, DaemonConfig
|
|
23
24
|
from culture.clients.acp.ipc import make_response
|
|
@@ -62,7 +63,7 @@ class ACPDaemon:
|
|
|
62
63
|
self.skip_agent = skip_agent
|
|
63
64
|
|
|
64
65
|
self._socket_path = os.path.join(
|
|
65
|
-
socket_dir or
|
|
66
|
+
socket_dir or culture_runtime_dir(),
|
|
66
67
|
f"culture-{agent.nick}.sock",
|
|
67
68
|
)
|
|
68
69
|
|
|
@@ -16,6 +16,7 @@ import os
|
|
|
16
16
|
import sys
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
19
20
|
from culture.clients.acp.ipc import (
|
|
20
21
|
MSG_TYPE_RESPONSE,
|
|
21
22
|
MSG_TYPE_WHISPER,
|
|
@@ -192,8 +193,7 @@ def _sock_path_from_env() -> str:
|
|
|
192
193
|
if not nick:
|
|
193
194
|
print("ERROR: CULTURE_NICK environment variable is not set", file=sys.stderr)
|
|
194
195
|
sys.exit(1)
|
|
195
|
-
|
|
196
|
-
return os.path.join(runtime_dir, f"culture-{nick}.sock")
|
|
196
|
+
return os.path.join(culture_runtime_dir(), f"culture-{nick}.sock")
|
|
197
197
|
|
|
198
198
|
|
|
199
199
|
def _parse_ask_timeout(remaining: list[str]) -> tuple[int, list[str]]:
|
|
@@ -8,6 +8,7 @@ import re
|
|
|
8
8
|
import time
|
|
9
9
|
|
|
10
10
|
from culture.aio import maybe_await
|
|
11
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
11
12
|
from culture.clients.claude.agent_runner import AgentRunner
|
|
12
13
|
from culture.clients.claude.config import AgentConfig, DaemonConfig
|
|
13
14
|
from culture.clients.claude.ipc import make_response
|
|
@@ -51,7 +52,7 @@ class AgentDaemon:
|
|
|
51
52
|
self.skip_claude = skip_claude
|
|
52
53
|
|
|
53
54
|
self._socket_path = os.path.join(
|
|
54
|
-
socket_dir or
|
|
55
|
+
socket_dir or culture_runtime_dir(),
|
|
55
56
|
f"culture-{agent.nick}.sock",
|
|
56
57
|
)
|
|
57
58
|
|
|
@@ -16,6 +16,7 @@ import os
|
|
|
16
16
|
import sys
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
19
20
|
from culture.clients.claude.ipc import (
|
|
20
21
|
MSG_TYPE_RESPONSE,
|
|
21
22
|
MSG_TYPE_WHISPER,
|
|
@@ -189,8 +190,7 @@ def _sock_path_from_env() -> str:
|
|
|
189
190
|
if not nick:
|
|
190
191
|
print("ERROR: CULTURE_NICK environment variable is not set", file=sys.stderr)
|
|
191
192
|
sys.exit(1)
|
|
192
|
-
|
|
193
|
-
return os.path.join(runtime_dir, f"culture-{nick}.sock")
|
|
193
|
+
return os.path.join(culture_runtime_dir(), f"culture-{nick}.sock")
|
|
194
194
|
|
|
195
195
|
|
|
196
196
|
def _parse_ask_timeout(remaining: list[str]) -> tuple[int, list[str]]:
|
|
@@ -15,6 +15,7 @@ import time
|
|
|
15
15
|
from collections import deque
|
|
16
16
|
|
|
17
17
|
from culture.aio import maybe_await
|
|
18
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
18
19
|
from culture.clients.codex.agent_runner import CodexAgentRunner
|
|
19
20
|
from culture.clients.codex.config import AgentConfig, DaemonConfig
|
|
20
21
|
from culture.clients.codex.ipc import make_response
|
|
@@ -66,7 +67,7 @@ class CodexDaemon:
|
|
|
66
67
|
self.skip_codex = skip_codex
|
|
67
68
|
|
|
68
69
|
self._socket_path = os.path.join(
|
|
69
|
-
socket_dir or
|
|
70
|
+
socket_dir or culture_runtime_dir(),
|
|
70
71
|
f"culture-{agent.nick}.sock",
|
|
71
72
|
)
|
|
72
73
|
|
|
@@ -16,6 +16,7 @@ import os
|
|
|
16
16
|
import sys
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
19
20
|
from culture.clients.codex.ipc import (
|
|
20
21
|
MSG_TYPE_RESPONSE,
|
|
21
22
|
MSG_TYPE_WHISPER,
|
|
@@ -189,8 +190,7 @@ def _sock_path_from_env() -> str:
|
|
|
189
190
|
if not nick:
|
|
190
191
|
print("ERROR: CULTURE_NICK environment variable is not set", file=sys.stderr)
|
|
191
192
|
sys.exit(1)
|
|
192
|
-
|
|
193
|
-
return os.path.join(runtime_dir, f"culture-{nick}.sock")
|
|
193
|
+
return os.path.join(culture_runtime_dir(), f"culture-{nick}.sock")
|
|
194
194
|
|
|
195
195
|
|
|
196
196
|
def _parse_ask_timeout(remaining: list[str]) -> tuple[int, list[str]]:
|
|
@@ -15,6 +15,7 @@ import time
|
|
|
15
15
|
from collections import deque
|
|
16
16
|
|
|
17
17
|
from culture.aio import maybe_await
|
|
18
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
18
19
|
from culture.clients.copilot.agent_runner import CopilotAgentRunner
|
|
19
20
|
from culture.clients.copilot.config import AgentConfig, DaemonConfig
|
|
20
21
|
from culture.clients.copilot.ipc import make_response
|
|
@@ -59,7 +60,7 @@ class CopilotDaemon:
|
|
|
59
60
|
self.skip_copilot = skip_copilot
|
|
60
61
|
|
|
61
62
|
self._socket_path = os.path.join(
|
|
62
|
-
socket_dir or
|
|
63
|
+
socket_dir or culture_runtime_dir(),
|
|
63
64
|
f"culture-{agent.nick}.sock",
|
|
64
65
|
)
|
|
65
66
|
|
|
@@ -16,6 +16,7 @@ import os
|
|
|
16
16
|
import sys
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
19
20
|
from culture.clients.copilot.ipc import (
|
|
20
21
|
MSG_TYPE_RESPONSE,
|
|
21
22
|
MSG_TYPE_WHISPER,
|
|
@@ -192,8 +193,7 @@ def _sock_path_from_env() -> str:
|
|
|
192
193
|
if not nick:
|
|
193
194
|
print("ERROR: CULTURE_NICK environment variable is not set", file=sys.stderr)
|
|
194
195
|
sys.exit(1)
|
|
195
|
-
|
|
196
|
-
return os.path.join(runtime_dir, f"culture-{nick}.sock")
|
|
196
|
+
return os.path.join(culture_runtime_dir(), f"culture-{nick}.sock")
|
|
197
197
|
|
|
198
198
|
|
|
199
199
|
def _parse_ask_timeout(remaining: list[str]) -> tuple[int, list[str]]:
|
|
@@ -7,6 +7,7 @@ import glob
|
|
|
7
7
|
import os
|
|
8
8
|
|
|
9
9
|
from culture.bots.config import BOT_CONFIG_FILE
|
|
10
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
10
11
|
from culture.protocol.message import Message as IRCMessage
|
|
11
12
|
|
|
12
13
|
from .model import Agent, BotInfo, MeshState, Message, Room
|
|
@@ -428,8 +429,7 @@ async def _enrich_via_ipc(agents: dict[str, Agent], server_name: str) -> None:
|
|
|
428
429
|
"""Enrich local agents with daemon IPC status data."""
|
|
429
430
|
from culture.clients.claude.ipc import decode_message, encode_message, make_request
|
|
430
431
|
|
|
431
|
-
|
|
432
|
-
socket_pattern = os.path.join(runtime_dir, "culture-*.sock")
|
|
432
|
+
socket_pattern = os.path.join(culture_runtime_dir(), "culture-*.sock")
|
|
433
433
|
|
|
434
434
|
for sock_path in glob.glob(socket_pattern):
|
|
435
435
|
# Extract nick from socket filename: culture-<nick>.sock
|
|
@@ -295,7 +295,18 @@ Unix socket.
|
|
|
295
295
|
$XDG_RUNTIME_DIR/culture-<nick>.sock
|
|
296
296
|
```
|
|
297
297
|
|
|
298
|
-
Falls back to
|
|
298
|
+
Falls back to `~/.culture/run/culture-<nick>.sock` (mode 0700) if
|
|
299
|
+
`XDG_RUNTIME_DIR` is not set — typical on macOS. The fallback is
|
|
300
|
+
user-private rather than world-writable like `/tmp/`.
|
|
301
|
+
|
|
302
|
+
All socket-path resolvers (4 backend daemons, 4 skill irc_clients, the
|
|
303
|
+
CLI in `culture/cli/shared/constants.py::culture_runtime_dir()`, the
|
|
304
|
+
overview collector, and the console status reader) MUST go through
|
|
305
|
+
`culture_runtime_dir()`. A regression test in
|
|
306
|
+
`tests/test_socket_path_convergence.py` parametrically asserts every
|
|
307
|
+
site agrees, with `XDG_RUNTIME_DIR` both set and unset. Any future site
|
|
308
|
+
that re-introduces a raw `os.environ.get("XDG_RUNTIME_DIR", "/tmp")`
|
|
309
|
+
will fail that test (issue #302).
|
|
299
310
|
|
|
300
311
|
### Message Format
|
|
301
312
|
|
|
@@ -250,6 +250,19 @@ culture channel message "#general" "hello from the CLI"
|
|
|
250
250
|
|
|
251
251
|
Uses an ephemeral IRC connection — no daemon required.
|
|
252
252
|
|
|
253
|
+
**Sending under an agent's nick.** Set `CULTURE_NICK=<server>-<agent>` and
|
|
254
|
+
`culture channel message` (along with `list` and `read`) routes through
|
|
255
|
+
the agent daemon's Unix socket so the message appears under the agent's
|
|
256
|
+
real nick instead of an ephemeral peek connection.
|
|
257
|
+
|
|
258
|
+
If `CULTURE_NICK` is set but the daemon's IPC socket is unreachable (or
|
|
259
|
+
the daemon rejects the request), the CLI falls back to the peek path
|
|
260
|
+
*and* prints a stderr warning that names the nick, the socket path, and
|
|
261
|
+
the issue tracker. Treat the warning as actionable: check
|
|
262
|
+
`culture agent status <nick>`, and if the daemon is running, file a bug
|
|
263
|
+
at <https://github.com/agentculture/culture/issues> — a silent fallback
|
|
264
|
+
here masked a macOS path-mismatch bug for two releases (#302).
|
|
265
|
+
|
|
253
266
|
**Multi-line messages.** The message text interprets `\n` as a newline and
|
|
254
267
|
`\t` as a tab, so the shell can pass multi-line input without needing
|
|
255
268
|
`$'...'` quoting. Each line is sent as a separate IRC `PRIVMSG` (required by
|
|
@@ -22,6 +22,7 @@ from typing import Any
|
|
|
22
22
|
|
|
23
23
|
# These imports point to YOUR backend's copies of these files:
|
|
24
24
|
from culture.aio import maybe_await
|
|
25
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
25
26
|
from culture.clients.BACKEND.config import AgentConfig, DaemonConfig
|
|
26
27
|
from culture.clients.BACKEND.ipc import make_response
|
|
27
28
|
from culture.clients.BACKEND.irc_transport import IRCTransport
|
|
@@ -66,7 +67,7 @@ class AgentDaemon:
|
|
|
66
67
|
self.skip_agent = skip_agent
|
|
67
68
|
|
|
68
69
|
self._socket_path = os.path.join(
|
|
69
|
-
socket_dir or
|
|
70
|
+
socket_dir or culture_runtime_dir(),
|
|
70
71
|
f"culture-{agent.nick}.sock",
|
|
71
72
|
)
|
|
72
73
|
|
|
@@ -19,6 +19,7 @@ import os
|
|
|
19
19
|
import sys
|
|
20
20
|
from typing import Any
|
|
21
21
|
|
|
22
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
22
23
|
from culture.clients.BACKEND.ipc import (
|
|
23
24
|
MSG_TYPE_RESPONSE,
|
|
24
25
|
MSG_TYPE_WHISPER,
|
|
@@ -192,8 +193,7 @@ def _sock_path_from_env() -> str:
|
|
|
192
193
|
if not nick:
|
|
193
194
|
print("ERROR: CULTURE_NICK environment variable is not set", file=sys.stderr)
|
|
194
195
|
sys.exit(1)
|
|
195
|
-
|
|
196
|
-
return os.path.join(runtime_dir, f"culture-{nick}.sock")
|
|
196
|
+
return os.path.join(culture_runtime_dir(), f"culture-{nick}.sock")
|
|
197
197
|
|
|
198
198
|
|
|
199
199
|
def _parse_ask_timeout(remaining: list[str]) -> tuple[int, list[str]]:
|
|
@@ -12,6 +12,7 @@ from culture.cli.channel import (
|
|
|
12
12
|
_require_ipc,
|
|
13
13
|
_try_ipc,
|
|
14
14
|
_valid_nick,
|
|
15
|
+
_warn_observer_fallback,
|
|
15
16
|
dispatch,
|
|
16
17
|
register,
|
|
17
18
|
)
|
|
@@ -87,7 +88,8 @@ class TestMessageIpcRouting:
|
|
|
87
88
|
monkeypatch.setenv("CULTURE_NICK", "spark-claude")
|
|
88
89
|
monkeypatch.setenv("XDG_RUNTIME_DIR", tempfile.mkdtemp())
|
|
89
90
|
|
|
90
|
-
# _try_ipc
|
|
91
|
+
# _try_ipc itself stays silent — the warning is emitted by the
|
|
92
|
+
# observer-fallback caller (see TestObserverFallbackWarning).
|
|
91
93
|
result = _try_ipc("irc_send", channel="#general", message="hello")
|
|
92
94
|
assert result is None
|
|
93
95
|
|
|
@@ -98,6 +100,81 @@ class TestMessageIpcRouting:
|
|
|
98
100
|
assert result is None
|
|
99
101
|
|
|
100
102
|
|
|
103
|
+
class TestObserverFallbackWarning:
|
|
104
|
+
"""Issue #302: the three observer-fallback callers must warn loudly.
|
|
105
|
+
|
|
106
|
+
Before the fix, a daemon/CLI socket-path mismatch on macOS caused
|
|
107
|
+
`culture channel message` to silently fall back to an anonymous peek
|
|
108
|
+
connection. The CLI printed `Sent to #general` either way, so the
|
|
109
|
+
bug hid for two releases. The warning must (a) name the nick that
|
|
110
|
+
was attempted, (b) name the operation, and (c) point at the GitHub
|
|
111
|
+
issue tracker so the next reproducer takes seconds to file.
|
|
112
|
+
|
|
113
|
+
The warning lives in `_warn_observer_fallback`, called only by
|
|
114
|
+
`_cmd_message`, `_cmd_list`, and `_cmd_read`. `_topic_read` and the
|
|
115
|
+
`_require_ipc` commands exit on failure instead, so no spurious
|
|
116
|
+
"falling back" notice contradicts their actual error.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def test_warns_when_nick_set_and_daemon_unreachable(self, monkeypatch, capsys):
|
|
120
|
+
"""CULTURE_NICK set + IPC down → stderr warning naming op + nick + issues URL."""
|
|
121
|
+
monkeypatch.setenv("CULTURE_NICK", "spark-claude")
|
|
122
|
+
monkeypatch.setenv("XDG_RUNTIME_DIR", tempfile.mkdtemp())
|
|
123
|
+
|
|
124
|
+
_warn_observer_fallback("channel message")
|
|
125
|
+
|
|
126
|
+
err = capsys.readouterr().err
|
|
127
|
+
assert "spark-claude" in err
|
|
128
|
+
assert "channel message" in err
|
|
129
|
+
assert "Falling back to observer" in err
|
|
130
|
+
assert "https://github.com/agentculture/culture/issues" in err
|
|
131
|
+
|
|
132
|
+
def test_warning_text_is_operation_specific(self, monkeypatch, capsys):
|
|
133
|
+
"""Each caller passes its own operation name; helper renders it verbatim."""
|
|
134
|
+
monkeypatch.setenv("CULTURE_NICK", "spark-claude")
|
|
135
|
+
monkeypatch.setenv("XDG_RUNTIME_DIR", tempfile.mkdtemp())
|
|
136
|
+
|
|
137
|
+
_warn_observer_fallback("channel list")
|
|
138
|
+
err = capsys.readouterr().err
|
|
139
|
+
assert "channel list" in err
|
|
140
|
+
assert "channel message" not in err # no leakage from sibling callers
|
|
141
|
+
|
|
142
|
+
def test_no_warning_when_nick_unset(self, monkeypatch, capsys):
|
|
143
|
+
"""Human use without CULTURE_NICK is the legitimate observer path — no warning."""
|
|
144
|
+
monkeypatch.delenv("CULTURE_NICK", raising=False)
|
|
145
|
+
|
|
146
|
+
_warn_observer_fallback("channel message")
|
|
147
|
+
|
|
148
|
+
assert capsys.readouterr().err == ""
|
|
149
|
+
|
|
150
|
+
def test_no_warning_when_nick_invalid(self, monkeypatch, capsys):
|
|
151
|
+
"""Invalid nick falls into the same human-use bucket — no warning."""
|
|
152
|
+
monkeypatch.setenv("CULTURE_NICK", "nodash")
|
|
153
|
+
|
|
154
|
+
_warn_observer_fallback("channel message")
|
|
155
|
+
|
|
156
|
+
assert capsys.readouterr().err == ""
|
|
157
|
+
|
|
158
|
+
def test_topic_read_does_not_warn(self, monkeypatch, capsys):
|
|
159
|
+
"""_topic_read uses _try_ipc but exits on failure — no fallback, no warning.
|
|
160
|
+
|
|
161
|
+
Regression guard against the Qodo/Copilot review on PR #304: the
|
|
162
|
+
previous design auto-warned inside `_try_ipc` and printed a
|
|
163
|
+
misleading 'falling back' notice for `topic` (which actually exits).
|
|
164
|
+
"""
|
|
165
|
+
from culture.cli.channel import _topic_read
|
|
166
|
+
|
|
167
|
+
monkeypatch.setenv("CULTURE_NICK", "spark-claude")
|
|
168
|
+
monkeypatch.setenv("XDG_RUNTIME_DIR", tempfile.mkdtemp())
|
|
169
|
+
|
|
170
|
+
with pytest.raises(SystemExit):
|
|
171
|
+
_topic_read("#general")
|
|
172
|
+
|
|
173
|
+
err = capsys.readouterr().err
|
|
174
|
+
assert "Falling back" not in err
|
|
175
|
+
assert "topic query requires" in err
|
|
176
|
+
|
|
177
|
+
|
|
101
178
|
class TestNickValidation:
|
|
102
179
|
"""Issue #202 review: CULTURE_NICK must match <server>-<agent> format."""
|
|
103
180
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Unit tests for culture/cli/shared/constants.py.
|
|
2
|
+
|
|
3
|
+
Issue #302 turned `culture_runtime_dir()` into the single source of truth
|
|
4
|
+
for the daemon socket directory. Pin its contract so any future refactor
|
|
5
|
+
that breaks the env-var precedence, fallback path, or 0700 mode is caught
|
|
6
|
+
in CI rather than at runtime on macOS.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import stat
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from culture.cli.shared.constants import culture_runtime_dir
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_uses_xdg_runtime_dir_when_set(monkeypatch, tmp_path):
|
|
19
|
+
"""When XDG_RUNTIME_DIR is set, the value is returned verbatim."""
|
|
20
|
+
monkeypatch.setenv("XDG_RUNTIME_DIR", str(tmp_path))
|
|
21
|
+
assert culture_runtime_dir() == str(tmp_path)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_falls_back_to_culture_run_when_xdg_unset(monkeypatch, tmp_path):
|
|
25
|
+
"""When XDG_RUNTIME_DIR is missing, fall back to ~/.culture/run/.
|
|
26
|
+
|
|
27
|
+
macOS regression: this used to fall back to /tmp in the daemons but to
|
|
28
|
+
~/.culture/run/ in the CLI. The fix converged everyone on the latter.
|
|
29
|
+
"""
|
|
30
|
+
monkeypatch.delenv("XDG_RUNTIME_DIR", raising=False)
|
|
31
|
+
monkeypatch.setenv("HOME", str(tmp_path))
|
|
32
|
+
expected = str(tmp_path / ".culture" / "run")
|
|
33
|
+
assert culture_runtime_dir() == expected
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_creates_fallback_dir_with_user_only_permissions(monkeypatch, tmp_path):
|
|
37
|
+
"""The fallback directory is created mode 0700 (user-private).
|
|
38
|
+
|
|
39
|
+
/tmp would have been world-writable; ~/.culture/run/ is mode 0700 so
|
|
40
|
+
sockets there cannot be observed or hijacked by other local users.
|
|
41
|
+
"""
|
|
42
|
+
monkeypatch.delenv("XDG_RUNTIME_DIR", raising=False)
|
|
43
|
+
monkeypatch.setenv("HOME", str(tmp_path))
|
|
44
|
+
path = Path(culture_runtime_dir())
|
|
45
|
+
assert path.exists()
|
|
46
|
+
assert path.is_dir()
|
|
47
|
+
mode = stat.S_IMODE(os.stat(path).st_mode)
|
|
48
|
+
assert mode == 0o700, f"expected mode 0700, got {oct(mode)}"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_raises_when_home_unresolvable(monkeypatch):
|
|
52
|
+
"""Both XDG_RUNTIME_DIR and HOME unset → RuntimeError, not a literal '~' dir.
|
|
53
|
+
|
|
54
|
+
Qodo flagged that the pre-fix resolver would silently `mkdir` a literal
|
|
55
|
+
`~/.culture/run` in CWD if `os.path.expanduser('~')` could not resolve.
|
|
56
|
+
Now that 9 daemons/skills depend on this resolver, fail loud instead.
|
|
57
|
+
"""
|
|
58
|
+
monkeypatch.delenv("XDG_RUNTIME_DIR", raising=False)
|
|
59
|
+
monkeypatch.delenv("HOME", raising=False)
|
|
60
|
+
# On Linux, expanduser may still consult /etc/passwd via pwd. Force
|
|
61
|
+
# the fallback path by also clearing the user's pwd entry lookup.
|
|
62
|
+
monkeypatch.setattr(os.path, "expanduser", lambda p: p)
|
|
63
|
+
|
|
64
|
+
import pytest
|
|
65
|
+
|
|
66
|
+
with pytest.raises(RuntimeError, match="cannot resolve a home directory"):
|
|
67
|
+
culture_runtime_dir()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_enforces_permissions_on_existing_dir(monkeypatch, tmp_path):
|
|
71
|
+
"""Even if the fallback dir already exists with wrong perms, it's tightened.
|
|
72
|
+
|
|
73
|
+
Defensive: a previous version of culture (or a hand-created dir) may
|
|
74
|
+
have left ~/.culture/run/ at 0755. Re-tighten on every call so the
|
|
75
|
+
invariant always holds at runtime.
|
|
76
|
+
"""
|
|
77
|
+
monkeypatch.delenv("XDG_RUNTIME_DIR", raising=False)
|
|
78
|
+
monkeypatch.setenv("HOME", str(tmp_path))
|
|
79
|
+
pre_existing = tmp_path / ".culture" / "run"
|
|
80
|
+
pre_existing.mkdir(parents=True, mode=0o755)
|
|
81
|
+
os.chmod(pre_existing, 0o755) # noqa: S103 — intentional: test that loose perms get tightened
|
|
82
|
+
|
|
83
|
+
culture_runtime_dir()
|
|
84
|
+
|
|
85
|
+
mode = stat.S_IMODE(os.stat(pre_existing).st_mode)
|
|
86
|
+
assert mode == 0o700
|