agentirc-cli 0.15.0__tar.gz → 0.15.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-0.15.2/.pr_agent.toml +38 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/CHANGELOG.md +15 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/PKG-INFO +1 -1
- agentirc_cli-0.15.2/agentirc/__init__.py +3 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/overview/renderer_web.py +69 -3
- agentirc_cli-0.15.2/agentirc/pidfile.py +84 -0
- agentirc_cli-0.15.2/docs/harness-conformance.md +84 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/overview.md +14 -0
- agentirc_cli-0.15.2/docs/superpowers/plans/2026-03-30-overview.md +1626 -0
- agentirc_cli-0.15.2/docs/superpowers/specs/2026-03-30-overview-design.md +328 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/pyproject.toml +1 -1
- agentirc_cli-0.15.2/tests/test_overview_web.py +165 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/uv.lock +1 -1
- agentirc_cli-0.15.0/.pr_agent.toml +0 -9
- agentirc_cli-0.15.0/agentirc/__init__.py +0 -1
- agentirc_cli-0.15.0/agentirc/pidfile.py +0 -49
- agentirc_cli-0.15.0/tests/test_overview_web.py +0 -58
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/.gitignore +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/CLAUDE.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/CNAME +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/Gemfile +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/Gemfile.lock +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/LICENSE +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/README.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/_config.yml +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/__main__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/cli.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/__main__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/agent_runner.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/config.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/ipc.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/irc_transport.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/skill/irc_client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/socket_server.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/supervisor.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/claude/webhook.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/agent_runner.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/config.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/ipc.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/irc_transport.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/skill/irc_client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/socket_server.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/supervisor.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/codex/webhook.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/config.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/ipc.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/irc_transport.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/skill/irc_client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/socket_server.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/copilot/webhook.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/agent_runner.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/config.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/ipc.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/irc_transport.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/message_buffer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/skill/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/skill/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/skill/irc_client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/socket_server.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/supervisor.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/clients/opencode/webhook.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/learn_prompt.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/observer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/overview/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/overview/collector.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/overview/model.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/overview/renderer_text.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/overview/web/style.css +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/commands.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/extensions/federation.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/extensions/history.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/extensions/tags.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/message.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/protocol-index.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/protocol/replies.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/__main__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/channel.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/config.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/ircd.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/remote_client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/room_store.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/rooms_util.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/server_link.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/skill.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/skills/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/skills/history.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/agentirc/server/skills/rooms.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/agent-client.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/agent-harness-spec.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/ci.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/cli.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/opencode/configuration.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/opencode/context-management.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/opencode/irc-tools.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/opencode/overview.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/opencode/setup.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/opencode/supervisor.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/clients/opencode/webhooks.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/codex-backend.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/copilot-backend.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/design.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/docs-site.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/getting-started.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/grow-your-agent.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/layer1-core-irc.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/layer2-attention.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/layer3-skills.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/layer4-federation.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/layer5-agent-harness.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/opencode-backend.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/publishing.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/rooms.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/server-architecture.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases/10-grow-your-agent.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/docs/use-cases-index.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/index.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/irc_transport.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/message_buffer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/skill/irc_client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/socket_server.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/plugins/codex/skills/agentirc-irc/SKILL.md +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/__init__.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/conftest.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_agent_runner.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_channel.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_connection.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_discovery.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_federation.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_history.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_ipc.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_mentions.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_message.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_messaging.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_modes.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_opencode_daemon.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_overview_model.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_rooms.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_skill_client.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_skills.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_socket_server.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_supervisor.py +0 -0
- {agentirc_cli-0.15.0 → agentirc_cli-0.15.2}/tests/test_webhook.py +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[pr_reviewer]
|
|
2
|
+
extra_instructions = """
|
|
3
|
+
## Project Context
|
|
4
|
+
|
|
5
|
+
- The `packages/` directory is ONLY for the "assimilai" pattern (internal packages copied into other projects). Top-level directories like `server/`, `protocol/`, and `clients/` are standalone application packages — they belong at the top level, NOT under `packages/`.
|
|
6
|
+
- The "no mocks for the server" testing rule applies to IRC server tests only. Client libraries (like SkillClient) may use mock/stub servers in unit tests. Integration tests in `test_integration_layer5.py` exercise the real server stack.
|
|
7
|
+
- Nick format validation (`<server>-<agent>`) is enforced by the IRC server at connection time. Config loading is a data layer and should not duplicate server-side validation.
|
|
8
|
+
- Features explicitly marked as TODO or listed in the spec's "Deferred Features" section are known limitations, not bugs.
|
|
9
|
+
- The `clients/` directory contains agent client harnesses (daemons). It is NOT an internal package for assimilation.
|
|
10
|
+
|
|
11
|
+
## Harness Conformance (CRITICAL)
|
|
12
|
+
|
|
13
|
+
The authoritative spec is `docs/agent-harness-spec.md`. There are 4 agent backends under `agentirc/clients/` — claude, codex, copilot, opencode — plus a reference implementation in `packages/agent-harness/`. The all-backends rule: a feature that exists in only one backend is a bug.
|
|
14
|
+
|
|
15
|
+
When reviewing changes to any file under `agentirc/clients/` or `packages/agent-harness/`, apply these checks:
|
|
16
|
+
|
|
17
|
+
### Cross-backend propagation
|
|
18
|
+
When a PR changes a file in `agentirc/clients/<backend>/`, check whether the same change must be applied to the other 3 backends. If corresponding files in other backends were not updated, flag each missing backend. Exception: `agent_runner.py` and `supervisor.py` contain backend-specific logic — only structural/interface changes need propagation, not internal implementation details.
|
|
19
|
+
|
|
20
|
+
### Generic file identity
|
|
21
|
+
These files MUST be identical across all 4 backends and `packages/agent-harness/`, except for import paths (`from agentirc.clients.<backend>.`): `irc_transport.py`, `message_buffer.py`, `socket_server.py`, `ipc.py`, `webhook.py`, `skill/irc_client.py`. If any of these is changed in one backend, flag that all other backends AND the reference in `packages/agent-harness/` must get the same change.
|
|
22
|
+
|
|
23
|
+
### Interface contract
|
|
24
|
+
If `agent_runner.py` is modified, verify the public interface still satisfies `docs/agent-harness-spec.md` AgentRunnerBase: `start(initial_prompt)`, `stop()`, `send_prompt(text)`, `is_running()`, `session_id` property, `on_message` callback, `on_exit` callback. If `supervisor.py` is modified, verify SupervisorBase: `start()`, `stop()`, `observe(turn)`, `on_whisper` callback, `on_escalation` callback. Flag any missing or renamed interface members.
|
|
25
|
+
|
|
26
|
+
### Daemon contract
|
|
27
|
+
If `daemon.py` is modified, verify all IPC dispatch handlers are still present: `irc_send`, `irc_read`, `irc_ask`, `irc_join`, `irc_part`, `irc_who`, `irc_channels`, `compact`, `clear`, `shutdown`. Also verify structural features (crash recovery, `_mention_targets`, sleep scheduler) are consistent across backends. If a structural feature is added to one daemon, flag its absence in the others.
|
|
28
|
+
|
|
29
|
+
### Config schema
|
|
30
|
+
If `config.py` is modified, verify the same dataclass field names and types exist across all 4 backends. Only default values may differ by backend (e.g., model names). If a new field is added to one backend's config, flag its absence in the others.
|
|
31
|
+
|
|
32
|
+
### SKILL.md consistency
|
|
33
|
+
If any `SKILL.md` under `agentirc/clients/<backend>/skill/` is modified, verify all backends' SKILL.md documents the same required commands: send, read, ask, join, part, channels, who. Flag format or content inconsistencies.
|
|
34
|
+
|
|
35
|
+
### Spec-doc alignment
|
|
36
|
+
If `docs/agent-harness-spec.md` is changed, verify that client docs in `docs/clients/` and the actual code in `agentirc/clients/` still match the updated spec. If code or docs under `docs/clients/` is changed, verify it does not contradict the spec.
|
|
37
|
+
"""
|
|
38
|
+
num_max_findings = 10
|
|
@@ -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
|
+
## [0.15.2] - 2026-03-31
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Extended .pr_agent.toml with harness conformance checks for cross-backend validation
|
|
13
|
+
|
|
14
|
+
## [0.15.1] - 2026-03-30
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Overview serve: flush stdout so port URL is visible when backgrounded
|
|
20
|
+
- Overview serve: auto-kill previous instance for same server via PID/port files
|
|
21
|
+
|
|
7
22
|
## [0.15.0] - 2026-03-30
|
|
8
23
|
|
|
9
24
|
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
"""Render mesh overview as HTML and serve via HTTP."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
import atexit
|
|
4
5
|
import asyncio
|
|
5
6
|
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
|
7
|
+
import os
|
|
6
8
|
from pathlib import Path
|
|
9
|
+
import signal
|
|
10
|
+
import threading
|
|
11
|
+
import time
|
|
7
12
|
|
|
8
13
|
import re
|
|
9
14
|
|
|
10
15
|
import mistune
|
|
11
16
|
|
|
17
|
+
from agentirc.pidfile import (
|
|
18
|
+
is_process_alive, read_pid, read_port,
|
|
19
|
+
remove_pid, remove_port, write_pid, write_port,
|
|
20
|
+
)
|
|
12
21
|
from .collector import collect_mesh_state
|
|
13
22
|
from .model import MeshState
|
|
14
23
|
from .renderer_text import render_text
|
|
@@ -72,6 +81,45 @@ def render_html(
|
|
|
72
81
|
</html>"""
|
|
73
82
|
|
|
74
83
|
|
|
84
|
+
def _stop_existing_overview(pid_name: str) -> None:
|
|
85
|
+
"""Kill a previous overview instance if running, clean up its files."""
|
|
86
|
+
existing_pid = read_pid(pid_name)
|
|
87
|
+
if existing_pid and is_process_alive(existing_pid):
|
|
88
|
+
existing_port = read_port(pid_name)
|
|
89
|
+
try:
|
|
90
|
+
os.kill(existing_pid, signal.SIGTERM)
|
|
91
|
+
except (PermissionError, ProcessLookupError) as exc:
|
|
92
|
+
remove_pid(pid_name)
|
|
93
|
+
remove_port(pid_name)
|
|
94
|
+
port_msg = f", port {existing_port}" if existing_port else ""
|
|
95
|
+
print(
|
|
96
|
+
f"Warning: could not stop previous overview (PID {existing_pid}"
|
|
97
|
+
f"{port_msg}): {exc}",
|
|
98
|
+
flush=True,
|
|
99
|
+
)
|
|
100
|
+
return
|
|
101
|
+
for _ in range(20):
|
|
102
|
+
if not is_process_alive(existing_pid):
|
|
103
|
+
break
|
|
104
|
+
time.sleep(0.1)
|
|
105
|
+
else:
|
|
106
|
+
try:
|
|
107
|
+
os.kill(existing_pid, signal.SIGKILL)
|
|
108
|
+
except (PermissionError, ProcessLookupError):
|
|
109
|
+
pass
|
|
110
|
+
remove_pid(pid_name)
|
|
111
|
+
remove_port(pid_name)
|
|
112
|
+
port_msg = f", port {existing_port}" if existing_port else ""
|
|
113
|
+
print(
|
|
114
|
+
f"Stopped previous overview for '{pid_name.removeprefix('overview-')}'"
|
|
115
|
+
f" (PID {existing_pid}{port_msg})",
|
|
116
|
+
flush=True,
|
|
117
|
+
)
|
|
118
|
+
elif existing_pid:
|
|
119
|
+
remove_pid(pid_name)
|
|
120
|
+
remove_port(pid_name)
|
|
121
|
+
|
|
122
|
+
|
|
75
123
|
def serve_web(
|
|
76
124
|
host: str,
|
|
77
125
|
port: int,
|
|
@@ -84,6 +132,8 @@ def serve_web(
|
|
|
84
132
|
serve_port: int = 0,
|
|
85
133
|
) -> None:
|
|
86
134
|
"""Start a local HTTP server serving the live overview."""
|
|
135
|
+
pid_name = f"overview-{server_name}"
|
|
136
|
+
_stop_existing_overview(pid_name)
|
|
87
137
|
|
|
88
138
|
class OverviewHandler(SimpleHTTPRequestHandler):
|
|
89
139
|
def do_GET(self):
|
|
@@ -110,11 +160,27 @@ def serve_web(
|
|
|
110
160
|
|
|
111
161
|
httpd = HTTPServer(("127.0.0.1", serve_port), OverviewHandler)
|
|
112
162
|
actual_port = httpd.server_address[1]
|
|
113
|
-
|
|
114
|
-
|
|
163
|
+
|
|
164
|
+
write_pid(pid_name, os.getpid())
|
|
165
|
+
write_port(pid_name, actual_port)
|
|
166
|
+
|
|
167
|
+
def _cleanup():
|
|
168
|
+
remove_pid(pid_name)
|
|
169
|
+
remove_port(pid_name)
|
|
170
|
+
|
|
171
|
+
atexit.register(_cleanup)
|
|
172
|
+
if threading.current_thread() is threading.main_thread():
|
|
173
|
+
def _handle_term(_sig, _frame):
|
|
174
|
+
threading.Thread(target=httpd.shutdown, daemon=True).start()
|
|
175
|
+
signal.signal(signal.SIGTERM, _handle_term)
|
|
176
|
+
|
|
177
|
+
print(f"Overview dashboard: http://localhost:{actual_port}", flush=True)
|
|
178
|
+
print("Press Ctrl+C to stop.", flush=True)
|
|
115
179
|
try:
|
|
116
180
|
httpd.serve_forever()
|
|
117
181
|
except KeyboardInterrupt:
|
|
118
|
-
print("\nStopped.")
|
|
182
|
+
print("\nStopped.", flush=True)
|
|
119
183
|
finally:
|
|
120
184
|
httpd.server_close()
|
|
185
|
+
_cleanup()
|
|
186
|
+
atexit.unregister(_cleanup)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""PID file management for agentirc daemon instances."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
PID_DIR = os.path.expanduser("~/.agentirc/pids")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _safe_name(name: str) -> str:
|
|
13
|
+
"""Sanitize a daemon name to prevent path traversal."""
|
|
14
|
+
return re.sub(r"[^a-zA-Z0-9._-]", "_", Path(name).name)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def write_pid(name: str, pid: int) -> Path:
|
|
18
|
+
"""Write a PID file for the named daemon. Creates the directory if needed."""
|
|
19
|
+
pid_dir = Path(PID_DIR)
|
|
20
|
+
pid_dir.mkdir(parents=True, exist_ok=True)
|
|
21
|
+
pid_path = pid_dir / f"{_safe_name(name)}.pid"
|
|
22
|
+
pid_path.write_text(str(pid))
|
|
23
|
+
return pid_path
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def read_pid(name: str) -> int | None:
|
|
27
|
+
"""Read the PID for the named daemon. Returns None if file is missing."""
|
|
28
|
+
pid_path = Path(PID_DIR) / f"{_safe_name(name)}.pid"
|
|
29
|
+
if not pid_path.exists():
|
|
30
|
+
return None
|
|
31
|
+
try:
|
|
32
|
+
return int(pid_path.read_text().strip())
|
|
33
|
+
except (ValueError, OSError):
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def remove_pid(name: str) -> None:
|
|
38
|
+
"""Remove the PID file for the named daemon if it exists."""
|
|
39
|
+
pid_path = Path(PID_DIR) / f"{_safe_name(name)}.pid"
|
|
40
|
+
try:
|
|
41
|
+
pid_path.unlink()
|
|
42
|
+
except FileNotFoundError:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def write_port(name: str, port: int) -> Path:
|
|
47
|
+
"""Write a port file for the named daemon. Creates the directory if needed."""
|
|
48
|
+
pid_dir = Path(PID_DIR)
|
|
49
|
+
pid_dir.mkdir(parents=True, exist_ok=True)
|
|
50
|
+
port_path = pid_dir / f"{_safe_name(name)}.port"
|
|
51
|
+
port_path.write_text(str(port))
|
|
52
|
+
return port_path
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def read_port(name: str) -> int | None:
|
|
56
|
+
"""Read the port for the named daemon. Returns None if file is missing."""
|
|
57
|
+
port_path = Path(PID_DIR) / f"{_safe_name(name)}.port"
|
|
58
|
+
if not port_path.exists():
|
|
59
|
+
return None
|
|
60
|
+
try:
|
|
61
|
+
return int(port_path.read_text().strip())
|
|
62
|
+
except (ValueError, OSError):
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def remove_port(name: str) -> None:
|
|
67
|
+
"""Remove the port file for the named daemon if it exists."""
|
|
68
|
+
port_path = Path(PID_DIR) / f"{_safe_name(name)}.port"
|
|
69
|
+
try:
|
|
70
|
+
port_path.unlink()
|
|
71
|
+
except FileNotFoundError:
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def is_process_alive(pid: int) -> bool:
|
|
76
|
+
"""Check whether a process with the given PID is alive."""
|
|
77
|
+
try:
|
|
78
|
+
os.kill(pid, 0)
|
|
79
|
+
return True
|
|
80
|
+
except ProcessLookupError:
|
|
81
|
+
return False
|
|
82
|
+
except PermissionError:
|
|
83
|
+
# Process exists but we don't have permission to signal it
|
|
84
|
+
return True
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Harness Conformance"
|
|
3
|
+
parent: "Agent Harness"
|
|
4
|
+
nav_order: 8
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Harness Conformance Checks
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Qodo PR review is configured to enforce conformance across all 4 agent
|
|
12
|
+
backends (claude, codex, copilot, opencode). When a PR touches files under
|
|
13
|
+
`agentirc/clients/` or `packages/agent-harness/`, Qodo applies 7 checks
|
|
14
|
+
that prevent backends from drifting apart.
|
|
15
|
+
|
|
16
|
+
The authoritative spec is `docs/agent-harness-spec.md`.
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
All conformance rules live in `.pr_agent.toml` under the `[pr_reviewer]`
|
|
21
|
+
section's `extra_instructions` field.
|
|
22
|
+
|
|
23
|
+
## Checks
|
|
24
|
+
|
|
25
|
+
### 1. Cross-backend propagation
|
|
26
|
+
|
|
27
|
+
When a file in one backend changes, Qodo flags if the corresponding files
|
|
28
|
+
in the other 3 backends were not updated. Exception: `agent_runner.py` and
|
|
29
|
+
`supervisor.py` contain backend-specific logic — only structural/interface
|
|
30
|
+
changes need propagation.
|
|
31
|
+
|
|
32
|
+
### 2. Generic file identity
|
|
33
|
+
|
|
34
|
+
These files must be identical across all backends and the reference in
|
|
35
|
+
`packages/agent-harness/`, except for import paths:
|
|
36
|
+
|
|
37
|
+
- `irc_transport.py`
|
|
38
|
+
- `message_buffer.py`
|
|
39
|
+
- `socket_server.py`
|
|
40
|
+
- `ipc.py`
|
|
41
|
+
- `webhook.py`
|
|
42
|
+
- `skill/irc_client.py`
|
|
43
|
+
|
|
44
|
+
### 3. Interface contract
|
|
45
|
+
|
|
46
|
+
Changes to `agent_runner.py` or `supervisor.py` are checked against the
|
|
47
|
+
spec's `AgentRunnerBase` and `SupervisorBase` interfaces.
|
|
48
|
+
|
|
49
|
+
**AgentRunnerBase** requires: `start(initial_prompt)`, `stop()`,
|
|
50
|
+
`send_prompt(text)`, `is_running()`, `session_id`, `on_message`, `on_exit`.
|
|
51
|
+
|
|
52
|
+
**SupervisorBase** requires: `start()`, `stop()`, `observe(turn)`,
|
|
53
|
+
`on_whisper`, `on_escalation`.
|
|
54
|
+
|
|
55
|
+
### 4. Daemon contract
|
|
56
|
+
|
|
57
|
+
Changes to `daemon.py` are checked for all IPC dispatch handlers:
|
|
58
|
+
`irc_send`, `irc_read`, `irc_ask`, `irc_join`, `irc_part`, `irc_who`,
|
|
59
|
+
`irc_channels`, `compact`, `clear`, `shutdown`.
|
|
60
|
+
|
|
61
|
+
Structural features (crash recovery, `_mention_targets`, sleep scheduler)
|
|
62
|
+
must be consistent across backends.
|
|
63
|
+
|
|
64
|
+
### 5. Config schema
|
|
65
|
+
|
|
66
|
+
Changes to `config.py` must preserve the same field names and types across
|
|
67
|
+
all backends. Only default values (model names, agent identifiers) may
|
|
68
|
+
differ.
|
|
69
|
+
|
|
70
|
+
### 6. SKILL.md consistency
|
|
71
|
+
|
|
72
|
+
All backends' `SKILL.md` must document the same required commands: `send`,
|
|
73
|
+
`read`, `ask`, `join`, `part`, `channels`, `who`.
|
|
74
|
+
|
|
75
|
+
### 7. Spec-doc alignment
|
|
76
|
+
|
|
77
|
+
Changes to `docs/agent-harness-spec.md` are cross-referenced against
|
|
78
|
+
client docs in `docs/clients/` and the code in `agentirc/clients/`.
|
|
79
|
+
Changes to client docs or code are checked against the spec.
|
|
80
|
+
|
|
81
|
+
## Adding New Checks
|
|
82
|
+
|
|
83
|
+
Edit `.pr_agent.toml` and add a new subsection under the
|
|
84
|
+
`## Harness Conformance (CRITICAL)` heading in `extra_instructions`.
|
|
@@ -48,6 +48,20 @@ memberships with roles, and cross-channel recent activity.
|
|
|
48
48
|
styled HTML with the anthropic cream theme. Auto-refreshes at the interval
|
|
49
49
|
set by `--refresh` (default: 5 seconds).
|
|
50
50
|
|
|
51
|
+
### Instance Management
|
|
52
|
+
|
|
53
|
+
Each overview server registers itself with a PID and port file in
|
|
54
|
+
`~/.agentirc/pids/` (e.g., `overview-spark.pid`, `overview-spark.port`).
|
|
55
|
+
|
|
56
|
+
- **One per server**: Starting a new overview for the same IRC server
|
|
57
|
+
auto-kills the previous instance via SIGTERM (with SIGKILL fallback).
|
|
58
|
+
- **Multiple servers**: Different IRC servers can each have their own
|
|
59
|
+
overview site running simultaneously (keyed by `server_name`).
|
|
60
|
+
- **Graceful shutdown**: SIGTERM and Ctrl+C both trigger clean shutdown
|
|
61
|
+
with PID/port file removal.
|
|
62
|
+
- **Background visibility**: The dashboard URL is flushed to stdout
|
|
63
|
+
immediately, so it appears even when the process runs in the background.
|
|
64
|
+
|
|
51
65
|
## Data Sources
|
|
52
66
|
|
|
53
67
|
- **IRC Observer**: Ephemeral connection queries LIST, NAMES, WHO, HISTORY
|