Pivot orchestration : agents IA pilotés via leur mode programmatique/JSON
(capture déterministe), au lieu du TUI brut + self-report. §16 (idea/MCP)
marquée remplacée comme voie principale.
- D0 (domaine) : port AgentSession + AgentSessionFactory, types ReplyEvent
/ReplyStream/AgentSessionError, champ AgentProfile.structured_adapter
(Option<StructuredAdapter{Claude,Codex}>, skip si None ⇒ zéro régression),
catalogue Claude/Codex annotés.
- D1 (application) : registre StructuredSessions (jumeau de TerminalSessions),
agrégateur LiveSessions{pty,structured} derrière LiveAgentRegistry (vivant si
PTY OU structuré, surface du trait inchangée), helper send_blocking (draine le
ReplyStream jusqu'au Final, Timeout sans tuer la session).
Tests : domaine 16+2 ; application registre 11 + send_blocking 9 ; workspace 0 échec.
A/B intacts. Aucun adapter concret (D2), pas de Tauri/front.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
100 lines
3.9 KiB
Rust
100 lines
3.9 KiB
Rust
//! Reference profile **catalogue** — the pre-filled, *editable* profiles offered
|
|
//! by the first-run wizard (CONTEXT §9, ARCHITECTURE §6 `ConfigureProfiles`).
|
|
//!
|
|
//! These are **data, not domain code**: the catalogue lives in the application
|
|
//! layer (a product decision about *which* AIs to suggest), built from the
|
|
//! domain's validating constructors. Nothing is imposed — the user picks, edits
|
|
//! the pre-filled commands, and may add custom profiles. The single
|
|
//! [`domain::ports::AgentRuntime`] adapter consumes whatever profiles result.
|
|
//!
|
|
//! Reference set (CONTEXT §9):
|
|
//! - **Claude Code** — `claude`, context via `CLAUDE.md` (convention file),
|
|
//! - **OpenAI Codex CLI** — `codex`, context via `AGENTS.md`,
|
|
//! - **Gemini CLI** — `gemini`, context via `GEMINI.md`,
|
|
//! - **Aider** — `aider`, context passed as an argument (`--message-file {path}`).
|
|
//!
|
|
//! The ids are **stable, deterministic UUIDs** (derived from a fixed namespace)
|
|
//! so re-deriving the catalogue yields the same id for "claude" every time,
|
|
//! making the reference profiles addressable across runs without a registry.
|
|
|
|
use domain::ids::ProfileId;
|
|
use domain::profile::{AgentProfile, ContextInjection, StructuredAdapter};
|
|
|
|
/// A fixed UUID namespace used to derive stable ids for reference profiles.
|
|
/// (Random-looking but constant; only its stability matters.)
|
|
const REFERENCE_NAMESPACE: uuid::Uuid = uuid::uuid!("6f9b1d2a-7c34-4e58-9a1b-2c3d4e5f6a7b");
|
|
|
|
/// Derives a stable [`ProfileId`] for a reference profile from its slug.
|
|
#[must_use]
|
|
fn reference_id(slug: &str) -> ProfileId {
|
|
ProfileId::from_uuid(uuid::Uuid::new_v5(&REFERENCE_NAMESPACE, slug.as_bytes()))
|
|
}
|
|
|
|
/// Returns the stable id a reference profile slug maps to (exposed for tests and
|
|
/// callers that need to address a reference profile).
|
|
#[must_use]
|
|
pub fn reference_profile_id(slug: &str) -> ProfileId {
|
|
reference_id(slug)
|
|
}
|
|
|
|
/// Builds the pre-filled, editable reference profiles (CONTEXT §9).
|
|
///
|
|
/// # Panics
|
|
/// Never in practice: every literal here satisfies the domain invariants, so the
|
|
/// constructors cannot fail; the `expect`s document that.
|
|
#[must_use]
|
|
pub fn reference_profiles() -> Vec<AgentProfile> {
|
|
vec![
|
|
AgentProfile::new(
|
|
reference_id("claude"),
|
|
"Claude Code",
|
|
"claude",
|
|
Vec::new(),
|
|
ContextInjection::convention_file("CLAUDE.md")
|
|
.expect("CLAUDE.md is a valid convention target"),
|
|
Some("claude --version".to_owned()),
|
|
"{agentRunDir}",
|
|
None,
|
|
)
|
|
.expect("claude reference profile is valid")
|
|
.with_structured_adapter(StructuredAdapter::Claude),
|
|
AgentProfile::new(
|
|
reference_id("codex"),
|
|
"OpenAI Codex CLI",
|
|
"codex",
|
|
Vec::new(),
|
|
ContextInjection::convention_file("AGENTS.md")
|
|
.expect("AGENTS.md is a valid convention target"),
|
|
Some("codex --version".to_owned()),
|
|
"{agentRunDir}",
|
|
None,
|
|
)
|
|
.expect("codex reference profile is valid")
|
|
.with_structured_adapter(StructuredAdapter::Codex),
|
|
AgentProfile::new(
|
|
reference_id("gemini"),
|
|
"Gemini CLI",
|
|
"gemini",
|
|
Vec::new(),
|
|
ContextInjection::convention_file("GEMINI.md")
|
|
.expect("GEMINI.md is a valid convention target"),
|
|
Some("gemini --version".to_owned()),
|
|
"{agentRunDir}",
|
|
None,
|
|
)
|
|
.expect("gemini reference profile is valid"),
|
|
AgentProfile::new(
|
|
reference_id("aider"),
|
|
"Aider",
|
|
"aider",
|
|
Vec::new(),
|
|
ContextInjection::flag("--message-file {path}")
|
|
.expect("aider flag template is non-empty"),
|
|
Some("aider --version".to_owned()),
|
|
"{agentRunDir}",
|
|
None,
|
|
)
|
|
.expect("aider reference profile is valid"),
|
|
]
|
|
}
|