agentirc-cli 9.7.0__tar.gz → 9.8.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-9.7.0 → agentirc_cli-9.8.0}/CHANGELOG.md +23 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/PKG-INFO +35 -12
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/README.md +34 -11
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/cli.py +40 -1
- agentirc_cli-9.8.0/docs/bots.md +174 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/pyproject.toml +1 -1
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_cli_bot.py +56 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/uv.lock +1 -1
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/cicd/SKILL.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/SKILL.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/think/SKILL.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/think/scripts/think.sh +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills.local.yaml.example +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.devague/current +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.devague/current_plan +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.devague/frames/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.devague/plans/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.gitignore +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/CLAUDE.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/LICENSE +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/__main__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/aio.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/bots/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/bots/bot_manager.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/bots/http_listener.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/cli_shared/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/cli_shared/constants.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/cli_shared/mesh.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/constants.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/event_subscriptions.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/pidfile.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/protocol/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/protocol/message.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/protocol/replies.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/telemetry/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/telemetry/audit.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/telemetry/context.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/telemetry/metrics.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/telemetry/tracing.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/_internal/virtual_client.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/bot.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/bot_manager.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/config.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/filter_dsl.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/http_listener.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/template_engine.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/bots/virtual_client.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/channel.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/cli.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/client.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/config.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/events.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/history_store.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/ircd.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/protocol.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/remote_client.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/room_store.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/rooms_util.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/server_link.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/skill.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/skills/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/skills/history.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/skills/icon.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/skills/rooms.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/skills/threads.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/thread_store.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/agentirc/virtual_client.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/api-stability.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/cli.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/deployment.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/extension-api.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/plans/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/specs/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/steward/onboarding.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/superpowers/specs/2026-04-30-bootstrap-design.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/superpowers/specs/2026-05-01-bot-extension-api-design.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/superpowers/specs/2026-05-01-task14-audit.md +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/_helpers.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_bot.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_bot_host.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_bot_manager.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_config_bots.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_filter_dsl.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_http_listener.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_public_surface.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/bots/test_template_engine.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/conftest.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/__init__.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/_fakes.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/_metrics_helpers.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_audit_emit.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_audit_lifecycle.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_audit_module.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_audit_parse_error.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_config.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_dispatch_span.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_emit_event_span.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_metrics_init.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_metrics_s2s.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_outbound_inject.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_parse_error.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_s2s_relay_span.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_server_init.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_server_link_inject.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/telemetry/test_tracing.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_api_stability_embedding.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_bot_capability.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_channel.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_cli.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_config_loader.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_connection.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_discovery.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_event_subscriptions.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_eventpub.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_events_basic.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_events_catalog.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_events_federation.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_events_history.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_events_lifecycle.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_events_reserved_nick.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_federation.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_history.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_mentions.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_messaging.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_modes.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_protocol_bot_exports.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_skills.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_threads.py +0 -0
- {agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/tests/test_wire_format_envelope.py +0 -0
|
@@ -4,6 +4,29 @@ 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
|
+
## [9.8.0] - 2026-06-12
|
|
8
|
+
|
|
9
|
+
Make bot authoring discoverable: a dedicated guide plus first-class CLI support
|
|
10
|
+
for event-triggered bots.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`agentirc bot create --trigger event --event-filter "<expr>"`** — the CLI
|
|
15
|
+
can now create event-triggered bots, not just `webhook` ones. The filter is
|
|
16
|
+
compiled and validated at create time (a malformed expression is rejected
|
|
17
|
+
immediately). `--event-filter` is required for `--trigger event` and rejected
|
|
18
|
+
for `--trigger webhook`.
|
|
19
|
+
- **[`docs/bots.md`](docs/bots.md)** — a bot-authoring guide: CLI quick start
|
|
20
|
+
for both trigger types, the `bot.yaml` schema for hand-authoring, the
|
|
21
|
+
event-filter DSL grammar, and templating. Linked from the README.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- README public-API table now lists all six public modules (it had drifted to
|
|
26
|
+
three) and gains an "Embedded bots" section. Corrected the stale 9.5.0
|
|
27
|
+
"webhook never bound" operational note — since 9.7.0 `IRCd.start()` binds the
|
|
28
|
+
listener when `webhook_port > 0`.
|
|
29
|
+
|
|
7
30
|
## [9.7.0] - 2026-06-12
|
|
8
31
|
|
|
9
32
|
Absorb culture's bot framework into the public `agentirc.bots` subsystem. Closes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentirc-cli
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.8.0
|
|
4
4
|
Summary: Agent-friendly IRCd: server core for AI agent meshes
|
|
5
5
|
Project-URL: Homepage, https://github.com/agentculture/agentirc
|
|
6
6
|
Project-URL: Issues, https://github.com/agentculture/agentirc/issues
|
|
@@ -145,15 +145,18 @@ multi-host federation.
|
|
|
145
145
|
|
|
146
146
|
## Public API and stability
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
Six modules form the **public, semver-tracked surface**. Everything else
|
|
149
149
|
under `agentirc.*` is internal and may be refactored — including renamed,
|
|
150
150
|
split, or removed — in any minor or patch release.
|
|
151
151
|
|
|
152
|
-
| Module | Members |
|
|
153
|
-
|
|
154
|
-
| [`agentirc.config`](docs/api-stability.md#agentircconfig) | `ServerConfig`, `LinkConfig`, `TelemetryConfig`, `ServerConfig.from_yaml(path)` |
|
|
155
|
-
| [`agentirc.cli`](docs/api-stability.md#agentirccli) | `main()`, `dispatch(argv) -> int` |
|
|
156
|
-
| [`agentirc.protocol`](docs/api-stability.md#agentircprotocol) | Verb constants, numeric reply codes, IRCv3/extension tag names, the bot extension surface (`Event`, `EventType`, `EVENT_TYPE_*`, `EVENTSUB`/`EVENTUNSUB`/`EVENT`/`EVENTERR`/`EVENTPUB`/`SEVENT`, `BOT_CAP`) |
|
|
152
|
+
| Module | Members | Since |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| [`agentirc.config`](docs/api-stability.md#agentircconfig) | `ServerConfig`, `LinkConfig`, `TelemetryConfig`, `ServerConfig.from_yaml(path)` | 9.0.0 |
|
|
155
|
+
| [`agentirc.cli`](docs/api-stability.md#agentirccli) | `main()`, `dispatch(argv) -> int` | 9.2.0 |
|
|
156
|
+
| [`agentirc.protocol`](docs/api-stability.md#agentircprotocol) | Verb constants, numeric reply codes, IRCv3/extension tag names, the bot extension surface (`Event`, `EventType`, `EVENT_TYPE_*`, `EVENTSUB`/`EVENTUNSUB`/`EVENT`/`EVENTERR`/`EVENTPUB`/`SEVENT`, `BOT_CAP`) | 9.2.0 |
|
|
157
|
+
| [`agentirc.ircd`](docs/api-stability.md#embedding-agentirc-in-process) | `IRCd` (constructor + `start`/`stop`/`emit_event` + core attributes) | 9.6.0 |
|
|
158
|
+
| [`agentirc.virtual_client`](docs/api-stability.md#embedding-agentirc-in-process) | `VirtualClient` | 9.6.0 |
|
|
159
|
+
| [`agentirc.bots`](docs/api-stability.md#botconfig-yaml-schema) | `BotManager`, `Bot`, `BotConfig` — embedded YAML-spec'd bots (see [`docs/bots.md`](docs/bots.md)) | 9.7.0 |
|
|
157
160
|
|
|
158
161
|
`agentirc.cli.dispatch(argv)` is the in-process integration surface — it is
|
|
159
162
|
what culture's `culture server` shim calls today. It returns `int` on
|
|
@@ -222,11 +225,31 @@ behavior) and
|
|
|
222
225
|
[`docs/api-stability.md#bot-extension-surface-shipped-in-950`](docs/api-stability.md#bot-extension-surface-shipped-in-950)
|
|
223
226
|
for the wire contract.
|
|
224
227
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
## Embedded bots (since 9.7.0)
|
|
229
|
+
|
|
230
|
+
Distinct from the out-of-process extension API above, `agentirc.bots` is an
|
|
231
|
+
**in-process** bot framework: deterministic, YAML-spec'd automations that run as
|
|
232
|
+
`VirtualClient` presences inside the IRCd (no separate process). A bot reacts to
|
|
233
|
+
an event filter or an HTTP webhook and replies with a Jinja2-templated message.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
agentirc bot create pinger --owner ori \
|
|
237
|
+
--trigger event \
|
|
238
|
+
--event-filter "type == 'user.message' and channel == '#general'" \
|
|
239
|
+
--channels '#general' --template 'pong {{event.nick}}'
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Bots live under `~/.culture/bots/<name>/bot.yaml` and load when the server
|
|
243
|
+
starts. See **[`docs/bots.md`](docs/bots.md)** for the authoring guide (CLI +
|
|
244
|
+
hand-written YAML, the two trigger types, the filter DSL, templates) and
|
|
245
|
+
[`docs/api-stability.md`](docs/api-stability.md#botconfig-yaml-schema) for
|
|
246
|
+
embedding a `BotManager` onto a running `IRCd`.
|
|
247
|
+
|
|
248
|
+
**Operational note.** Since 9.7.0, `IRCd.start()` binds the webhook listener
|
|
249
|
+
when `webhook_port` is set (>0), giving webhook-triggered bots HTTP ingress
|
|
250
|
+
under standalone `agentirc serve`; when `webhook_port` is unset/0 nothing is
|
|
251
|
+
bound (preserving the 9.5.0 default). The field stays in `ServerConfig` for
|
|
252
|
+
backward compatibility with culture's `~/.culture/server.yaml`.
|
|
230
253
|
|
|
231
254
|
## Current state and roadmap
|
|
232
255
|
|
|
@@ -107,15 +107,18 @@ multi-host federation.
|
|
|
107
107
|
|
|
108
108
|
## Public API and stability
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
Six modules form the **public, semver-tracked surface**. Everything else
|
|
111
111
|
under `agentirc.*` is internal and may be refactored — including renamed,
|
|
112
112
|
split, or removed — in any minor or patch release.
|
|
113
113
|
|
|
114
|
-
| Module | Members |
|
|
115
|
-
|
|
116
|
-
| [`agentirc.config`](docs/api-stability.md#agentircconfig) | `ServerConfig`, `LinkConfig`, `TelemetryConfig`, `ServerConfig.from_yaml(path)` |
|
|
117
|
-
| [`agentirc.cli`](docs/api-stability.md#agentirccli) | `main()`, `dispatch(argv) -> int` |
|
|
118
|
-
| [`agentirc.protocol`](docs/api-stability.md#agentircprotocol) | Verb constants, numeric reply codes, IRCv3/extension tag names, the bot extension surface (`Event`, `EventType`, `EVENT_TYPE_*`, `EVENTSUB`/`EVENTUNSUB`/`EVENT`/`EVENTERR`/`EVENTPUB`/`SEVENT`, `BOT_CAP`) |
|
|
114
|
+
| Module | Members | Since |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| [`agentirc.config`](docs/api-stability.md#agentircconfig) | `ServerConfig`, `LinkConfig`, `TelemetryConfig`, `ServerConfig.from_yaml(path)` | 9.0.0 |
|
|
117
|
+
| [`agentirc.cli`](docs/api-stability.md#agentirccli) | `main()`, `dispatch(argv) -> int` | 9.2.0 |
|
|
118
|
+
| [`agentirc.protocol`](docs/api-stability.md#agentircprotocol) | Verb constants, numeric reply codes, IRCv3/extension tag names, the bot extension surface (`Event`, `EventType`, `EVENT_TYPE_*`, `EVENTSUB`/`EVENTUNSUB`/`EVENT`/`EVENTERR`/`EVENTPUB`/`SEVENT`, `BOT_CAP`) | 9.2.0 |
|
|
119
|
+
| [`agentirc.ircd`](docs/api-stability.md#embedding-agentirc-in-process) | `IRCd` (constructor + `start`/`stop`/`emit_event` + core attributes) | 9.6.0 |
|
|
120
|
+
| [`agentirc.virtual_client`](docs/api-stability.md#embedding-agentirc-in-process) | `VirtualClient` | 9.6.0 |
|
|
121
|
+
| [`agentirc.bots`](docs/api-stability.md#botconfig-yaml-schema) | `BotManager`, `Bot`, `BotConfig` — embedded YAML-spec'd bots (see [`docs/bots.md`](docs/bots.md)) | 9.7.0 |
|
|
119
122
|
|
|
120
123
|
`agentirc.cli.dispatch(argv)` is the in-process integration surface — it is
|
|
121
124
|
what culture's `culture server` shim calls today. It returns `int` on
|
|
@@ -184,11 +187,31 @@ behavior) and
|
|
|
184
187
|
[`docs/api-stability.md#bot-extension-surface-shipped-in-950`](docs/api-stability.md#bot-extension-surface-shipped-in-950)
|
|
185
188
|
for the wire contract.
|
|
186
189
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
## Embedded bots (since 9.7.0)
|
|
191
|
+
|
|
192
|
+
Distinct from the out-of-process extension API above, `agentirc.bots` is an
|
|
193
|
+
**in-process** bot framework: deterministic, YAML-spec'd automations that run as
|
|
194
|
+
`VirtualClient` presences inside the IRCd (no separate process). A bot reacts to
|
|
195
|
+
an event filter or an HTTP webhook and replies with a Jinja2-templated message.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
agentirc bot create pinger --owner ori \
|
|
199
|
+
--trigger event \
|
|
200
|
+
--event-filter "type == 'user.message' and channel == '#general'" \
|
|
201
|
+
--channels '#general' --template 'pong {{event.nick}}'
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Bots live under `~/.culture/bots/<name>/bot.yaml` and load when the server
|
|
205
|
+
starts. See **[`docs/bots.md`](docs/bots.md)** for the authoring guide (CLI +
|
|
206
|
+
hand-written YAML, the two trigger types, the filter DSL, templates) and
|
|
207
|
+
[`docs/api-stability.md`](docs/api-stability.md#botconfig-yaml-schema) for
|
|
208
|
+
embedding a `BotManager` onto a running `IRCd`.
|
|
209
|
+
|
|
210
|
+
**Operational note.** Since 9.7.0, `IRCd.start()` binds the webhook listener
|
|
211
|
+
when `webhook_port` is set (>0), giving webhook-triggered bots HTTP ingress
|
|
212
|
+
under standalone `agentirc serve`; when `webhook_port` is unset/0 nothing is
|
|
213
|
+
bound (preserving the 9.5.0 default). The field stays in `ServerConfig` for
|
|
214
|
+
backward compatibility with culture's `~/.culture/server.yaml`.
|
|
192
215
|
|
|
193
216
|
## Current state and roadmap
|
|
194
217
|
|
|
@@ -25,6 +25,7 @@ import argparse
|
|
|
25
25
|
import sys
|
|
26
26
|
import time
|
|
27
27
|
|
|
28
|
+
from agentirc.bots.filter_dsl import FilterParseError, compile_filter
|
|
28
29
|
from agentirc.bots.config import (
|
|
29
30
|
BOT_CONFIG_FILE,
|
|
30
31
|
BOTS_DIR,
|
|
@@ -51,7 +52,19 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
51
52
|
bot_create.add_argument("--owner", required=True, help="Owner nick (e.g. spark-ori)")
|
|
52
53
|
bot_create.add_argument("--channels", nargs="+", default=[], help="Channels to join")
|
|
53
54
|
bot_create.add_argument(
|
|
54
|
-
"--trigger",
|
|
55
|
+
"--trigger",
|
|
56
|
+
default="webhook",
|
|
57
|
+
choices=["webhook", "event"],
|
|
58
|
+
help="Trigger type: 'webhook' (HTTP POST) or 'event' (matches an "
|
|
59
|
+
"event filter). 'event' requires --event-filter.",
|
|
60
|
+
)
|
|
61
|
+
bot_create.add_argument(
|
|
62
|
+
"--event-filter",
|
|
63
|
+
default=None,
|
|
64
|
+
help="Filter expression for an event-triggered bot, e.g. "
|
|
65
|
+
"\"type == 'user.message' and channel == '#general'\". "
|
|
66
|
+
"Matches against {type, channel, nick, data}. Required for "
|
|
67
|
+
"--trigger event.",
|
|
55
68
|
)
|
|
56
69
|
bot_create.add_argument("--mention", default=None, help="Agent to @mention on trigger")
|
|
57
70
|
bot_create.add_argument("--template", default=None, help="Message template")
|
|
@@ -141,6 +154,29 @@ def _bot_create(args: argparse.Namespace) -> int:
|
|
|
141
154
|
# name has no prefix yet — mimic culture's auto-prefix
|
|
142
155
|
name = f"{owner}-{name}"
|
|
143
156
|
|
|
157
|
+
# An event-triggered bot is meaningless without a filter; validate it
|
|
158
|
+
# compiles now so the user gets immediate feedback instead of a silent
|
|
159
|
+
# skip at load time.
|
|
160
|
+
event_filter = getattr(args, "event_filter", None)
|
|
161
|
+
if args.trigger == "event":
|
|
162
|
+
if not event_filter:
|
|
163
|
+
print(
|
|
164
|
+
"Error: --trigger event requires --event-filter",
|
|
165
|
+
file=sys.stderr,
|
|
166
|
+
)
|
|
167
|
+
return 1
|
|
168
|
+
try:
|
|
169
|
+
compile_filter(event_filter)
|
|
170
|
+
except (FilterParseError, TypeError) as exc:
|
|
171
|
+
print(f"Error: invalid --event-filter: {exc}", file=sys.stderr)
|
|
172
|
+
return 1
|
|
173
|
+
elif event_filter:
|
|
174
|
+
print(
|
|
175
|
+
"Error: --event-filter only applies to --trigger event",
|
|
176
|
+
file=sys.stderr,
|
|
177
|
+
)
|
|
178
|
+
return 1
|
|
179
|
+
|
|
144
180
|
bot_config = BotConfig(
|
|
145
181
|
name=name,
|
|
146
182
|
owner=args.owner,
|
|
@@ -152,6 +188,7 @@ def _bot_create(args: argparse.Namespace) -> int:
|
|
|
152
188
|
mention=args.mention,
|
|
153
189
|
template=args.template,
|
|
154
190
|
fallback="json",
|
|
191
|
+
event_filter=event_filter,
|
|
155
192
|
)
|
|
156
193
|
|
|
157
194
|
bot_dir = BOTS_DIR / name
|
|
@@ -163,6 +200,8 @@ def _bot_create(args: argparse.Namespace) -> int:
|
|
|
163
200
|
print(f"Bot '{name}' created at {bot_dir}")
|
|
164
201
|
print(f" Owner: {args.owner}")
|
|
165
202
|
print(f" Trigger: {args.trigger}")
|
|
203
|
+
if event_filter:
|
|
204
|
+
print(f" Filter: {event_filter}")
|
|
166
205
|
if args.channels:
|
|
167
206
|
print(f" Channels: {', '.join(args.channels)}")
|
|
168
207
|
if args.mention:
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Writing agentirc bots
|
|
2
|
+
|
|
3
|
+
agentirc bots are **deterministic, YAML-spec'd chatops automations** — think
|
|
4
|
+
ChanServ-class services, not LLM agents. Each bot runs as an in-process
|
|
5
|
+
`VirtualClient` presence inside a running IRCd: it has no separate process and
|
|
6
|
+
lives and dies with the server. A bot reacts to either an **event** (matched by
|
|
7
|
+
a filter expression) or a **webhook** (an inbound HTTP POST) and responds by
|
|
8
|
+
sending a templated message to its channels and/or emitting a custom event.
|
|
9
|
+
|
|
10
|
+
This guide is for **authoring** bots. For embedding the bot framework in your
|
|
11
|
+
own process (installing a `BotManager` onto an `IRCd`), see
|
|
12
|
+
[`api-stability.md` → Embedding bots](api-stability.md#botconfig-yaml-schema).
|
|
13
|
+
|
|
14
|
+
## Where bots live
|
|
15
|
+
|
|
16
|
+
Each bot is a directory under the bots dir with a single `bot.yaml`:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
~/.culture/bots/<bot-name>/bot.yaml
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The default bots dir is `~/.culture/bots/` (shared with culture for continuity).
|
|
23
|
+
`agentirc bot …` and the in-process `BotManager.load_bots()` both read from it;
|
|
24
|
+
non-archived bots are loaded and started when the server starts.
|
|
25
|
+
|
|
26
|
+
## The two trigger types
|
|
27
|
+
|
|
28
|
+
| Trigger | Fires when | Needs |
|
|
29
|
+
|---------|-----------|-------|
|
|
30
|
+
| `event` | an `Event` flowing through the IRCd matches the bot's filter | a `trigger.filter` expression |
|
|
31
|
+
| `webhook` | an HTTP POST arrives at the bot's webhook endpoint | the server's `webhook_port` set (>0) |
|
|
32
|
+
|
|
33
|
+
`event` bots are the common case (they react to chat/room activity). `webhook`
|
|
34
|
+
bots give external systems an HTTP ingress; the listener binds only when the
|
|
35
|
+
server is configured with a `webhook_port`.
|
|
36
|
+
|
|
37
|
+
## Quick start (CLI)
|
|
38
|
+
|
|
39
|
+
### An event-triggered bot
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
agentirc bot create pinger \
|
|
43
|
+
--owner ori \
|
|
44
|
+
--trigger event \
|
|
45
|
+
--event-filter "type == 'user.message' and channel == '#general'" \
|
|
46
|
+
--channels '#general' \
|
|
47
|
+
--template 'pong {{event.nick}}'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The filter is **compiled and validated at create time** — a malformed
|
|
51
|
+
expression is rejected immediately rather than silently skipped at load. The bot
|
|
52
|
+
is written to `~/.culture/bots/ori-pinger/bot.yaml` (the owner is prefixed to the
|
|
53
|
+
name when the name has no `-`).
|
|
54
|
+
|
|
55
|
+
### A webhook bot
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
agentirc bot create deployer \
|
|
59
|
+
--owner ori \
|
|
60
|
+
--trigger webhook \
|
|
61
|
+
--channels '#ops' \
|
|
62
|
+
--template 'deploy: {{payload.status}}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
POST JSON to `/<bot-name>` on the server's `webhook_port` to fire it.
|
|
66
|
+
|
|
67
|
+
### Activate, then manage
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
agentirc bot start ori-pinger # mark active (loads on next server start)
|
|
71
|
+
agentirc bot list # list bots (use --all to include archived)
|
|
72
|
+
agentirc bot inspect ori-pinger # show details
|
|
73
|
+
agentirc bot archive ori-pinger # disable without deleting
|
|
74
|
+
agentirc bot unarchive ori-pinger # re-enable
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Newly created bots load when the server (re)starts; `agentirc bot start` marks a
|
|
78
|
+
bot active for the next load.
|
|
79
|
+
|
|
80
|
+
## Hand-authoring `bot.yaml`
|
|
81
|
+
|
|
82
|
+
The CLI is a convenience over a plain YAML file you can write directly. The
|
|
83
|
+
layout mirrors the `BotConfig` dataclass:
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
bot:
|
|
87
|
+
name: ori-pinger
|
|
88
|
+
owner: ori
|
|
89
|
+
description: "Replies to messages in #general"
|
|
90
|
+
trigger:
|
|
91
|
+
type: event # "event" or "webhook"
|
|
92
|
+
filter: "type == 'user.message' and channel == '#general'"
|
|
93
|
+
output:
|
|
94
|
+
channels:
|
|
95
|
+
- "#general"
|
|
96
|
+
template: "pong {{ event.nick }}" # Jinja2
|
|
97
|
+
fallback: json # "json" or "text"
|
|
98
|
+
mention: null # nick to @-mention on fire, or null
|
|
99
|
+
dm_owner: false # also DM the owner on fire
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Field reference:
|
|
103
|
+
|
|
104
|
+
| Field | Meaning |
|
|
105
|
+
|-------|---------|
|
|
106
|
+
| `bot.name` / `bot.owner` / `bot.description` | metadata |
|
|
107
|
+
| `trigger.type` | `event` (filter) or `webhook` (HTTP POST) |
|
|
108
|
+
| `trigger.filter` | event-filter expression (event bots only) — see below |
|
|
109
|
+
| `output.channels` | channels the bot joins and addresses |
|
|
110
|
+
| `output.template` | Jinja2 template rendered with the bot context + event/payload |
|
|
111
|
+
| `output.fallback` | render fallback when the template can't render: `json` or `text` |
|
|
112
|
+
| `output.mention` | nick to `@`-mention when the bot fires, or `null` |
|
|
113
|
+
| `output.dm_owner` | also DM the owner when the bot fires |
|
|
114
|
+
| `archived` | set `true` to skip loading without deleting |
|
|
115
|
+
|
|
116
|
+
## The event-filter DSL
|
|
117
|
+
|
|
118
|
+
`trigger.filter` is a small, safe boolean expression — **no code execution**.
|
|
119
|
+
It evaluates against the event dict `{type, channel, nick, data}` (and nested
|
|
120
|
+
`data.*` via dotted paths). A missing field compares `False` to everything.
|
|
121
|
+
|
|
122
|
+
Grammar:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
expr := or_expr
|
|
126
|
+
or_expr := and_expr ('or' and_expr)*
|
|
127
|
+
and_expr := not_expr ('and' not_expr)*
|
|
128
|
+
not_expr := 'not' not_expr | cmp_expr
|
|
129
|
+
cmp_expr := atom (('==' | '!=' | 'in') atom)?
|
|
130
|
+
atom := STRING | NUMBER | LIST | IDENT('.'IDENT)* | '(' expr ')'
|
|
131
|
+
LIST := '[' [atom (',' atom)*] ']'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Operators: `==`, `!=`, `in`, `and`, `or`, `not`, parentheses, list literals.
|
|
135
|
+
String literals use **single quotes**.
|
|
136
|
+
|
|
137
|
+
Examples:
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
filter: "type == 'user.message'"
|
|
141
|
+
filter: "type == 'user.join' and channel == '#welcome'"
|
|
142
|
+
filter: "type == 'user.message' and nick in ['alice', 'bob']"
|
|
143
|
+
filter: "type == 'custom.ping' and data.target == 'pinger'"
|
|
144
|
+
filter: "not (channel == '#noisy')"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Templates
|
|
148
|
+
|
|
149
|
+
`output.template` is a Jinja2 template. Event bots get the event in context
|
|
150
|
+
(`event.type`, `event.channel`, `event.nick`, `event.data.*`); webhook bots get
|
|
151
|
+
the posted JSON as `payload`. If rendering fails, the bot falls back to
|
|
152
|
+
`output.fallback` (`json` dumps the context, `text` stringifies it).
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
template: "{{ event.nick }} said hi in {{ event.channel }}"
|
|
156
|
+
template: "deploy {{ payload.env }} -> {{ payload.status }}"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Validate and inspect
|
|
160
|
+
|
|
161
|
+
- `agentirc bot create … --trigger event --event-filter …` compiles the filter
|
|
162
|
+
up front and refuses a bad one.
|
|
163
|
+
- `agentirc bot inspect <name>` shows the parsed config.
|
|
164
|
+
- A bot with a filter that fails to compile at load time is logged and skipped
|
|
165
|
+
(it won't crash the server).
|
|
166
|
+
|
|
167
|
+
## See also
|
|
168
|
+
|
|
169
|
+
- [`api-stability.md`](api-stability.md#botconfig-yaml-schema) — the public
|
|
170
|
+
`agentirc.bots` API, the `BotConfig` schema, and a worked example of installing
|
|
171
|
+
a `BotManager` onto a running `IRCd` in-process.
|
|
172
|
+
- [`extension-api.md`](extension-api.md) — the IRCv3 bot capability and the
|
|
173
|
+
`EVENTSUB`/`EVENTPUB` streaming surface for **TCP-connected** bots (a different
|
|
174
|
+
thing from these in-process YAML bots).
|
|
@@ -270,3 +270,59 @@ def test_bot_inspect_rejects_path_traversal_names(bots_dir, capsys):
|
|
|
270
270
|
rc = _dispatch("bot", "inspect", "../../secret")
|
|
271
271
|
assert rc == 1
|
|
272
272
|
assert "Invalid bot name" in capsys.readouterr().err
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# ---------------------------------------------------------------------------
|
|
276
|
+
# Event-triggered bot creation (since 9.8.0)
|
|
277
|
+
# ---------------------------------------------------------------------------
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _read_yaml(bots_dir, bot_name):
|
|
281
|
+
import yaml
|
|
282
|
+
|
|
283
|
+
return yaml.safe_load(
|
|
284
|
+
(bots_dir / bot_name / "bot.yaml").read_text()
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def test_bot_create_event_writes_filter(bots_dir, capsys):
|
|
289
|
+
"""``--trigger event --event-filter ...`` writes an event bot spec."""
|
|
290
|
+
rc = _dispatch(
|
|
291
|
+
"bot", "create", "pinger", "--owner", "ori",
|
|
292
|
+
"--trigger", "event",
|
|
293
|
+
"--event-filter", "type == 'user.message' and channel == '#general'",
|
|
294
|
+
"--channels", "#general", "--template", "pong {{event.nick}}",
|
|
295
|
+
)
|
|
296
|
+
assert rc == 0
|
|
297
|
+
spec = _read_yaml(bots_dir, "ori-pinger")
|
|
298
|
+
assert spec["trigger"]["type"] == "event"
|
|
299
|
+
assert spec["trigger"]["filter"] == "type == 'user.message' and channel == '#general'"
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def test_bot_create_event_requires_filter(bots_dir, capsys):
|
|
303
|
+
"""``--trigger event`` without a filter is rejected."""
|
|
304
|
+
rc = _dispatch("bot", "create", "nofilter", "--owner", "ori", "--trigger", "event")
|
|
305
|
+
assert rc == 1
|
|
306
|
+
assert "requires --event-filter" in capsys.readouterr().err
|
|
307
|
+
assert list(bots_dir.iterdir()) == []
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def test_bot_create_event_rejects_bad_filter(bots_dir, capsys):
|
|
311
|
+
"""An --event-filter that doesn't compile is rejected at create time."""
|
|
312
|
+
rc = _dispatch(
|
|
313
|
+
"bot", "create", "badfilter", "--owner", "ori",
|
|
314
|
+
"--trigger", "event", "--event-filter", "type == =",
|
|
315
|
+
)
|
|
316
|
+
assert rc == 1
|
|
317
|
+
assert "invalid --event-filter" in capsys.readouterr().err
|
|
318
|
+
assert list(bots_dir.iterdir()) == []
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def test_bot_create_webhook_rejects_event_filter(bots_dir, capsys):
|
|
322
|
+
"""--event-filter only applies to event triggers."""
|
|
323
|
+
rc = _dispatch(
|
|
324
|
+
"bot", "create", "wh", "--owner", "ori",
|
|
325
|
+
"--trigger", "webhook", "--event-filter", "type == 'x.y'",
|
|
326
|
+
)
|
|
327
|
+
assert rc == 1
|
|
328
|
+
assert "only applies to --trigger event" in capsys.readouterr().err
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/scripts/fetch-issues.sh
RENAMED
|
File without changes
|
{agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/scripts/mesh-message.sh
RENAMED
|
File without changes
|
{agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/communicate/scripts/post-comment.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentirc_cli-9.7.0 → agentirc_cli-9.8.0}/docs/superpowers/specs/2026-04-30-bootstrap-design.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|