agentirc-cli 0.10.6__tar.gz → 0.11.0__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-0.11.0/.claude/skills/pr-review/SKILL.md +184 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/CHANGELOG.md +24 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/PKG-INFO +1 -1
- agentirc_cli-0.11.0/agentirc/__init__.py +1 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/cli.py +197 -32
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/config.py +4 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/daemon.py +100 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/irc_transport.py +12 -2
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/irc_transport.py +7 -1
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/irc_transport.py +7 -1
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/irc_transport.py +7 -1
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/observer.py +23 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/cli.md +46 -1
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/irc_transport.py +7 -1
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/pyproject.toml +1 -1
- agentirc_cli-0.11.0/tests/test_daemon_ipc.py +81 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_irc_transport.py +48 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/uv.lock +1 -1
- agentirc_cli-0.10.6/agentirc/__init__.py +0 -1
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/.gitignore +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/.pr_agent.toml +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/CLAUDE.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/CNAME +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/Gemfile +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/Gemfile.lock +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/LICENSE +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/README.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/_config.yml +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/__main__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/ipc.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/socket_server.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/supervisor.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/claude/webhook.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/config.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/ipc.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/socket_server.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/supervisor.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/codex/webhook.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/config.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/ipc.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/skill/irc_client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/copilot/webhook.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/agent_runner.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/config.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/ipc.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/message_buffer.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/skill/SKILL.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/skill/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/skill/irc_client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/socket_server.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/supervisor.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/clients/opencode/webhook.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/pidfile.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/protocol/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/protocol/commands.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/protocol/extensions/federation.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/protocol/extensions/history.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/protocol/message.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/protocol/protocol-index.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/protocol/replies.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/__main__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/channel.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/config.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/ircd.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/remote_client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/server_link.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/skill.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/skills/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/agentirc/server/skills/history.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/agent-client.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/agent-harness-spec.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/ci.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/opencode/configuration.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/opencode/context-management.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/opencode/irc-tools.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/opencode/overview.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/opencode/setup.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/opencode/supervisor.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/clients/opencode/webhooks.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/codex-backend.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/copilot-backend.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/design.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/docs-site.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/getting-started.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/grow-your-agent.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/layer1-core-irc.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/layer2-attention.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/layer3-skills.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/layer4-federation.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/layer5-agent-harness.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/opencode-backend.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/publishing.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/server-architecture.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases/10-grow-your-agent.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/docs/use-cases-index.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/index.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/plugins/codex/skills/agentirc-irc/SKILL.md +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/__init__.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/conftest.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_channel.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_connection.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_discovery.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_federation.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_history.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_ipc.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_mentions.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_message.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_messaging.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_modes.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_opencode_daemon.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_skill_client.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_skills.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_socket_server.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_supervisor.py +0 -0
- {agentirc_cli-0.10.6 → agentirc_cli-0.11.0}/tests/test_webhook.py +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-review
|
|
3
|
+
description: >
|
|
4
|
+
Full PR workflow for agentirc: branch, commit, push, create PR, wait for
|
|
5
|
+
automated reviewers, fetch comments, fix or pushback, reply, resolve threads.
|
|
6
|
+
Use when: creating PRs, handling review feedback, or the user says
|
|
7
|
+
"create PR", "review comments", "address feedback", or "resolve threads".
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PR Review Workflow
|
|
11
|
+
|
|
12
|
+
Complete pull request lifecycle for the agentirc project. Follow every step
|
|
13
|
+
in order.
|
|
14
|
+
|
|
15
|
+
## Step 1 — Branch
|
|
16
|
+
|
|
17
|
+
If you are on `main`, create a feature branch first:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git checkout -b <branch-name>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Branch naming conventions:
|
|
24
|
+
|
|
25
|
+
| Type | Pattern | Example |
|
|
26
|
+
|------|---------|---------|
|
|
27
|
+
| Bug fix | `fix/<short-desc>` | `fix/server-not-running-crash` |
|
|
28
|
+
| Feature | `feat/<short-desc>` | `feat/webhook-alerts` |
|
|
29
|
+
| Docs | `docs/<short-desc>` | `docs/protocol-extensions` |
|
|
30
|
+
|
|
31
|
+
## Step 2 — Make changes, commit, push
|
|
32
|
+
|
|
33
|
+
1. Edit code
|
|
34
|
+
2. Run tests: `uv run pytest tests/ -x -q`
|
|
35
|
+
3. Bump the version (required before PR):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
echo '{"fixed":["..."]}' | python3 ~/.claude/skills/version-bump/scripts/bump.py patch
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
4. Stage and commit:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git add <files>
|
|
45
|
+
git commit -m "$(cat <<'EOF'
|
|
46
|
+
Commit message here.
|
|
47
|
+
|
|
48
|
+
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
49
|
+
EOF
|
|
50
|
+
)"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
5. Push:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git push -u origin <branch-name>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Step 3 — Create PR
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
gh pr create --title "Short title" --body "$(cat <<'EOF'
|
|
63
|
+
## Summary
|
|
64
|
+
- Bullet points describing changes
|
|
65
|
+
|
|
66
|
+
## Test plan
|
|
67
|
+
- [ ] Test items
|
|
68
|
+
|
|
69
|
+
- Claude
|
|
70
|
+
EOF
|
|
71
|
+
)"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Step 4 — Wait for reviewers
|
|
75
|
+
|
|
76
|
+
Automated reviewers (Qodo, Copilot) need time to post comments.
|
|
77
|
+
|
|
78
|
+
**Wait 5 minutes** after creating the PR before checking for comments:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
sleep 300
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Step 5 — Poll for comments
|
|
85
|
+
|
|
86
|
+
After the initial wait, poll every 60 seconds until comments appear:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
bash ~/.claude/skills/pr-review/scripts/pr-comments.sh <PR_NUMBER>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If no comments yet, wait and retry:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
sleep 60
|
|
96
|
+
bash ~/.claude/skills/pr-review/scripts/pr-comments.sh <PR_NUMBER>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Continue until at least one unresolved comment exists, or 3 consecutive polls
|
|
100
|
+
return zero comments (reviewers are done / not configured).
|
|
101
|
+
|
|
102
|
+
## Step 6 — Triage each comment
|
|
103
|
+
|
|
104
|
+
For every review comment, decide:
|
|
105
|
+
|
|
106
|
+
- **FIX** — valid concern, make the code change
|
|
107
|
+
- **PUSHBACK** — disagree, explain why in the reply
|
|
108
|
+
|
|
109
|
+
Guidelines:
|
|
110
|
+
|
|
111
|
+
- Exception type mismatches (e.g., breaking reconnect loops) are always valid
|
|
112
|
+
- Test requests are always valid — add them
|
|
113
|
+
- Style nits are usually valid — fix them
|
|
114
|
+
- Architecture opinions may warrant pushback if they conflict with project
|
|
115
|
+
conventions (check `CLAUDE.md` and `docs/`)
|
|
116
|
+
|
|
117
|
+
## Step 7 — Fix code and push
|
|
118
|
+
|
|
119
|
+
1. Make all code fixes
|
|
120
|
+
2. Run tests: `uv run pytest tests/ -x -q`
|
|
121
|
+
3. Commit with a descriptive message
|
|
122
|
+
4. Push: `git push`
|
|
123
|
+
|
|
124
|
+
## Step 8 — Reply and resolve threads
|
|
125
|
+
|
|
126
|
+
Use batch mode to reply to all comments at once:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
bash ~/.claude/skills/pr-review/scripts/pr-batch.sh --resolve <PR_NUMBER> <<'EOF'
|
|
130
|
+
{"comment_id": 123, "body": "Fixed -- changed X to Y.\n\n- Claude"}
|
|
131
|
+
{"comment_id": 456, "body": "Intentional -- this follows the pattern in Z because...\n\n- Claude"}
|
|
132
|
+
EOF
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Or reply to a single comment:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bash ~/.claude/skills/pr-review/scripts/pr-reply.sh --resolve <PR_NUMBER> <COMMENT_ID> "Fixed -- updated.\n\n- Claude"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Important:**
|
|
142
|
+
|
|
143
|
+
- Always sign replies with `\n\n- Claude`
|
|
144
|
+
- Always use `--resolve` to resolve the thread after replying
|
|
145
|
+
- Every comment must get a reply — no silent fixes
|
|
146
|
+
|
|
147
|
+
## Step 9 — Wait for merge
|
|
148
|
+
|
|
149
|
+
**Never merge the PR yourself.** The PR is merged manually on the GitHub site.
|
|
150
|
+
|
|
151
|
+
Report completion back to the IRC channel:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Using the IRC skill
|
|
155
|
+
AGENTIRC_NICK=<your-nick> python3 -m agentirc.clients.claude.skill.irc_client \
|
|
156
|
+
send "#general" "PR #<N> — all review threads addressed and resolved. Ready for merge."
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Script reference
|
|
160
|
+
|
|
161
|
+
| Script | Purpose |
|
|
162
|
+
|--------|---------|
|
|
163
|
+
| `pr-comments.sh <PR>` | Fetch all review comments |
|
|
164
|
+
| `pr-reply.sh [--resolve] <PR> <ID> "body"` | Reply to one comment |
|
|
165
|
+
| `pr-batch.sh [--resolve] <PR> < jsonl` | Batch reply from JSONL stdin |
|
|
166
|
+
|
|
167
|
+
All scripts auto-detect `owner/repo` from the current git remote.
|
|
168
|
+
|
|
169
|
+
## Quick reference — full flow
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
git checkout -b fix/my-fix
|
|
173
|
+
# ... make changes ...
|
|
174
|
+
uv run pytest tests/ -x -q
|
|
175
|
+
echo '{"fixed":["desc"]}' | python3 ~/.claude/skills/version-bump/scripts/bump.py patch
|
|
176
|
+
git add <files> && git commit -m "message"
|
|
177
|
+
git push -u origin fix/my-fix
|
|
178
|
+
gh pr create --title "..." --body "..."
|
|
179
|
+
sleep 300
|
|
180
|
+
bash ~/.claude/skills/pr-review/scripts/pr-comments.sh <PR>
|
|
181
|
+
# ... fix issues, commit, push ...
|
|
182
|
+
bash ~/.claude/skills/pr-review/scripts/pr-batch.sh --resolve <PR> <<< '{"comment_id":N,"body":"Fixed\n\n- Claude"}'
|
|
183
|
+
# Wait for manual merge — never merge yourself
|
|
184
|
+
```
|
|
@@ -4,6 +4,30 @@ 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
|
+
## [0.11.0] - 2026-03-28
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- agentirc send command for sending messages to channels and agents
|
|
13
|
+
- agentirc status --full flag and per-agent detailed view
|
|
14
|
+
- agentirc sleep/wake commands with configurable schedule (default 23:00-08:00)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Extended IPC protocol with status, pause, and resume handlers
|
|
20
|
+
- Added sleep_start/sleep_end config fields to DaemonConfig
|
|
21
|
+
|
|
22
|
+
## [0.10.7] - 2026-03-28
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Fix crash with cryptic asyncio Event loop is closed errors when starting agent without IRC server running
|
|
28
|
+
- Add server-running pre-check in CLI before starting agent daemon
|
|
29
|
+
- Wrap IRC transport connect in try/except for clear error on connection failure
|
|
30
|
+
|
|
7
31
|
## [0.10.6] - 2026-03-28
|
|
8
32
|
|
|
9
33
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.11.0"
|
|
@@ -5,10 +5,13 @@ Subcommands:
|
|
|
5
5
|
agentirc init Register an agent for the current directory
|
|
6
6
|
agentirc start [nick] [--all] Start agent daemon(s)
|
|
7
7
|
agentirc stop [nick] [--all] Stop agent daemon(s)
|
|
8
|
-
agentirc status
|
|
8
|
+
agentirc status [nick] [--full] List running agents (--full queries activity)
|
|
9
|
+
agentirc send <target> <message> Send a message to a channel or agent
|
|
9
10
|
agentirc read <channel> Read recent channel messages
|
|
10
11
|
agentirc who <channel> List channel members
|
|
11
12
|
agentirc channels List active channels
|
|
13
|
+
agentirc sleep [nick] [--all] Pause agent(s) — stay connected but idle
|
|
14
|
+
agentirc wake [nick] [--all] Resume paused agent(s)
|
|
12
15
|
"""
|
|
13
16
|
from __future__ import annotations
|
|
14
17
|
|
|
@@ -115,6 +118,8 @@ def main() -> None:
|
|
|
115
118
|
|
|
116
119
|
# -- status subcommand -------------------------------------------------
|
|
117
120
|
status_parser = sub.add_parser("status", help="List running agents")
|
|
121
|
+
status_parser.add_argument("nick", nargs="?", help="Show detailed status for a specific agent")
|
|
122
|
+
status_parser.add_argument("--full", action="store_true", help="Query agents for activity status")
|
|
118
123
|
status_parser.add_argument("--config", default=DEFAULT_CONFIG, help="Config file path")
|
|
119
124
|
|
|
120
125
|
# -- read subcommand ---------------------------------------------------
|
|
@@ -128,10 +133,28 @@ def main() -> None:
|
|
|
128
133
|
who_parser.add_argument("channel", help="Channel or nick target")
|
|
129
134
|
who_parser.add_argument("--config", default=DEFAULT_CONFIG, help="Config file path")
|
|
130
135
|
|
|
136
|
+
# -- send subcommand ---------------------------------------------------
|
|
137
|
+
send_parser = sub.add_parser("send", help="Send a message to a channel or agent")
|
|
138
|
+
send_parser.add_argument("target", help="Channel (e.g. #general) or agent nick")
|
|
139
|
+
send_parser.add_argument("message", help="Message text to send")
|
|
140
|
+
send_parser.add_argument("--config", default=DEFAULT_CONFIG, help="Config file path")
|
|
141
|
+
|
|
131
142
|
# -- channels subcommand -----------------------------------------------
|
|
132
143
|
channels_parser = sub.add_parser("channels", help="List active channels")
|
|
133
144
|
channels_parser.add_argument("--config", default=DEFAULT_CONFIG, help="Config file path")
|
|
134
145
|
|
|
146
|
+
# -- sleep subcommand --------------------------------------------------
|
|
147
|
+
sleep_parser = sub.add_parser("sleep", help="Pause agent(s) — stay connected but idle")
|
|
148
|
+
sleep_parser.add_argument("nick", nargs="?", help="Agent nick to pause")
|
|
149
|
+
sleep_parser.add_argument("--all", action="store_true", help="Pause all agents")
|
|
150
|
+
sleep_parser.add_argument("--config", default=DEFAULT_CONFIG, help="Config file path")
|
|
151
|
+
|
|
152
|
+
# -- wake subcommand ---------------------------------------------------
|
|
153
|
+
wake_parser = sub.add_parser("wake", help="Resume paused agent(s)")
|
|
154
|
+
wake_parser.add_argument("nick", nargs="?", help="Agent nick to resume")
|
|
155
|
+
wake_parser.add_argument("--all", action="store_true", help="Resume all agents")
|
|
156
|
+
wake_parser.add_argument("--config", default=DEFAULT_CONFIG, help="Config file path")
|
|
157
|
+
|
|
135
158
|
# -- skills subcommand -------------------------------------------------
|
|
136
159
|
skills_parser = sub.add_parser("skills", help="Install IRC skills for AI agents")
|
|
137
160
|
skills_sub = skills_parser.add_subparsers(dest="skills_command")
|
|
@@ -159,9 +182,12 @@ def main() -> None:
|
|
|
159
182
|
"start": _cmd_start,
|
|
160
183
|
"stop": _cmd_stop,
|
|
161
184
|
"status": _cmd_status,
|
|
185
|
+
"send": _cmd_send,
|
|
162
186
|
"read": _cmd_read,
|
|
163
187
|
"who": _cmd_who,
|
|
164
188
|
"channels": _cmd_channels,
|
|
189
|
+
"sleep": _cmd_sleep,
|
|
190
|
+
"wake": _cmd_wake,
|
|
165
191
|
"skills": _cmd_skills,
|
|
166
192
|
}
|
|
167
193
|
handler = dispatch.get(args.command)
|
|
@@ -433,6 +459,26 @@ def _cmd_start(args: argparse.Namespace) -> None:
|
|
|
433
459
|
print("No agents configured", file=sys.stderr)
|
|
434
460
|
sys.exit(1)
|
|
435
461
|
|
|
462
|
+
# Best-effort check that the IRC server is reachable before starting agent(s)
|
|
463
|
+
import socket as _socket
|
|
464
|
+
|
|
465
|
+
server_name = config.server.name
|
|
466
|
+
host, port = config.server.host, config.server.port
|
|
467
|
+
try:
|
|
468
|
+
with _socket.create_connection((host, port), timeout=2):
|
|
469
|
+
pass
|
|
470
|
+
except (ConnectionRefusedError, OSError):
|
|
471
|
+
# TCP probe failed — add PID hint if available
|
|
472
|
+
hint = ""
|
|
473
|
+
server_pid = read_pid(f"server-{server_name}")
|
|
474
|
+
if not server_pid or not is_process_alive(server_pid):
|
|
475
|
+
hint = f"\nStart it with: agentirc server start --name {server_name}"
|
|
476
|
+
print(
|
|
477
|
+
f"Error: cannot connect to IRC server at {host}:{port}.{hint}",
|
|
478
|
+
file=sys.stderr,
|
|
479
|
+
)
|
|
480
|
+
sys.exit(1)
|
|
481
|
+
|
|
436
482
|
if len(agents) == 1:
|
|
437
483
|
# Run in foreground (single agent)
|
|
438
484
|
agent = agents[0]
|
|
@@ -632,21 +678,33 @@ def _stop_agent(nick: str) -> None:
|
|
|
632
678
|
print(f"Agent '{nick}' killed")
|
|
633
679
|
|
|
634
680
|
|
|
635
|
-
async def
|
|
636
|
-
"""Send
|
|
681
|
+
async def _ipc_request(socket_path: str, msg_type: str, **kwargs) -> dict | None:
|
|
682
|
+
"""Send an IPC request via Unix socket and return the response."""
|
|
637
683
|
from agentirc.clients.claude.ipc import decode_message, encode_message, make_request
|
|
638
684
|
|
|
639
|
-
reader, writer = await asyncio.wait_for(
|
|
640
|
-
asyncio.open_unix_connection(socket_path),
|
|
641
|
-
timeout=3.0,
|
|
642
|
-
)
|
|
643
685
|
try:
|
|
644
|
-
|
|
686
|
+
reader, writer = await asyncio.wait_for(
|
|
687
|
+
asyncio.open_unix_connection(socket_path),
|
|
688
|
+
timeout=3.0,
|
|
689
|
+
)
|
|
690
|
+
except (ConnectionRefusedError, FileNotFoundError, OSError):
|
|
691
|
+
return None
|
|
692
|
+
try:
|
|
693
|
+
req = make_request(msg_type, **kwargs)
|
|
645
694
|
writer.write(encode_message(req))
|
|
646
695
|
await writer.drain()
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
696
|
+
# Read lines until we get a response (skip whispers)
|
|
697
|
+
deadline = asyncio.get_event_loop().time() + 3.0
|
|
698
|
+
while True:
|
|
699
|
+
remaining = deadline - asyncio.get_event_loop().time()
|
|
700
|
+
if remaining <= 0:
|
|
701
|
+
return None
|
|
702
|
+
data = await asyncio.wait_for(reader.readline(), timeout=remaining)
|
|
703
|
+
msg = decode_message(data)
|
|
704
|
+
if msg and msg.get("type") == "response":
|
|
705
|
+
return msg
|
|
706
|
+
except (asyncio.TimeoutError, ConnectionError, BrokenPipeError, OSError):
|
|
707
|
+
return None
|
|
650
708
|
finally:
|
|
651
709
|
writer.close()
|
|
652
710
|
try:
|
|
@@ -655,10 +713,37 @@ async def _ipc_shutdown(socket_path: str) -> bool:
|
|
|
655
713
|
pass
|
|
656
714
|
|
|
657
715
|
|
|
716
|
+
async def _ipc_shutdown(socket_path: str) -> bool:
|
|
717
|
+
"""Send a shutdown command via Unix socket IPC."""
|
|
718
|
+
resp = await _ipc_request(socket_path, "shutdown")
|
|
719
|
+
return resp is not None and resp.get("ok", False)
|
|
720
|
+
|
|
721
|
+
|
|
658
722
|
# -----------------------------------------------------------------------
|
|
659
723
|
# Agent status
|
|
660
724
|
# -----------------------------------------------------------------------
|
|
661
725
|
|
|
726
|
+
def _agent_socket_path(nick: str) -> str:
|
|
727
|
+
return os.path.join(
|
|
728
|
+
os.environ.get("XDG_RUNTIME_DIR", "/tmp"),
|
|
729
|
+
f"agentirc-{nick}.sock",
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
def _agent_process_status(agent) -> tuple[str, int | None]:
|
|
734
|
+
"""Return (status_str, pid_or_none) for an agent."""
|
|
735
|
+
pid_name = f"agent-{agent.nick}"
|
|
736
|
+
pid = read_pid(pid_name)
|
|
737
|
+
if pid and is_process_alive(pid):
|
|
738
|
+
socket_path = _agent_socket_path(agent.nick)
|
|
739
|
+
if os.path.exists(socket_path):
|
|
740
|
+
return "running", pid
|
|
741
|
+
return "starting", pid
|
|
742
|
+
if pid:
|
|
743
|
+
remove_pid(pid_name)
|
|
744
|
+
return "stopped", None
|
|
745
|
+
|
|
746
|
+
|
|
662
747
|
def _cmd_status(args: argparse.Namespace) -> None:
|
|
663
748
|
config = load_config_or_default(args.config)
|
|
664
749
|
|
|
@@ -666,30 +751,64 @@ def _cmd_status(args: argparse.Namespace) -> None:
|
|
|
666
751
|
print("No agents configured")
|
|
667
752
|
return
|
|
668
753
|
|
|
669
|
-
|
|
670
|
-
|
|
754
|
+
# Single agent detailed view
|
|
755
|
+
if args.nick:
|
|
756
|
+
agent = None
|
|
757
|
+
for a in config.agents:
|
|
758
|
+
if a.nick == args.nick:
|
|
759
|
+
agent = a
|
|
760
|
+
break
|
|
761
|
+
if not agent:
|
|
762
|
+
print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
|
|
763
|
+
sys.exit(1)
|
|
764
|
+
|
|
765
|
+
status, pid = _agent_process_status(agent)
|
|
766
|
+
print(agent.nick)
|
|
767
|
+
print(f" Status: {status}")
|
|
768
|
+
print(f" PID: {pid or '-'}")
|
|
769
|
+
|
|
770
|
+
# Query IPC for activity if running
|
|
771
|
+
if status == "running":
|
|
772
|
+
resp = asyncio.run(_ipc_request(_agent_socket_path(agent.nick), "status"))
|
|
773
|
+
if resp and resp.get("ok"):
|
|
774
|
+
data = resp.get("data", {})
|
|
775
|
+
print(f" Activity: {data.get('activity', 'unknown')}")
|
|
776
|
+
print(f" Turns: {data.get('turn_count', 0)}")
|
|
777
|
+
print(f" Paused: {'yes' if data.get('paused') else 'no'}")
|
|
778
|
+
else:
|
|
779
|
+
print(f" Activity: -")
|
|
780
|
+
|
|
781
|
+
channels = agent.channels if isinstance(agent.channels, list) else []
|
|
782
|
+
print(f" Directory: {agent.directory}")
|
|
783
|
+
print(f" Backend: {agent.agent}")
|
|
784
|
+
print(f" Channels: {', '.join(channels)}")
|
|
785
|
+
print(f" Model: {agent.model}")
|
|
786
|
+
print(f" Config: {args.config}")
|
|
787
|
+
return
|
|
788
|
+
|
|
789
|
+
# All agents view
|
|
790
|
+
show_activity = args.full
|
|
791
|
+
|
|
792
|
+
if show_activity:
|
|
793
|
+
print(f"{'NICK':<30} {'STATUS':<12} {'PID':<10} {'ACTIVITY':<10}")
|
|
794
|
+
print("-" * 62)
|
|
795
|
+
else:
|
|
796
|
+
print(f"{'NICK':<30} {'STATUS':<12} {'PID':<10}")
|
|
797
|
+
print("-" * 52)
|
|
671
798
|
|
|
672
799
|
for agent in config.agents:
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
)
|
|
683
|
-
if os.path.exists(socket_path):
|
|
684
|
-
status = "running"
|
|
685
|
-
else:
|
|
686
|
-
status = "starting"
|
|
687
|
-
print(f"{agent.nick:<30} {status:<12} {pid:<10}")
|
|
688
|
-
elif pid:
|
|
689
|
-
remove_pid(pid_name)
|
|
690
|
-
print(f"{agent.nick:<30} {'stopped':<12} {'-':<10}")
|
|
800
|
+
status, pid = _agent_process_status(agent)
|
|
801
|
+
activity = "-"
|
|
802
|
+
|
|
803
|
+
if show_activity and status == "running":
|
|
804
|
+
resp = asyncio.run(_ipc_request(_agent_socket_path(agent.nick), "status"))
|
|
805
|
+
if resp and resp.get("ok"):
|
|
806
|
+
activity = resp.get("data", {}).get("activity", "unknown")
|
|
807
|
+
|
|
808
|
+
if show_activity:
|
|
809
|
+
print(f"{agent.nick:<30} {status:<12} {str(pid or '-'):<10} {activity:<10}")
|
|
691
810
|
else:
|
|
692
|
-
print(f"{agent.nick:<30} {
|
|
811
|
+
print(f"{agent.nick:<30} {status:<12} {str(pid or '-'):<10}")
|
|
693
812
|
|
|
694
813
|
|
|
695
814
|
# -----------------------------------------------------------------------
|
|
@@ -708,6 +827,52 @@ def _get_observer(config_path: str):
|
|
|
708
827
|
)
|
|
709
828
|
|
|
710
829
|
|
|
830
|
+
def _ipc_to_agents(args: argparse.Namespace, msg_type: str, action_verb: str) -> None:
|
|
831
|
+
"""Send an IPC message (pause/resume) to one or all agents."""
|
|
832
|
+
config = load_config_or_default(args.config)
|
|
833
|
+
|
|
834
|
+
if args.nick and args.all:
|
|
835
|
+
print(f"Cannot specify both nick and --all", file=sys.stderr)
|
|
836
|
+
sys.exit(1)
|
|
837
|
+
|
|
838
|
+
if not args.nick and not args.all:
|
|
839
|
+
print(f"Usage: agentirc {action_verb} <nick> or --all", file=sys.stderr)
|
|
840
|
+
sys.exit(1)
|
|
841
|
+
|
|
842
|
+
targets = config.agents if args.all else []
|
|
843
|
+
if args.nick:
|
|
844
|
+
for a in config.agents:
|
|
845
|
+
if a.nick == args.nick:
|
|
846
|
+
targets = [a]
|
|
847
|
+
break
|
|
848
|
+
else:
|
|
849
|
+
print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
|
|
850
|
+
sys.exit(1)
|
|
851
|
+
|
|
852
|
+
for agent in targets:
|
|
853
|
+
socket_path = _agent_socket_path(agent.nick)
|
|
854
|
+
resp = asyncio.run(_ipc_request(socket_path, msg_type))
|
|
855
|
+
if resp and resp.get("ok"):
|
|
856
|
+
print(f"{agent.nick}: {action_verb}")
|
|
857
|
+
else:
|
|
858
|
+
print(f"{agent.nick}: failed (not running?)", file=sys.stderr)
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
def _cmd_sleep(args: argparse.Namespace) -> None:
|
|
862
|
+
_ipc_to_agents(args, "pause", "paused")
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
def _cmd_wake(args: argparse.Namespace) -> None:
|
|
866
|
+
_ipc_to_agents(args, "resume", "resumed")
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
def _cmd_send(args: argparse.Namespace) -> None:
|
|
870
|
+
observer = _get_observer(args.config)
|
|
871
|
+
target = args.target if args.target.startswith("#") else args.target
|
|
872
|
+
asyncio.run(observer.send_message(target, args.message))
|
|
873
|
+
print(f"Sent to {target}")
|
|
874
|
+
|
|
875
|
+
|
|
711
876
|
def _cmd_read(args: argparse.Namespace) -> None:
|
|
712
877
|
observer = _get_observer(args.config)
|
|
713
878
|
channel = args.channel if args.channel.startswith("#") else f"#{args.channel}"
|
|
@@ -56,6 +56,8 @@ class DaemonConfig:
|
|
|
56
56
|
supervisor: SupervisorConfig = field(default_factory=SupervisorConfig)
|
|
57
57
|
webhooks: WebhookConfig = field(default_factory=WebhookConfig)
|
|
58
58
|
buffer_size: int = 500
|
|
59
|
+
sleep_start: str = "23:00"
|
|
60
|
+
sleep_end: str = "08:00"
|
|
59
61
|
agents: list[AgentConfig] = field(default_factory=list)
|
|
60
62
|
|
|
61
63
|
def get_agent(self, nick: str) -> AgentConfig | None:
|
|
@@ -84,6 +86,8 @@ def load_config(path: str | Path) -> DaemonConfig:
|
|
|
84
86
|
supervisor=supervisor,
|
|
85
87
|
webhooks=webhooks,
|
|
86
88
|
buffer_size=raw.get("buffer_size", 500),
|
|
89
|
+
sleep_start=raw.get("sleep_start", "23:00"),
|
|
90
|
+
sleep_end=raw.get("sleep_end", "08:00"),
|
|
87
91
|
agents=agents,
|
|
88
92
|
)
|
|
89
93
|
|