agentirc-cli 1.0.0__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/publish.yml +0 -10
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/CHANGELOG.md +15 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/PKG-INFO +2 -2
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/README.md +1 -1
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/agent_runner.py +10 -15
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/daemon.py +20 -10
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/irc_transport.py +6 -6
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/skill/irc_client.py +1 -4
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/agent_runner.py +2 -5
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/daemon.py +17 -9
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/irc_transport.py +6 -6
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/skill/irc_client.py +1 -4
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/agent_runner.py +6 -10
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/daemon.py +17 -9
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/irc_transport.py +6 -6
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/skill/irc_client.py +1 -4
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/agent_runner.py +2 -5
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/daemon.py +17 -9
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/irc_transport.py +6 -6
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/skill/irc_client.py +1 -4
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/ircd.py +5 -2
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/daemon.py +8 -6
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/irc_transport.py +6 -6
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/skill/irc_client.py +1 -4
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/pyproject.toml +1 -1
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/uv.lock +1 -1
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.flake8 +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.gitignore +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.pr_agent.toml +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.pylintrc +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/CLAUDE.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/CNAME +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/Gemfile +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/Gemfile.lock +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/LICENSE +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/SECURITY.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/_config.yml +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/__main__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/bot.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/bot_manager.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/cli.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/socket_server.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/socket_server.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/socket_server.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/credentials.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/learn_prompt.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/mesh_config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/observer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/collector.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/model.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/web/style.css +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/persistence.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/pidfile.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/commands.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/message.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/replies.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/__main__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/channel.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/client.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/remote_client.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/room_store.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/server_link.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skill.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/history.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/rooms.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/threads.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/thread_store.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/SECURITY.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/agent-client.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/agent-harness-spec.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/bots.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/ci.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/cli.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/codex-backend.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/copilot-backend.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/docs-site.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/getting-started.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/grow-your-agent.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/harness-conformance.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer1-core-irc.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer2-attention.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer3-skills.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer4-federation.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer5-agent-harness.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/ops-tooling.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/overview.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/publishing.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/rooms.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/server-architecture.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/threads.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/10-grow-your-agent.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases-index.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/index.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/sonar-project.properties +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/__init__.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/conftest.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_acp_daemon.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bot.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bot_config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_channel.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_connection.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_daemon.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_discovery.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_federation.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_history.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_http_listener.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_ipc.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_mentions.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_message.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_messaging.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_modes.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_model.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_web.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_persistence.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_rooms.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_skill_client.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_skills.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_socket_server.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_supervisor.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_template_engine.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_threads.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_webhook.py +0 -0
|
@@ -55,7 +55,6 @@ jobs:
|
|
|
55
55
|
echo "Publishing ${DEV_VERSION} to TestPyPI"
|
|
56
56
|
|
|
57
57
|
- name: Build and publish culture to TestPyPI
|
|
58
|
-
continue-on-error: true
|
|
59
58
|
run: |
|
|
60
59
|
uv build
|
|
61
60
|
uv publish --publish-url https://test.pypi.org/legacy/ --trusted-publishing always --check-url https://test.pypi.org/simple/
|
|
@@ -100,7 +99,6 @@ jobs:
|
|
|
100
99
|
- run: uv sync
|
|
101
100
|
|
|
102
101
|
- name: Build and publish culture to PyPI
|
|
103
|
-
continue-on-error: true
|
|
104
102
|
run: |
|
|
105
103
|
uv build
|
|
106
104
|
uv publish --trusted-publishing always --check-url https://pypi.org/simple/
|
|
@@ -112,11 +110,3 @@ jobs:
|
|
|
112
110
|
rm -rf dist
|
|
113
111
|
uv build
|
|
114
112
|
uv publish --trusted-publishing always --check-url https://pypi.org/simple/
|
|
115
|
-
|
|
116
|
-
- name: Build and publish agentirc alias to PyPI
|
|
117
|
-
run: |
|
|
118
|
-
sed -i 's/^name = "agentirc-cli"/name = "agentirc"/' pyproject.toml
|
|
119
|
-
sed -i 's/^name = "culture"/name = "agentirc"/' pyproject.toml
|
|
120
|
-
rm -rf dist
|
|
121
|
-
uv build
|
|
122
|
-
uv publish --trusted-publishing always --check-url https://pypi.org/simple/
|
|
@@ -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
|
+
## [1.0.2] - 2026-04-05
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Re-raise asyncio.CancelledError after cleanup to fix cancellation propagation (SonarCloud S7497)
|
|
13
|
+
- Save asyncio.create_task() results to prevent garbage collection (SonarCloud S7502)
|
|
14
|
+
|
|
15
|
+
## [1.0.1] - 2026-04-05
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Remove agentirc legacy alias from production PyPI publish pipeline
|
|
21
|
+
|
|
7
22
|
## [1.0.0] - 2026-04-05
|
|
8
23
|
|
|
9
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentirc-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Legacy alias for culture — install culture instead
|
|
5
5
|
Project-URL: Homepage, https://github.com/OriNachum/culture
|
|
6
6
|
Author: Ori Nachum
|
|
@@ -46,7 +46,7 @@ Claude Code · Codex · Copilot · ACP (Cline, Kiro, OpenCode, Gemini, ...)
|
|
|
46
46
|
<br><br>
|
|
47
47
|
<sub>If you find Culture useful, <a href="https://github.com/OriNachum/culture/stargazers">give it a ⭐</a> — it helps others discover the project.</sub>
|
|
48
48
|
|
|
49
|
-
<img width="800" alt="Culture" src="https://github.com/user-attachments/assets/
|
|
49
|
+
<img width="800" alt="Culture" src="https://github.com/user-attachments/assets/e8e589d2-eb04-47cc-9ae3-5a98d750e36c" />
|
|
50
50
|
|
|
51
51
|
</div>
|
|
52
52
|
|
|
@@ -23,7 +23,7 @@ Claude Code · Codex · Copilot · ACP (Cline, Kiro, OpenCode, Gemini, ...)
|
|
|
23
23
|
<br><br>
|
|
24
24
|
<sub>If you find Culture useful, <a href="https://github.com/OriNachum/culture/stargazers">give it a ⭐</a> — it helps others discover the project.</sub>
|
|
25
25
|
|
|
26
|
-
<img width="800" alt="Culture" src="https://github.com/user-attachments/assets/
|
|
26
|
+
<img width="800" alt="Culture" src="https://github.com/user-attachments/assets/e8e589d2-eb04-47cc-9ae3-5a98d750e36c" />
|
|
27
27
|
|
|
28
28
|
</div>
|
|
29
29
|
|
|
@@ -141,24 +141,15 @@ class ACPAgentRunner:
|
|
|
141
141
|
|
|
142
142
|
if self._task:
|
|
143
143
|
self._task.cancel()
|
|
144
|
-
|
|
145
|
-
await self._task
|
|
146
|
-
except asyncio.CancelledError:
|
|
147
|
-
pass
|
|
144
|
+
await asyncio.gather(self._task, return_exceptions=True)
|
|
148
145
|
|
|
149
146
|
if self._reader_task:
|
|
150
147
|
self._reader_task.cancel()
|
|
151
|
-
|
|
152
|
-
await self._reader_task
|
|
153
|
-
except asyncio.CancelledError:
|
|
154
|
-
pass
|
|
148
|
+
await asyncio.gather(self._reader_task, return_exceptions=True)
|
|
155
149
|
|
|
156
150
|
if self._stderr_task:
|
|
157
151
|
self._stderr_task.cancel()
|
|
158
|
-
|
|
159
|
-
await self._stderr_task
|
|
160
|
-
except asyncio.CancelledError:
|
|
161
|
-
pass
|
|
152
|
+
await asyncio.gather(self._stderr_task, return_exceptions=True)
|
|
162
153
|
|
|
163
154
|
if self._process:
|
|
164
155
|
try:
|
|
@@ -250,7 +241,9 @@ class ACPAgentRunner:
|
|
|
250
241
|
elif "method" in msg:
|
|
251
242
|
await self._handle_notification(msg)
|
|
252
243
|
|
|
253
|
-
except
|
|
244
|
+
except asyncio.CancelledError:
|
|
245
|
+
raise
|
|
246
|
+
except ConnectionError:
|
|
254
247
|
pass
|
|
255
248
|
except Exception:
|
|
256
249
|
logger.exception("ACP read loop error")
|
|
@@ -295,7 +288,9 @@ class ACPAgentRunner:
|
|
|
295
288
|
text = line.decode("utf-8", errors="replace").rstrip()
|
|
296
289
|
if text:
|
|
297
290
|
logger.warning("acp[%s] stderr: %s", cmd_name, text)
|
|
298
|
-
except
|
|
291
|
+
except asyncio.CancelledError:
|
|
292
|
+
raise
|
|
293
|
+
except ConnectionError:
|
|
299
294
|
pass
|
|
300
295
|
|
|
301
296
|
async def _handle_notification(self, msg: dict) -> None:
|
|
@@ -381,4 +376,4 @@ class ACPAgentRunner:
|
|
|
381
376
|
logger.exception("ACP turn error")
|
|
382
377
|
|
|
383
378
|
except asyncio.CancelledError:
|
|
384
|
-
|
|
379
|
+
raise
|
|
@@ -82,6 +82,9 @@ class ACPDaemon:
|
|
|
82
82
|
self._stop_event: asyncio.Event | None = None
|
|
83
83
|
self._pid_name: str = ""
|
|
84
84
|
|
|
85
|
+
# Background task tracking (prevent GC of fire-and-forget tasks)
|
|
86
|
+
self._background_tasks: set[asyncio.Task] = set()
|
|
87
|
+
|
|
85
88
|
# ------------------------------------------------------------------
|
|
86
89
|
# Lifecycle
|
|
87
90
|
# ------------------------------------------------------------------
|
|
@@ -150,7 +153,9 @@ class ACPDaemon:
|
|
|
150
153
|
)
|
|
151
154
|
self._agent_runner = None
|
|
152
155
|
self._crash_times.append(time.time())
|
|
153
|
-
asyncio.create_task(self._delayed_restart())
|
|
156
|
+
task = asyncio.create_task(self._delayed_restart())
|
|
157
|
+
self._background_tasks.add(task)
|
|
158
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
154
159
|
|
|
155
160
|
# 7. Sleep scheduler background task
|
|
156
161
|
self._sleep_task = asyncio.create_task(self._sleep_scheduler())
|
|
@@ -166,10 +171,7 @@ class ACPDaemon:
|
|
|
166
171
|
"""Cleanly shut down all components."""
|
|
167
172
|
if hasattr(self, "_sleep_task") and self._sleep_task:
|
|
168
173
|
self._sleep_task.cancel()
|
|
169
|
-
|
|
170
|
-
await self._sleep_task
|
|
171
|
-
except asyncio.CancelledError:
|
|
172
|
-
pass
|
|
174
|
+
await asyncio.gather(self._sleep_task, return_exceptions=True)
|
|
173
175
|
self._sleep_task = None
|
|
174
176
|
|
|
175
177
|
if self._agent_runner is not None:
|
|
@@ -236,7 +238,7 @@ class ACPDaemon:
|
|
|
236
238
|
self._paused = False
|
|
237
239
|
logger.info("Sleep schedule: resuming %s", self.agent.nick)
|
|
238
240
|
except asyncio.CancelledError:
|
|
239
|
-
|
|
241
|
+
raise
|
|
240
242
|
except Exception:
|
|
241
243
|
logger.exception("Sleep scheduler error")
|
|
242
244
|
|
|
@@ -303,11 +305,15 @@ class ACPDaemon:
|
|
|
303
305
|
prompt = f"[IRC @mention in {target}] <{sender}> {text}"
|
|
304
306
|
else:
|
|
305
307
|
prompt = f"[IRC DM] <{sender}> {text}"
|
|
306
|
-
asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
308
|
+
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
309
|
+
self._background_tasks.add(task)
|
|
310
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
307
311
|
|
|
308
312
|
def _on_roominvite(self, channel: str, meta_text: str) -> None:
|
|
309
313
|
"""Called by IRCTransport when a ROOMINVITE is received."""
|
|
310
|
-
asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
314
|
+
task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
315
|
+
self._background_tasks.add(task)
|
|
316
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
311
317
|
|
|
312
318
|
async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
|
|
313
319
|
"""Evaluate a room invitation using the agent's LLM."""
|
|
@@ -457,7 +463,9 @@ class ACPDaemon:
|
|
|
457
463
|
len(self._crash_times),
|
|
458
464
|
MAX_CRASH_COUNT,
|
|
459
465
|
)
|
|
460
|
-
asyncio.create_task(self._delayed_restart())
|
|
466
|
+
task = asyncio.create_task(self._delayed_restart())
|
|
467
|
+
self._background_tasks.add(task)
|
|
468
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
461
469
|
|
|
462
470
|
async def _delayed_restart(self) -> None:
|
|
463
471
|
await asyncio.sleep(CRASH_RESTART_DELAY)
|
|
@@ -554,7 +562,9 @@ class ACPDaemon:
|
|
|
554
562
|
return await self._ipc_irc_thread_read(req_id, msg)
|
|
555
563
|
|
|
556
564
|
elif msg_type == "shutdown":
|
|
557
|
-
asyncio.create_task(self._graceful_shutdown())
|
|
565
|
+
task = asyncio.create_task(self._graceful_shutdown())
|
|
566
|
+
self._background_tasks.add(task)
|
|
567
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
558
568
|
return make_response(req_id, ok=True)
|
|
559
569
|
|
|
560
570
|
else:
|
|
@@ -40,6 +40,7 @@ class IRCTransport:
|
|
|
40
40
|
self._read_task: asyncio.Task | None = None
|
|
41
41
|
self._reconnecting = False
|
|
42
42
|
self._should_run = False
|
|
43
|
+
self._background_tasks: set[asyncio.Task] = set()
|
|
43
44
|
|
|
44
45
|
async def connect(self) -> None:
|
|
45
46
|
self._should_run = True
|
|
@@ -61,10 +62,7 @@ class IRCTransport:
|
|
|
61
62
|
self._should_run = False
|
|
62
63
|
if self._read_task:
|
|
63
64
|
self._read_task.cancel()
|
|
64
|
-
|
|
65
|
-
await self._read_task
|
|
66
|
-
except asyncio.CancelledError:
|
|
67
|
-
pass
|
|
65
|
+
await asyncio.gather(self._read_task, return_exceptions=True)
|
|
68
66
|
if self._writer:
|
|
69
67
|
try:
|
|
70
68
|
await self._send_raw("QUIT :daemon shutdown")
|
|
@@ -129,13 +127,15 @@ class IRCTransport:
|
|
|
129
127
|
msg = Message.parse(line)
|
|
130
128
|
await self._handle(msg)
|
|
131
129
|
except asyncio.CancelledError:
|
|
132
|
-
|
|
130
|
+
raise
|
|
133
131
|
except (ConnectionError, OSError):
|
|
134
132
|
logger.warning("IRC connection lost")
|
|
135
133
|
finally:
|
|
136
134
|
self.connected = False
|
|
137
135
|
if self._should_run and not self._reconnecting:
|
|
138
|
-
asyncio.create_task(self._reconnect())
|
|
136
|
+
task = asyncio.create_task(self._reconnect())
|
|
137
|
+
self._background_tasks.add(task)
|
|
138
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
139
139
|
|
|
140
140
|
async def _reconnect(self) -> None:
|
|
141
141
|
self._reconnecting = True
|
|
@@ -49,10 +49,7 @@ class SkillClient:
|
|
|
49
49
|
"""Close the connection and cancel the background reader."""
|
|
50
50
|
if self._read_task is not None:
|
|
51
51
|
self._read_task.cancel()
|
|
52
|
-
|
|
53
|
-
await self._read_task
|
|
54
|
-
except asyncio.CancelledError:
|
|
55
|
-
pass
|
|
52
|
+
await asyncio.gather(self._read_task, return_exceptions=True)
|
|
56
53
|
self._read_task = None
|
|
57
54
|
|
|
58
55
|
if self._writer is not None:
|
|
@@ -84,10 +84,7 @@ class AgentRunner:
|
|
|
84
84
|
await asyncio.wait_for(asyncio.shield(self._task), timeout=5.0)
|
|
85
85
|
except (asyncio.TimeoutError, asyncio.CancelledError):
|
|
86
86
|
self._task.cancel()
|
|
87
|
-
|
|
88
|
-
await self._task
|
|
89
|
-
except asyncio.CancelledError:
|
|
90
|
-
pass
|
|
87
|
+
await asyncio.gather(self._task, return_exceptions=True)
|
|
91
88
|
self._task = None
|
|
92
89
|
|
|
93
90
|
def is_running(self) -> bool:
|
|
@@ -149,7 +146,7 @@ class AgentRunner:
|
|
|
149
146
|
return
|
|
150
147
|
|
|
151
148
|
except asyncio.CancelledError:
|
|
152
|
-
|
|
149
|
+
raise
|
|
153
150
|
|
|
154
151
|
# Loop exited normally (stopping flag set)
|
|
155
152
|
if self.on_exit:
|
|
@@ -63,6 +63,9 @@ class AgentDaemon:
|
|
|
63
63
|
self._status_query_response: str = ""
|
|
64
64
|
self._last_activity_text: str = ""
|
|
65
65
|
|
|
66
|
+
# Background tasks (prevent GC of fire-and-forget tasks)
|
|
67
|
+
self._background_tasks: set[asyncio.Task] = set()
|
|
68
|
+
|
|
66
69
|
# Graceful shutdown
|
|
67
70
|
self._stop_event: asyncio.Event | None = None
|
|
68
71
|
self._pid_name: str = ""
|
|
@@ -134,10 +137,7 @@ class AgentDaemon:
|
|
|
134
137
|
"""Cleanly shut down all components."""
|
|
135
138
|
if hasattr(self, "_sleep_task") and self._sleep_task:
|
|
136
139
|
self._sleep_task.cancel()
|
|
137
|
-
|
|
138
|
-
await self._sleep_task
|
|
139
|
-
except asyncio.CancelledError:
|
|
140
|
-
pass
|
|
140
|
+
await asyncio.gather(self._sleep_task, return_exceptions=True)
|
|
141
141
|
self._sleep_task = None
|
|
142
142
|
|
|
143
143
|
if self._agent_runner is not None:
|
|
@@ -204,7 +204,7 @@ class AgentDaemon:
|
|
|
204
204
|
self._paused = False
|
|
205
205
|
logger.info("Sleep schedule: resuming %s", self.agent.nick)
|
|
206
206
|
except asyncio.CancelledError:
|
|
207
|
-
|
|
207
|
+
raise
|
|
208
208
|
except Exception:
|
|
209
209
|
logger.exception("Sleep scheduler error")
|
|
210
210
|
|
|
@@ -262,11 +262,15 @@ class AgentDaemon:
|
|
|
262
262
|
prompt = f"[IRC @mention in {target}] <{sender}> {text}"
|
|
263
263
|
else:
|
|
264
264
|
prompt = f"[IRC DM] <{sender}> {text}"
|
|
265
|
-
asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
265
|
+
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
266
|
+
self._background_tasks.add(task)
|
|
267
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
266
268
|
|
|
267
269
|
def _on_roominvite(self, channel: str, meta_text: str) -> None:
|
|
268
270
|
"""Called by IRCTransport when a ROOMINVITE is received."""
|
|
269
|
-
asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
271
|
+
task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
272
|
+
self._background_tasks.add(task)
|
|
273
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
270
274
|
|
|
271
275
|
async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
|
|
272
276
|
"""Evaluate a room invitation using the agent's LLM."""
|
|
@@ -403,7 +407,9 @@ class AgentDaemon:
|
|
|
403
407
|
len(self._crash_times),
|
|
404
408
|
MAX_CRASH_COUNT,
|
|
405
409
|
)
|
|
406
|
-
asyncio.create_task(self._delayed_restart())
|
|
410
|
+
task = asyncio.create_task(self._delayed_restart())
|
|
411
|
+
self._background_tasks.add(task)
|
|
412
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
407
413
|
|
|
408
414
|
async def _delayed_restart(self) -> None:
|
|
409
415
|
await asyncio.sleep(CRASH_RESTART_DELAY)
|
|
@@ -492,7 +498,9 @@ class AgentDaemon:
|
|
|
492
498
|
return await self._ipc_irc_thread_read(req_id, msg)
|
|
493
499
|
|
|
494
500
|
elif msg_type == "shutdown":
|
|
495
|
-
asyncio.create_task(self._graceful_shutdown())
|
|
501
|
+
task = asyncio.create_task(self._graceful_shutdown())
|
|
502
|
+
self._background_tasks.add(task)
|
|
503
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
496
504
|
return make_response(req_id, ok=True)
|
|
497
505
|
|
|
498
506
|
else:
|
|
@@ -40,6 +40,7 @@ class IRCTransport:
|
|
|
40
40
|
self._read_task: asyncio.Task | None = None
|
|
41
41
|
self._reconnecting = False
|
|
42
42
|
self._should_run = False
|
|
43
|
+
self._background_tasks: set[asyncio.Task] = set()
|
|
43
44
|
|
|
44
45
|
async def connect(self) -> None:
|
|
45
46
|
self._should_run = True
|
|
@@ -61,10 +62,7 @@ class IRCTransport:
|
|
|
61
62
|
self._should_run = False
|
|
62
63
|
if self._read_task:
|
|
63
64
|
self._read_task.cancel()
|
|
64
|
-
|
|
65
|
-
await self._read_task
|
|
66
|
-
except asyncio.CancelledError:
|
|
67
|
-
pass
|
|
65
|
+
await asyncio.gather(self._read_task, return_exceptions=True)
|
|
68
66
|
if self._writer:
|
|
69
67
|
try:
|
|
70
68
|
await self._send_raw("QUIT :daemon shutdown")
|
|
@@ -129,13 +127,15 @@ class IRCTransport:
|
|
|
129
127
|
msg = Message.parse(line)
|
|
130
128
|
await self._handle(msg)
|
|
131
129
|
except asyncio.CancelledError:
|
|
132
|
-
|
|
130
|
+
raise
|
|
133
131
|
except (ConnectionError, OSError):
|
|
134
132
|
logger.warning("IRC connection lost")
|
|
135
133
|
finally:
|
|
136
134
|
self.connected = False
|
|
137
135
|
if self._should_run and not self._reconnecting:
|
|
138
|
-
asyncio.create_task(self._reconnect())
|
|
136
|
+
task = asyncio.create_task(self._reconnect())
|
|
137
|
+
self._background_tasks.add(task)
|
|
138
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
139
139
|
|
|
140
140
|
async def _reconnect(self) -> None:
|
|
141
141
|
self._reconnecting = True
|
|
@@ -49,10 +49,7 @@ class SkillClient:
|
|
|
49
49
|
"""Close the connection and cancel the background reader."""
|
|
50
50
|
if self._read_task is not None:
|
|
51
51
|
self._read_task.cancel()
|
|
52
|
-
|
|
53
|
-
await self._read_task
|
|
54
|
-
except asyncio.CancelledError:
|
|
55
|
-
pass
|
|
52
|
+
await asyncio.gather(self._read_task, return_exceptions=True)
|
|
56
53
|
self._read_task = None
|
|
57
54
|
|
|
58
55
|
if self._writer is not None:
|
|
@@ -118,17 +118,11 @@ class CodexAgentRunner:
|
|
|
118
118
|
|
|
119
119
|
if self._task:
|
|
120
120
|
self._task.cancel()
|
|
121
|
-
|
|
122
|
-
await self._task
|
|
123
|
-
except asyncio.CancelledError:
|
|
124
|
-
pass
|
|
121
|
+
await asyncio.gather(self._task, return_exceptions=True)
|
|
125
122
|
|
|
126
123
|
if self._reader_task:
|
|
127
124
|
self._reader_task.cancel()
|
|
128
|
-
|
|
129
|
-
await self._reader_task
|
|
130
|
-
except asyncio.CancelledError:
|
|
131
|
-
pass
|
|
125
|
+
await asyncio.gather(self._reader_task, return_exceptions=True)
|
|
132
126
|
|
|
133
127
|
if self._process:
|
|
134
128
|
try:
|
|
@@ -220,7 +214,9 @@ class CodexAgentRunner:
|
|
|
220
214
|
elif "method" in msg:
|
|
221
215
|
await self._handle_notification(msg)
|
|
222
216
|
|
|
223
|
-
except
|
|
217
|
+
except asyncio.CancelledError:
|
|
218
|
+
raise
|
|
219
|
+
except ConnectionError:
|
|
224
220
|
pass
|
|
225
221
|
except Exception:
|
|
226
222
|
logger.exception("Codex read loop error")
|
|
@@ -331,4 +327,4 @@ class CodexAgentRunner:
|
|
|
331
327
|
logger.exception("Codex turn error")
|
|
332
328
|
|
|
333
329
|
except asyncio.CancelledError:
|
|
334
|
-
|
|
330
|
+
raise
|
|
@@ -79,6 +79,9 @@ class CodexDaemon:
|
|
|
79
79
|
self._stop_event: asyncio.Event | None = None
|
|
80
80
|
self._pid_name: str = ""
|
|
81
81
|
|
|
82
|
+
# Background task tracking (prevent GC of fire-and-forget tasks)
|
|
83
|
+
self._background_tasks: set[asyncio.Task] = set()
|
|
84
|
+
|
|
82
85
|
# ------------------------------------------------------------------
|
|
83
86
|
# Lifecycle
|
|
84
87
|
# ------------------------------------------------------------------
|
|
@@ -143,10 +146,7 @@ class CodexDaemon:
|
|
|
143
146
|
"""Cleanly shut down all components."""
|
|
144
147
|
if hasattr(self, "_sleep_task") and self._sleep_task:
|
|
145
148
|
self._sleep_task.cancel()
|
|
146
|
-
|
|
147
|
-
await self._sleep_task
|
|
148
|
-
except asyncio.CancelledError:
|
|
149
|
-
pass
|
|
149
|
+
await asyncio.gather(self._sleep_task, return_exceptions=True)
|
|
150
150
|
self._sleep_task = None
|
|
151
151
|
|
|
152
152
|
if self._agent_runner is not None:
|
|
@@ -213,7 +213,7 @@ class CodexDaemon:
|
|
|
213
213
|
self._paused = False
|
|
214
214
|
logger.info("Sleep schedule: resuming %s", self.agent.nick)
|
|
215
215
|
except asyncio.CancelledError:
|
|
216
|
-
|
|
216
|
+
raise
|
|
217
217
|
except Exception:
|
|
218
218
|
logger.exception("Sleep scheduler error")
|
|
219
219
|
|
|
@@ -273,11 +273,15 @@ class CodexDaemon:
|
|
|
273
273
|
prompt = f"[IRC @mention in {target}] <{sender}> {text}"
|
|
274
274
|
else:
|
|
275
275
|
prompt = f"[IRC DM] <{sender}> {text}"
|
|
276
|
-
asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
276
|
+
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
277
|
+
self._background_tasks.add(task)
|
|
278
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
277
279
|
|
|
278
280
|
def _on_roominvite(self, channel: str, meta_text: str) -> None:
|
|
279
281
|
"""Called by IRCTransport when a ROOMINVITE is received."""
|
|
280
|
-
asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
282
|
+
task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
283
|
+
self._background_tasks.add(task)
|
|
284
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
281
285
|
|
|
282
286
|
async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
|
|
283
287
|
"""Evaluate a room invitation using the agent's LLM."""
|
|
@@ -427,7 +431,9 @@ class CodexDaemon:
|
|
|
427
431
|
len(self._crash_times),
|
|
428
432
|
MAX_CRASH_COUNT,
|
|
429
433
|
)
|
|
430
|
-
asyncio.create_task(self._delayed_restart())
|
|
434
|
+
task = asyncio.create_task(self._delayed_restart())
|
|
435
|
+
self._background_tasks.add(task)
|
|
436
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
431
437
|
|
|
432
438
|
async def _delayed_restart(self) -> None:
|
|
433
439
|
await asyncio.sleep(CRASH_RESTART_DELAY)
|
|
@@ -516,7 +522,9 @@ class CodexDaemon:
|
|
|
516
522
|
return await self._ipc_irc_thread_read(req_id, msg)
|
|
517
523
|
|
|
518
524
|
elif msg_type == "shutdown":
|
|
519
|
-
asyncio.create_task(self._graceful_shutdown())
|
|
525
|
+
task = asyncio.create_task(self._graceful_shutdown())
|
|
526
|
+
self._background_tasks.add(task)
|
|
527
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
520
528
|
return make_response(req_id, ok=True)
|
|
521
529
|
|
|
522
530
|
else:
|
|
@@ -40,6 +40,7 @@ class IRCTransport:
|
|
|
40
40
|
self._read_task: asyncio.Task | None = None
|
|
41
41
|
self._reconnecting = False
|
|
42
42
|
self._should_run = False
|
|
43
|
+
self._background_tasks: set[asyncio.Task] = set()
|
|
43
44
|
|
|
44
45
|
async def connect(self) -> None:
|
|
45
46
|
self._should_run = True
|
|
@@ -61,10 +62,7 @@ class IRCTransport:
|
|
|
61
62
|
self._should_run = False
|
|
62
63
|
if self._read_task:
|
|
63
64
|
self._read_task.cancel()
|
|
64
|
-
|
|
65
|
-
await self._read_task
|
|
66
|
-
except asyncio.CancelledError:
|
|
67
|
-
pass
|
|
65
|
+
await asyncio.gather(self._read_task, return_exceptions=True)
|
|
68
66
|
if self._writer:
|
|
69
67
|
try:
|
|
70
68
|
await self._send_raw("QUIT :daemon shutdown")
|
|
@@ -129,13 +127,15 @@ class IRCTransport:
|
|
|
129
127
|
msg = Message.parse(line)
|
|
130
128
|
await self._handle(msg)
|
|
131
129
|
except asyncio.CancelledError:
|
|
132
|
-
|
|
130
|
+
raise
|
|
133
131
|
except (ConnectionError, OSError):
|
|
134
132
|
logger.warning("IRC connection lost")
|
|
135
133
|
finally:
|
|
136
134
|
self.connected = False
|
|
137
135
|
if self._should_run and not self._reconnecting:
|
|
138
|
-
asyncio.create_task(self._reconnect())
|
|
136
|
+
task = asyncio.create_task(self._reconnect())
|
|
137
|
+
self._background_tasks.add(task)
|
|
138
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
139
139
|
|
|
140
140
|
async def _reconnect(self) -> None:
|
|
141
141
|
self._reconnecting = True
|
|
@@ -49,10 +49,7 @@ class SkillClient:
|
|
|
49
49
|
"""Close the connection and cancel the background reader."""
|
|
50
50
|
if self._read_task is not None:
|
|
51
51
|
self._read_task.cancel()
|
|
52
|
-
|
|
53
|
-
await self._read_task
|
|
54
|
-
except asyncio.CancelledError:
|
|
55
|
-
pass
|
|
52
|
+
await asyncio.gather(self._read_task, return_exceptions=True)
|
|
56
53
|
self._read_task = None
|
|
57
54
|
|
|
58
55
|
if self._writer is not None:
|
|
@@ -107,10 +107,7 @@ class CopilotAgentRunner:
|
|
|
107
107
|
|
|
108
108
|
if self._task:
|
|
109
109
|
self._task.cancel()
|
|
110
|
-
|
|
111
|
-
await self._task
|
|
112
|
-
except asyncio.CancelledError:
|
|
113
|
-
pass
|
|
110
|
+
await asyncio.gather(self._task, return_exceptions=True)
|
|
114
111
|
self._task = None
|
|
115
112
|
|
|
116
113
|
if self._session:
|
|
@@ -175,7 +172,7 @@ class CopilotAgentRunner:
|
|
|
175
172
|
return
|
|
176
173
|
|
|
177
174
|
except asyncio.CancelledError:
|
|
178
|
-
|
|
175
|
+
raise
|
|
179
176
|
|
|
180
177
|
if not self._stopping and self.on_exit:
|
|
181
178
|
await self.on_exit(0)
|
|
@@ -75,6 +75,9 @@ class CopilotDaemon:
|
|
|
75
75
|
self._status_query_response: str = ""
|
|
76
76
|
self._last_activity_text: str = ""
|
|
77
77
|
|
|
78
|
+
# Background tasks (prevent GC of fire-and-forget tasks)
|
|
79
|
+
self._background_tasks: set[asyncio.Task] = set()
|
|
80
|
+
|
|
78
81
|
# Graceful shutdown
|
|
79
82
|
self._stop_event: asyncio.Event | None = None
|
|
80
83
|
self._pid_name: str = ""
|
|
@@ -143,10 +146,7 @@ class CopilotDaemon:
|
|
|
143
146
|
"""Cleanly shut down all components."""
|
|
144
147
|
if hasattr(self, "_sleep_task") and self._sleep_task:
|
|
145
148
|
self._sleep_task.cancel()
|
|
146
|
-
|
|
147
|
-
await self._sleep_task
|
|
148
|
-
except asyncio.CancelledError:
|
|
149
|
-
pass
|
|
149
|
+
await asyncio.gather(self._sleep_task, return_exceptions=True)
|
|
150
150
|
self._sleep_task = None
|
|
151
151
|
|
|
152
152
|
if self._agent_runner is not None:
|
|
@@ -213,7 +213,7 @@ class CopilotDaemon:
|
|
|
213
213
|
self._paused = False
|
|
214
214
|
logger.info("Sleep schedule: resuming %s", self.agent.nick)
|
|
215
215
|
except asyncio.CancelledError:
|
|
216
|
-
|
|
216
|
+
raise
|
|
217
217
|
except Exception:
|
|
218
218
|
logger.exception("Sleep scheduler error")
|
|
219
219
|
|
|
@@ -280,11 +280,15 @@ class CopilotDaemon:
|
|
|
280
280
|
prompt = f"[IRC @mention in {target}] <{sender}> {text}"
|
|
281
281
|
else:
|
|
282
282
|
prompt = f"[IRC DM] <{sender}> {text}"
|
|
283
|
-
asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
283
|
+
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
284
|
+
self._background_tasks.add(task)
|
|
285
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
284
286
|
|
|
285
287
|
def _on_roominvite(self, channel: str, meta_text: str) -> None:
|
|
286
288
|
"""Called by IRCTransport when a ROOMINVITE is received."""
|
|
287
|
-
asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
289
|
+
task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
|
|
290
|
+
self._background_tasks.add(task)
|
|
291
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
288
292
|
|
|
289
293
|
async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
|
|
290
294
|
"""Evaluate a room invitation using the agent's LLM."""
|
|
@@ -434,7 +438,9 @@ class CopilotDaemon:
|
|
|
434
438
|
len(self._crash_times),
|
|
435
439
|
MAX_CRASH_COUNT,
|
|
436
440
|
)
|
|
437
|
-
asyncio.create_task(self._delayed_restart())
|
|
441
|
+
task = asyncio.create_task(self._delayed_restart())
|
|
442
|
+
self._background_tasks.add(task)
|
|
443
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
438
444
|
|
|
439
445
|
async def _delayed_restart(self) -> None:
|
|
440
446
|
await asyncio.sleep(CRASH_RESTART_DELAY)
|
|
@@ -523,7 +529,9 @@ class CopilotDaemon:
|
|
|
523
529
|
return await self._ipc_irc_thread_read(req_id, msg)
|
|
524
530
|
|
|
525
531
|
elif msg_type == "shutdown":
|
|
526
|
-
asyncio.create_task(self._graceful_shutdown())
|
|
532
|
+
task = asyncio.create_task(self._graceful_shutdown())
|
|
533
|
+
self._background_tasks.add(task)
|
|
534
|
+
task.add_done_callback(self._background_tasks.discard)
|
|
527
535
|
return make_response(req_id, ok=True)
|
|
528
536
|
|
|
529
537
|
else:
|