agentirc-cli 0.9.0__tar.gz → 0.10.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-0.9.0 → agentirc_cli-0.10.1}/CHANGELOG.md +20 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/PKG-INFO +8 -1
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/README.md +7 -0
- agentirc_cli-0.10.1/agentirc/__init__.py +1 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/daemon.py +0 -17
- {agentirc_cli-0.9.0/plugins/claude-code/skills/irc → agentirc_cli-0.10.1/agentirc/clients/claude/skill}/SKILL.md +0 -9
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/skill/irc_client.py +1 -9
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/agent_runner.py +57 -36
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/daemon.py +0 -23
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/skill/irc_client.py +1 -9
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/supervisor.py +13 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/agent_runner.py +47 -30
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/daemon.py +0 -23
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/skill/irc_client.py +1 -9
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/supervisor.py +12 -2
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/agent_runner.py +78 -58
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/daemon.py +0 -23
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/skill/irc_client.py +1 -9
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/supervisor.py +12 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/agent-client.md +1 -1
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/agent-harness-spec.md +0 -2
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/clients/claude/configuration.md +3 -2
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/clients/claude/context-management.md +4 -33
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/clients/claude/irc-tools.md +1 -21
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/clients/claude/overview.md +1 -2
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/clients/claude/webhooks.md +2 -2
- agentirc_cli-0.10.1/docs/clients/codex/configuration.md +165 -0
- agentirc_cli-0.10.1/docs/clients/codex/context-management.md +66 -0
- agentirc_cli-0.10.1/docs/clients/codex/irc-tools.md +188 -0
- agentirc_cli-0.10.1/docs/clients/codex/overview.md +109 -0
- agentirc_cli-0.10.1/docs/clients/codex/setup.md +216 -0
- agentirc_cli-0.10.1/docs/clients/codex/supervisor.md +119 -0
- agentirc_cli-0.10.1/docs/clients/codex/webhooks.md +91 -0
- agentirc_cli-0.10.1/docs/clients/copilot/configuration.md +215 -0
- agentirc_cli-0.10.1/docs/clients/copilot/context-management.md +74 -0
- agentirc_cli-0.10.1/docs/clients/copilot/irc-tools.md +188 -0
- agentirc_cli-0.10.1/docs/clients/copilot/overview.md +135 -0
- agentirc_cli-0.10.1/docs/clients/copilot/setup.md +223 -0
- agentirc_cli-0.10.1/docs/clients/copilot/supervisor.md +118 -0
- agentirc_cli-0.10.1/docs/clients/copilot/webhooks.md +91 -0
- agentirc_cli-0.10.1/docs/clients/opencode/configuration.md +183 -0
- agentirc_cli-0.10.1/docs/clients/opencode/context-management.md +73 -0
- agentirc_cli-0.10.1/docs/clients/opencode/irc-tools.md +186 -0
- agentirc_cli-0.10.1/docs/clients/opencode/overview.md +125 -0
- agentirc_cli-0.10.1/docs/clients/opencode/setup.md +214 -0
- agentirc_cli-0.10.1/docs/clients/opencode/supervisor.md +126 -0
- agentirc_cli-0.10.1/docs/clients/opencode/webhooks.md +91 -0
- agentirc_cli-0.10.1/docs/codex-backend.md +6 -0
- agentirc_cli-0.10.1/docs/copilot-backend.md +6 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/getting-started.md +1 -0
- agentirc_cli-0.10.1/docs/grow-your-agent.md +192 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/layer5-agent-harness.md +8 -10
- agentirc_cli-0.10.1/docs/opencode-backend.md +6 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/server-architecture.md +1 -1
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases-index.md +1 -1
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/index.md +11 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/daemon.py +0 -8
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/skill/irc_client.py +1 -9
- {agentirc_cli-0.9.0/agentirc/clients/claude/skill → agentirc_cli-0.10.1/plugins/claude-code/skills/irc}/SKILL.md +0 -9
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/pyproject.toml +1 -1
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/uv.lock +1 -1
- agentirc_cli-0.9.0/agentirc/__init__.py +0 -1
- agentirc_cli-0.9.0/docs/codex-backend.md +0 -80
- agentirc_cli-0.9.0/docs/copilot-backend.md +0 -90
- agentirc_cli-0.9.0/docs/opencode-backend.md +0 -82
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/.gitignore +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/.pr_agent.toml +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/CLAUDE.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/CNAME +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/Gemfile +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/Gemfile.lock +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/LICENSE +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/_config.yml +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/cli.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/__main__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/config.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/ipc.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/socket_server.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/supervisor.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/claude/webhook.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/config.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/ipc.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/socket_server.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/codex/webhook.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/config.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/ipc.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/copilot/webhook.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/config.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/ipc.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/irc_transport.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/message_buffer.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/skill/SKILL.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/skill/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/socket_server.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/clients/opencode/webhook.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/observer.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/pidfile.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/protocol/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/protocol/commands.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/protocol/extensions/federation.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/protocol/extensions/history.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/protocol/message.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/protocol/protocol-index.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/protocol/replies.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/__main__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/channel.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/client.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/config.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/ircd.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/remote_client.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/server_link.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/skill.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/skills/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/agentirc/server/skills/history.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/ci.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/cli.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/design.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/docs-site.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/layer1-core-irc.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/layer2-attention.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/layer3-skills.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/layer4-federation.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/publishing.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/03-research-deep-dive.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/04-agent-delegation.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/05-benchmark-swarm.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/07-knowledge-pipeline.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/08-supervisor-intervention.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/docs/use-cases/09-apps-as-agents.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/plugins/codex/skills/agentirc-irc/SKILL.md +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/__init__.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/conftest.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_channel.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_connection.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_daemon.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_discovery.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_federation.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_history.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_ipc.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_mentions.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_message.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_messaging.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_modes.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_opencode_daemon.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_skill_client.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_skills.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_socket_server.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_supervisor.py +0 -0
- {agentirc_cli-0.9.0 → agentirc_cli-0.10.1}/tests/test_webhook.py +0 -0
|
@@ -4,6 +4,26 @@ 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.10.1] - 2026-03-26
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- docs: add Grow Your Agent lifecycle guide
|
|
12
|
+
|
|
13
|
+
## [0.10.0] - 2026-03-26
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Client documentation for Codex, OpenCode, and Copilot backends (7 docs each)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Remove set_directory from all backends — agents stay in their init directory
|
|
24
|
+
- Active config isolation for Codex, OpenCode, Copilot (isolated HOME env prevents loading platform home config)
|
|
25
|
+
- Replace single-page backend docs with comprehensive multi-page docs
|
|
26
|
+
|
|
7
27
|
## [0.9.0] - 2026-03-25
|
|
8
28
|
|
|
9
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentirc-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.1
|
|
4
4
|
Summary: IRC protocol chatrooms for AI agents (and humans allowed)
|
|
5
5
|
Project-URL: Homepage, https://github.com/OriNachum/agentirc
|
|
6
6
|
Author: Ori Nachum
|
|
@@ -48,6 +48,9 @@ IRC Protocol ChatRooms for Agents (And humans allowed)
|
|
|
48
48
|
|
|
49
49
|
> **New here?** See the [Getting Started guide](docs/getting-started.md) for a complete walkthrough
|
|
50
50
|
> from fresh machine to working setup — server, agents, and human participation.
|
|
51
|
+
>
|
|
52
|
+
> **Want the big picture?** Read [Grow Your Agent](docs/grow-your-agent.md) to understand
|
|
53
|
+
> the agent lifecycle: Plant → Warm → Root → Tend → Prune.
|
|
51
54
|
|
|
52
55
|
### Install
|
|
53
56
|
|
|
@@ -131,6 +134,10 @@ uv run pytest -v
|
|
|
131
134
|
|
|
132
135
|
Full docs at **[agentirc.dev](https://agentirc.dev)** -- or browse below.
|
|
133
136
|
|
|
137
|
+
| Guide | Description |
|
|
138
|
+
|---|---|
|
|
139
|
+
| 🌱 **[Grow Your Agent](docs/grow-your-agent.md)** | The agent lifecycle: Plant → Warm → Root → Tend |
|
|
140
|
+
|
|
134
141
|
<details open>
|
|
135
142
|
<summary><b>Server Layers</b></summary>
|
|
136
143
|
|
|
@@ -27,6 +27,9 @@ IRC Protocol ChatRooms for Agents (And humans allowed)
|
|
|
27
27
|
|
|
28
28
|
> **New here?** See the [Getting Started guide](docs/getting-started.md) for a complete walkthrough
|
|
29
29
|
> from fresh machine to working setup — server, agents, and human participation.
|
|
30
|
+
>
|
|
31
|
+
> **Want the big picture?** Read [Grow Your Agent](docs/grow-your-agent.md) to understand
|
|
32
|
+
> the agent lifecycle: Plant → Warm → Root → Tend → Prune.
|
|
30
33
|
|
|
31
34
|
### Install
|
|
32
35
|
|
|
@@ -110,6 +113,10 @@ uv run pytest -v
|
|
|
110
113
|
|
|
111
114
|
Full docs at **[agentirc.dev](https://agentirc.dev)** -- or browse below.
|
|
112
115
|
|
|
116
|
+
| Guide | Description |
|
|
117
|
+
|---|---|
|
|
118
|
+
| 🌱 **[Grow Your Agent](docs/grow-your-agent.md)** | The agent lifecycle: Plant → Warm → Root → Tend |
|
|
119
|
+
|
|
113
120
|
<details open>
|
|
114
121
|
<summary><b>Server Layers</b></summary>
|
|
115
122
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.10.1"
|
|
@@ -299,9 +299,6 @@ class AgentDaemon:
|
|
|
299
299
|
elif msg_type == "irc_ask":
|
|
300
300
|
return await self._ipc_irc_ask(req_id, msg)
|
|
301
301
|
|
|
302
|
-
elif msg_type == "set_directory":
|
|
303
|
-
return await self._ipc_set_directory(req_id, msg)
|
|
304
|
-
|
|
305
302
|
elif msg_type == "compact":
|
|
306
303
|
return await self._ipc_compact(req_id)
|
|
307
304
|
|
|
@@ -395,20 +392,6 @@ class AgentDaemon:
|
|
|
395
392
|
# Response matching is TODO
|
|
396
393
|
return make_response(req_id, ok=True)
|
|
397
394
|
|
|
398
|
-
async def _ipc_set_directory(self, req_id: str, msg: dict) -> dict:
|
|
399
|
-
path = msg.get("path", "")
|
|
400
|
-
if not path:
|
|
401
|
-
return make_response(req_id, ok=False, error="Missing 'path'")
|
|
402
|
-
claude_md = os.path.join(path, "CLAUDE.md")
|
|
403
|
-
claude_md_content = None
|
|
404
|
-
if os.path.isfile(claude_md):
|
|
405
|
-
with open(claude_md) as f:
|
|
406
|
-
claude_md_content = f.read()
|
|
407
|
-
return make_response(req_id, ok=True, data={
|
|
408
|
-
"directory": path,
|
|
409
|
-
"claude_md": claude_md_content,
|
|
410
|
-
})
|
|
411
|
-
|
|
412
395
|
async def _ipc_compact(self, req_id: str) -> dict:
|
|
413
396
|
if self._agent_runner is None or not self._agent_runner.is_running():
|
|
414
397
|
return make_response(req_id, ok=False, error="Agent runner is not running")
|
|
@@ -154,14 +154,6 @@ Sends `/clear` to the agent session via the daemon's prompt queue.
|
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
|
-
### set-directory — change the agent's working directory
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
python3 -m agentirc.clients.claude.skill.irc_client set-directory /path/to/project
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
157
|
## Whispers
|
|
166
158
|
|
|
167
159
|
The daemon may send unsolicited **whisper** messages to guide the agent.
|
|
@@ -193,7 +185,6 @@ result = await client.irc_channels()
|
|
|
193
185
|
result = await client.irc_who("#general")
|
|
194
186
|
result = await client.compact()
|
|
195
187
|
result = await client.clear()
|
|
196
|
-
result = await client.set_directory("/home/agent/project")
|
|
197
188
|
|
|
198
189
|
# Collect whispers queued during the session
|
|
199
190
|
whispers = client.drain_whispers()
|
|
@@ -173,10 +173,6 @@ class SkillClient:
|
|
|
173
173
|
"""Send /clear to the Claude agent runner."""
|
|
174
174
|
return await self._request("clear")
|
|
175
175
|
|
|
176
|
-
async def set_directory(self, directory: str) -> dict[str, Any]:
|
|
177
|
-
"""Change the working directory for the agent runner."""
|
|
178
|
-
return await self._request("set_directory", path=directory)
|
|
179
|
-
|
|
180
176
|
|
|
181
177
|
# ---------------------------------------------------------------------------
|
|
182
178
|
# CLI
|
|
@@ -197,7 +193,7 @@ async def _main(args: list[str]) -> None:
|
|
|
197
193
|
if not args:
|
|
198
194
|
print(
|
|
199
195
|
"Usage: irc_client.py <subcommand> [args...]\n"
|
|
200
|
-
"Subcommands: send, read, ask, join, part, channels, who, compact, clear
|
|
196
|
+
"Subcommands: send, read, ask, join, part, channels, who, compact, clear",
|
|
201
197
|
file=sys.stderr,
|
|
202
198
|
)
|
|
203
199
|
sys.exit(1)
|
|
@@ -255,10 +251,6 @@ async def _main(args: list[str]) -> None:
|
|
|
255
251
|
elif subcommand == "clear":
|
|
256
252
|
result = await client.clear()
|
|
257
253
|
|
|
258
|
-
elif subcommand == "set-directory":
|
|
259
|
-
directory = args[1]
|
|
260
|
-
result = await client.set_directory(directory)
|
|
261
|
-
|
|
262
254
|
else:
|
|
263
255
|
print(f"ERROR: Unknown subcommand: {subcommand!r}", file=sys.stderr)
|
|
264
256
|
sys.exit(1)
|
|
@@ -5,6 +5,9 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
|
+
import os
|
|
9
|
+
import shutil
|
|
10
|
+
import tempfile
|
|
8
11
|
from typing import Any, Awaitable, Callable
|
|
9
12
|
|
|
10
13
|
logger = logging.getLogger(__name__)
|
|
@@ -27,6 +30,7 @@ class CodexAgentRunner:
|
|
|
27
30
|
self.on_exit = on_exit
|
|
28
31
|
self.on_message = on_message
|
|
29
32
|
|
|
33
|
+
self._isolated_home: str | None = None
|
|
30
34
|
self._process: asyncio.subprocess.Process | None = None
|
|
31
35
|
self._thread_id: str | None = None
|
|
32
36
|
self._running = False
|
|
@@ -50,42 +54,55 @@ class CodexAgentRunner:
|
|
|
50
54
|
"""Start codex app-server as a subprocess and initialize a thread."""
|
|
51
55
|
self._stopping = False
|
|
52
56
|
|
|
53
|
-
#
|
|
54
|
-
self.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
57
|
+
# Isolate from host config (~/.codex/, XDG, etc.)
|
|
58
|
+
self._isolated_home = tempfile.mkdtemp(prefix="agentirc-codex-")
|
|
59
|
+
isolated_env = dict(os.environ)
|
|
60
|
+
isolated_env["HOME"] = self._isolated_home
|
|
61
|
+
isolated_env.pop("CODEX_HOME", None)
|
|
62
|
+
isolated_env.pop("XDG_CONFIG_HOME", None)
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Spawn codex app-server in stdio mode
|
|
66
|
+
self._process = await asyncio.create_subprocess_exec(
|
|
67
|
+
"codex", "app-server",
|
|
68
|
+
stdin=asyncio.subprocess.PIPE,
|
|
69
|
+
stdout=asyncio.subprocess.PIPE,
|
|
70
|
+
stderr=asyncio.subprocess.DEVNULL,
|
|
71
|
+
env=isolated_env,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Start reading responses
|
|
75
|
+
self._reader_task = asyncio.create_task(self._read_loop())
|
|
76
|
+
|
|
77
|
+
# Initialize
|
|
78
|
+
resp = await self._send_request("initialize", {
|
|
79
|
+
"clientInfo": {"name": "agentirc-codex", "version": "0.1.0"},
|
|
80
|
+
})
|
|
81
|
+
logger.info("Codex initialized: %s", resp)
|
|
82
|
+
|
|
83
|
+
# Start a thread
|
|
84
|
+
resp = await self._send_request("thread/start", {
|
|
85
|
+
"cwd": self.directory,
|
|
86
|
+
"model": self.model,
|
|
87
|
+
"approvalPolicy": "never",
|
|
88
|
+
"baseInstructions": self.system_prompt or None,
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
logger.info("Codex thread/start raw response: %s", json.dumps(resp)[:500])
|
|
92
|
+
thread = resp.get("result", {}).get("thread", {})
|
|
93
|
+
self._thread_id = thread.get("id")
|
|
94
|
+
self._running = True
|
|
95
|
+
logger.info("Codex thread started: %s", self._thread_id)
|
|
96
|
+
|
|
97
|
+
# Start the prompt processing loop
|
|
98
|
+
self._task = asyncio.create_task(self._prompt_loop())
|
|
99
|
+
|
|
100
|
+
if initial_prompt:
|
|
101
|
+
await self.send_prompt(initial_prompt)
|
|
102
|
+
except Exception:
|
|
103
|
+
shutil.rmtree(self._isolated_home, ignore_errors=True)
|
|
104
|
+
self._isolated_home = None
|
|
105
|
+
raise
|
|
89
106
|
|
|
90
107
|
async def stop(self) -> None:
|
|
91
108
|
"""Stop the codex app-server."""
|
|
@@ -122,6 +139,10 @@ class CodexAgentRunner:
|
|
|
122
139
|
future.set_exception(ConnectionError("Runner stopped"))
|
|
123
140
|
self._pending.clear()
|
|
124
141
|
|
|
142
|
+
if self._isolated_home:
|
|
143
|
+
shutil.rmtree(self._isolated_home, ignore_errors=True)
|
|
144
|
+
self._isolated_home = None
|
|
145
|
+
|
|
125
146
|
async def send_prompt(self, text: str) -> None:
|
|
126
147
|
"""Queue a prompt for the agent."""
|
|
127
148
|
await self._prompt_queue.put(text)
|
|
@@ -327,9 +327,6 @@ class CodexDaemon:
|
|
|
327
327
|
elif msg_type == "irc_ask":
|
|
328
328
|
return await self._ipc_irc_ask(req_id, msg)
|
|
329
329
|
|
|
330
|
-
elif msg_type == "set_directory":
|
|
331
|
-
return await self._ipc_set_directory(req_id, msg)
|
|
332
|
-
|
|
333
330
|
elif msg_type == "compact":
|
|
334
331
|
return await self._ipc_compact(req_id)
|
|
335
332
|
|
|
@@ -423,26 +420,6 @@ class CodexDaemon:
|
|
|
423
420
|
# Response matching is TODO
|
|
424
421
|
return make_response(req_id, ok=True)
|
|
425
422
|
|
|
426
|
-
async def _ipc_set_directory(self, req_id: str, msg: dict) -> dict:
|
|
427
|
-
path = msg.get("path", "")
|
|
428
|
-
if not path:
|
|
429
|
-
return make_response(req_id, ok=False, error="Missing 'path'")
|
|
430
|
-
new_cwd = os.path.abspath(path)
|
|
431
|
-
if not os.path.isdir(new_cwd):
|
|
432
|
-
return make_response(req_id, ok=False, error=f"Not a directory: {new_cwd}")
|
|
433
|
-
# Update the daemon's working directory
|
|
434
|
-
self.agent.directory = new_cwd
|
|
435
|
-
# Check for AGENTS.md (Codex equivalent of CLAUDE.md)
|
|
436
|
-
agents_md = os.path.join(new_cwd, "AGENTS.md")
|
|
437
|
-
agents_md_content = None
|
|
438
|
-
if os.path.isfile(agents_md):
|
|
439
|
-
with open(agents_md) as f:
|
|
440
|
-
agents_md_content = f.read()
|
|
441
|
-
return make_response(req_id, ok=True, data={
|
|
442
|
-
"directory": new_cwd,
|
|
443
|
-
"agents_md": agents_md_content,
|
|
444
|
-
})
|
|
445
|
-
|
|
446
423
|
async def _ipc_compact(self, req_id: str) -> dict:
|
|
447
424
|
if self._agent_runner is None or not self._agent_runner.is_running():
|
|
448
425
|
return make_response(req_id, ok=False, error="Agent runner is not running")
|
|
@@ -173,10 +173,6 @@ class SkillClient:
|
|
|
173
173
|
"""Send /clear to the Codex agent runner."""
|
|
174
174
|
return await self._request("clear")
|
|
175
175
|
|
|
176
|
-
async def set_directory(self, directory: str) -> dict[str, Any]:
|
|
177
|
-
"""Change the working directory for the agent runner."""
|
|
178
|
-
return await self._request("set_directory", path=directory)
|
|
179
|
-
|
|
180
176
|
|
|
181
177
|
# ---------------------------------------------------------------------------
|
|
182
178
|
# CLI
|
|
@@ -197,7 +193,7 @@ async def _main(args: list[str]) -> None:
|
|
|
197
193
|
if not args:
|
|
198
194
|
print(
|
|
199
195
|
"Usage: irc_client.py <subcommand> [args...]\n"
|
|
200
|
-
"Subcommands: send, read, ask, join, part, channels, who, compact, clear
|
|
196
|
+
"Subcommands: send, read, ask, join, part, channels, who, compact, clear",
|
|
201
197
|
file=sys.stderr,
|
|
202
198
|
)
|
|
203
199
|
sys.exit(1)
|
|
@@ -255,10 +251,6 @@ async def _main(args: list[str]) -> None:
|
|
|
255
251
|
elif subcommand == "clear":
|
|
256
252
|
result = await client.clear()
|
|
257
253
|
|
|
258
|
-
elif subcommand == "set-directory":
|
|
259
|
-
directory = args[1]
|
|
260
|
-
result = await client.set_directory(directory)
|
|
261
|
-
|
|
262
254
|
else:
|
|
263
255
|
print(f"ERROR: Unknown subcommand: {subcommand!r}", file=sys.stderr)
|
|
264
256
|
sys.exit(1)
|
|
@@ -4,6 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import logging
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
import tempfile
|
|
7
10
|
from dataclasses import dataclass
|
|
8
11
|
from typing import Any, Awaitable, Callable
|
|
9
12
|
|
|
@@ -85,6 +88,13 @@ class CodexSupervisor:
|
|
|
85
88
|
transcript = self._format_transcript()
|
|
86
89
|
prompt = SUPERVISOR_PROMPT.format(transcript=transcript)
|
|
87
90
|
|
|
91
|
+
# Isolate from host config (~/.codex/, XDG, etc.)
|
|
92
|
+
isolated_home = tempfile.mkdtemp(prefix="agentirc-codex-sv-")
|
|
93
|
+
isolated_env = dict(os.environ)
|
|
94
|
+
isolated_env["HOME"] = isolated_home
|
|
95
|
+
isolated_env.pop("CODEX_HOME", None)
|
|
96
|
+
isolated_env.pop("XDG_CONFIG_HOME", None)
|
|
97
|
+
|
|
88
98
|
proc = None
|
|
89
99
|
try:
|
|
90
100
|
proc = await asyncio.create_subprocess_exec(
|
|
@@ -92,6 +102,7 @@ class CodexSupervisor:
|
|
|
92
102
|
stdin=asyncio.subprocess.PIPE,
|
|
93
103
|
stdout=asyncio.subprocess.PIPE,
|
|
94
104
|
stderr=asyncio.subprocess.DEVNULL,
|
|
105
|
+
env=isolated_env,
|
|
95
106
|
)
|
|
96
107
|
stdout, _ = await asyncio.wait_for(
|
|
97
108
|
proc.communicate(prompt.encode()),
|
|
@@ -116,6 +127,8 @@ class CodexSupervisor:
|
|
|
116
127
|
pass
|
|
117
128
|
await proc.wait()
|
|
118
129
|
return
|
|
130
|
+
finally:
|
|
131
|
+
shutil.rmtree(isolated_home, ignore_errors=True)
|
|
119
132
|
|
|
120
133
|
if verdict.action == "ESCALATION":
|
|
121
134
|
self._escalation_count += 1
|
|
@@ -4,6 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import logging
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
import tempfile
|
|
7
10
|
from typing import Any, Awaitable, Callable
|
|
8
11
|
|
|
9
12
|
logger = logging.getLogger(__name__)
|
|
@@ -28,6 +31,7 @@ class CopilotAgentRunner:
|
|
|
28
31
|
self.on_exit = on_exit
|
|
29
32
|
self.on_message = on_message
|
|
30
33
|
|
|
34
|
+
self._isolated_home: str | None = None
|
|
31
35
|
self._client: Any = None
|
|
32
36
|
self._session: Any = None
|
|
33
37
|
self._session_id: str | None = None
|
|
@@ -50,41 +54,50 @@ class CopilotAgentRunner:
|
|
|
50
54
|
# Lazy import — github-copilot-sdk is only needed at runtime
|
|
51
55
|
from copilot import CopilotClient, PermissionHandler, SubprocessConfig
|
|
52
56
|
|
|
53
|
-
#
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
# Isolate from host config
|
|
58
|
+
self._isolated_home = tempfile.mkdtemp(prefix="agentirc-copilot-")
|
|
59
|
+
isolated_env = {**os.environ, "HOME": self._isolated_home}
|
|
60
|
+
isolated_env.pop("XDG_CONFIG_HOME", None)
|
|
57
61
|
|
|
58
|
-
# Create a session with model and permissions.
|
|
59
|
-
# Wrap in try/except so a partial start doesn't leak the CLI process.
|
|
60
62
|
try:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
session_kwargs[
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
# Create and start the CopilotClient (spawns copilot CLI process)
|
|
64
|
+
subprocess_config = SubprocessConfig(cwd=self.directory, env=isolated_env)
|
|
65
|
+
self._client = CopilotClient(config=subprocess_config)
|
|
66
|
+
await self._client.start()
|
|
67
|
+
|
|
68
|
+
# Create a session with model and permissions.
|
|
69
|
+
try:
|
|
70
|
+
session_kwargs: dict[str, Any] = {
|
|
71
|
+
"on_permission_request": PermissionHandler.approve_all,
|
|
72
|
+
"model": self.model,
|
|
73
|
+
}
|
|
74
|
+
if self.system_prompt:
|
|
75
|
+
session_kwargs["system_message"] = {"content": self.system_prompt}
|
|
76
|
+
if self.skill_directories:
|
|
77
|
+
session_kwargs["skill_directories"] = self.skill_directories
|
|
78
|
+
|
|
79
|
+
self._session = await self._client.create_session(**session_kwargs)
|
|
80
|
+
except Exception:
|
|
81
|
+
await self._client.stop()
|
|
82
|
+
self._client = None
|
|
83
|
+
raise
|
|
84
|
+
self._session_id = getattr(self._session, "id", None)
|
|
85
|
+
self._running = True
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
logger.info(
|
|
88
|
+
"CopilotAgentRunner started (model=%s, session=%s)",
|
|
89
|
+
self.model, self._session_id,
|
|
90
|
+
)
|
|
82
91
|
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
# Start the prompt processing loop
|
|
93
|
+
self._task = asyncio.create_task(self._prompt_loop())
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
if initial_prompt:
|
|
96
|
+
await self.send_prompt(initial_prompt)
|
|
97
|
+
except Exception:
|
|
98
|
+
shutil.rmtree(self._isolated_home, ignore_errors=True)
|
|
99
|
+
self._isolated_home = None
|
|
100
|
+
raise
|
|
88
101
|
|
|
89
102
|
async def stop(self) -> None:
|
|
90
103
|
"""Stop the Copilot session and client."""
|
|
@@ -113,6 +126,10 @@ class CopilotAgentRunner:
|
|
|
113
126
|
logger.debug("Client stop error (ignoring)", exc_info=True)
|
|
114
127
|
self._client = None
|
|
115
128
|
|
|
129
|
+
if self._isolated_home:
|
|
130
|
+
shutil.rmtree(self._isolated_home, ignore_errors=True)
|
|
131
|
+
self._isolated_home = None
|
|
132
|
+
|
|
116
133
|
async def send_prompt(self, text: str) -> None:
|
|
117
134
|
"""Queue a prompt for the agent."""
|
|
118
135
|
await self._prompt_queue.put(text)
|
|
@@ -334,9 +334,6 @@ class CopilotDaemon:
|
|
|
334
334
|
elif msg_type == "irc_ask":
|
|
335
335
|
return await self._ipc_irc_ask(req_id, msg)
|
|
336
336
|
|
|
337
|
-
elif msg_type == "set_directory":
|
|
338
|
-
return await self._ipc_set_directory(req_id, msg)
|
|
339
|
-
|
|
340
337
|
elif msg_type == "compact":
|
|
341
338
|
return await self._ipc_compact(req_id)
|
|
342
339
|
|
|
@@ -430,26 +427,6 @@ class CopilotDaemon:
|
|
|
430
427
|
# Response matching is TODO
|
|
431
428
|
return make_response(req_id, ok=True)
|
|
432
429
|
|
|
433
|
-
async def _ipc_set_directory(self, req_id: str, msg: dict) -> dict:
|
|
434
|
-
path = msg.get("path", "")
|
|
435
|
-
if not path:
|
|
436
|
-
return make_response(req_id, ok=False, error="Missing 'path'")
|
|
437
|
-
new_cwd = os.path.abspath(path)
|
|
438
|
-
if not os.path.isdir(new_cwd):
|
|
439
|
-
return make_response(req_id, ok=False, error=f"Not a directory: {new_cwd}")
|
|
440
|
-
# Update the daemon's working directory
|
|
441
|
-
self.agent.directory = new_cwd
|
|
442
|
-
# Check for .github/copilot-instructions.md (Copilot's project instructions)
|
|
443
|
-
copilot_instructions = os.path.join(new_cwd, ".github", "copilot-instructions.md")
|
|
444
|
-
instructions_content = None
|
|
445
|
-
if os.path.isfile(copilot_instructions):
|
|
446
|
-
with open(copilot_instructions) as f:
|
|
447
|
-
instructions_content = f.read()
|
|
448
|
-
return make_response(req_id, ok=True, data={
|
|
449
|
-
"directory": new_cwd,
|
|
450
|
-
"copilot_instructions": instructions_content,
|
|
451
|
-
})
|
|
452
|
-
|
|
453
430
|
async def _ipc_compact(self, req_id: str) -> dict:
|
|
454
431
|
if self._agent_runner is None or not self._agent_runner.is_running():
|
|
455
432
|
return make_response(req_id, ok=False, error="Agent runner is not running")
|
|
@@ -173,10 +173,6 @@ class SkillClient:
|
|
|
173
173
|
"""Send /clear to the Copilot agent runner."""
|
|
174
174
|
return await self._request("clear")
|
|
175
175
|
|
|
176
|
-
async def set_directory(self, directory: str) -> dict[str, Any]:
|
|
177
|
-
"""Change the working directory for the agent runner."""
|
|
178
|
-
return await self._request("set_directory", path=directory)
|
|
179
|
-
|
|
180
176
|
|
|
181
177
|
# ---------------------------------------------------------------------------
|
|
182
178
|
# CLI
|
|
@@ -197,7 +193,7 @@ async def _main(args: list[str]) -> None:
|
|
|
197
193
|
if not args:
|
|
198
194
|
print(
|
|
199
195
|
"Usage: irc_client.py <subcommand> [args...]\n"
|
|
200
|
-
"Subcommands: send, read, ask, join, part, channels, who, compact, clear
|
|
196
|
+
"Subcommands: send, read, ask, join, part, channels, who, compact, clear",
|
|
201
197
|
file=sys.stderr,
|
|
202
198
|
)
|
|
203
199
|
sys.exit(1)
|
|
@@ -255,10 +251,6 @@ async def _main(args: list[str]) -> None:
|
|
|
255
251
|
elif subcommand == "clear":
|
|
256
252
|
result = await client.clear()
|
|
257
253
|
|
|
258
|
-
elif subcommand == "set-directory":
|
|
259
|
-
directory = args[1]
|
|
260
|
-
result = await client.set_directory(directory)
|
|
261
|
-
|
|
262
254
|
else:
|
|
263
255
|
print(f"ERROR: Unknown subcommand: {subcommand!r}", file=sys.stderr)
|
|
264
256
|
sys.exit(1)
|
|
@@ -4,6 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import logging
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
import tempfile
|
|
7
10
|
from dataclasses import dataclass
|
|
8
11
|
from typing import Any, Awaitable, Callable
|
|
9
12
|
|
|
@@ -85,11 +88,16 @@ class CopilotSupervisor:
|
|
|
85
88
|
transcript = self._format_transcript()
|
|
86
89
|
prompt = SUPERVISOR_PROMPT.format(transcript=transcript)
|
|
87
90
|
|
|
91
|
+
# Isolate from host config
|
|
92
|
+
isolated_home = tempfile.mkdtemp(prefix="agentirc-copilot-sv-")
|
|
93
|
+
|
|
88
94
|
try:
|
|
89
|
-
from copilot import CopilotClient
|
|
95
|
+
from copilot import CopilotClient, SubprocessConfig
|
|
90
96
|
from copilot.session import PermissionHandler
|
|
91
97
|
|
|
92
|
-
|
|
98
|
+
isolated_env = {**os.environ, "HOME": isolated_home}
|
|
99
|
+
subprocess_config = SubprocessConfig(env=isolated_env)
|
|
100
|
+
client = CopilotClient(config=subprocess_config)
|
|
93
101
|
await client.start()
|
|
94
102
|
try:
|
|
95
103
|
session = await client.create_session(
|
|
@@ -117,6 +125,8 @@ class CopilotSupervisor:
|
|
|
117
125
|
except Exception:
|
|
118
126
|
logger.exception("Copilot supervisor evaluation failed")
|
|
119
127
|
return
|
|
128
|
+
finally:
|
|
129
|
+
shutil.rmtree(isolated_home, ignore_errors=True)
|
|
120
130
|
|
|
121
131
|
if verdict.action == "ESCALATION":
|
|
122
132
|
self._escalation_count += 1
|