use std::path::PathBuf;
use serde::{Deserialize, Serialize};
pub const RESERVED_GROUP_ALL: &str = "ALL";
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SessionType {
Tmux,
Acp,
Ui,
Pubsub,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct BundleMember {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub working_directory: Option<PathBuf>,
pub target: TargetConfiguration,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub coder_session_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub policy_id: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct PromptReadinessTemplate {
pub prompt_regex: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub inspect_lines: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub input_idle_cursor_column: Option<usize>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case", tag = "transport", content = "config")]
pub enum TargetConfiguration {
Tmux(TmuxTargetConfiguration),
Acp(AcpTargetConfiguration),
Ui,
Pubsub,
}
impl TargetConfiguration {
#[must_use]
pub fn session_type(&self) -> SessionType {
match self {
Self::Tmux(_) => SessionType::Tmux,
Self::Acp(_) => SessionType::Acp,
Self::Ui => SessionType::Ui,
Self::Pubsub => SessionType::Pubsub,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct TmuxTargetConfiguration {
pub start_command: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub prompt_readiness: Option<PromptReadinessTemplate>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct AcpTargetConfiguration {
pub channel: AcpChannel,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub command: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub turn_timeout_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub headers: Vec<NameValueEntry>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub environment: Vec<NameValueEntry>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct BundleConfiguration {
pub schema_version: String,
pub bundle_name: String,
pub autostart: bool,
pub groups: Vec<String>,
pub members: Vec<BundleMember>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BundleGroupMembership {
pub bundle_name: String,
pub autostart: bool,
pub groups: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct TuiSession {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
pub policy: String,
pub session_type: SessionType,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct TuiConfiguration {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default_bundle: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default_session: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub sessions: Vec<TuiSession>,
}
impl TuiConfiguration {
#[must_use]
pub fn session_by_id(&self, selector: &str) -> Option<&TuiSession> {
self.sessions.iter().find(|session| session.id == selector)
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
pub struct NameValueEntry {
pub name: String,
pub value: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum AcpChannel {
Stdio,
Http,
}