aion_integration_cli/lib.rs
1//! A second, independent [`AgentHarness`] integration for Aion — the empirical proof that
2//! `aion-integrations` is a real, neutral SDK, not a Norn wrapper (NOI-8, §9.1).
3//!
4//! `aion-integration-norn` is the FIRST adapter (a rich, bidirectional JSON-RPC harness). This
5//! crate is a SECOND adapter of a **deliberately different shape**, so two implementations of one
6//! trait exist across two crates — which is what makes the boundary an SDK rather than a one-off.
7//! Both fit the neutral seam WITHOUT any change to `aion-core`, `aion-integrations`, the wire, the
8//! server, or the worker: if a second working integration required touching those, the contract
9//! would be "Norn-with-a-flag," not neutral.
10//!
11//! # The two shapes in this crate
12//!
13//! - [`CliHarness`] — the **observability-only** case (case (b) in the design). A plain-stdout CLI
14//! agent with **no control channel at all**: [`CliHarness::start`] spawns a line-oriented process
15//! and hands its stdout to a [`CliSession`] whose pump **demuxes interleaved stdout into neutral
16//! [`ActivityEvent`]s** ([`demux`], mostly [`aion_core::ActivityEventKind::Raw`], some mapped). It
17//! advertises an **empty [`InterventionCapabilities`] set**, so [`CliSession::intervene`] rejects
18//! every command and the server offers no controls for it. This is a first-class tier — an empty
19//! capability advertisement is valid, not degenerate.
20//! - [`MockAgentHarness`] — the **interveneable** case. A deterministic in-crate harness that
21//! advertises `{inject_message, cancel}`, ACCEPTS those, and cleanly REJECTS the three primitives
22//! it does not advertise (notably `respond_to_approval`) with a capability-not-supported NACK. It
23//! exercises the OTHER branch of the [`AgentSession::intervene`] contract, and it is a genuine
24//! harness the worker driver runs live (not a stub) so the full worker apply path — control
25//! channel → [`AgentSession::intervene`] → accept/gate → ack — is exercised end-to-end.
26//!
27//! # Harness neutrality (the whole point)
28//!
29//! Neither shape depends on Norn or on any wire protocol beyond the neutral seam. Both speak only
30//! [`AgentRunSpec`] in, neutral [`ActivityEvent`]s out, neutral [`InterventionCommand`]s in (gated
31//! by the neutral [`InterventionCapabilities`]), and a neutral terminal [`Payload`]. There is **no
32//! Norn here** — this crate exists precisely to prove that.
33//!
34//! [`AgentHarness`]: aion_integrations::AgentHarness
35//! [`AgentSession`]: aion_integrations::AgentSession
36//! [`CliHarness::start`]: aion_integrations::AgentHarness::start
37//! [`CliSession::intervene`]: aion_integrations::AgentSession::intervene
38//! [`AgentSession::intervene`]: aion_integrations::AgentSession::intervene
39//! [`ActivityEvent`]: aion_core::ActivityEvent
40//! [`InterventionCommand`]: aion_core::InterventionCommand
41//! [`InterventionCapabilities`]: aion_core::InterventionCapabilities
42//! [`AgentRunSpec`]: aion_integrations::AgentRunSpec
43//! [`Payload`]: aion_core::Payload
44
45/// The pure stdout demux — plain CLI stdout lines → neutral [`aion_core::ActivityEvent`]s.
46pub mod demux;
47/// The observability-only [`aion_integrations::AgentHarness`] over a plain-stdout CLI agent.
48pub mod harness;
49/// The interveneable mock harness advertising `{inject_message, cancel}`.
50pub mod mock;
51/// The live observability-only session implementing [`aion_integrations::AgentSession`].
52pub mod session;
53
54pub use harness::CliHarness;
55pub use mock::{MockAgentHarness, MockAgentSession};
56pub use session::CliSession;