use super::*;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Capabilities {
pub spawn: bool,
pub attach: bool,
pub probe: bool,
pub close: bool,
pub focus: bool,
pub rename: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SpawnSpec {
pub cwd: PathBuf,
pub task_id: String,
pub command: Vec<String>,
#[serde(default)]
pub env: BTreeMap<String, String>,
#[serde(default)]
pub tools_token: String,
#[serde(default)]
pub prose: String,
#[serde(default)]
pub focus: Option<bool>,
#[serde(default)]
pub placement: Option<PanePlacement>,
#[serde(default)]
pub rename: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SplitDirection {
Right,
Down,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct PanePlacement {
pub direction: SplitDirection,
pub ratio: f64,
}
impl PanePlacement {
pub fn from_pane_count(pane_count: usize) -> Self {
let direction = if (pane_count + 1).is_power_of_two() {
SplitDirection::Right
} else {
SplitDirection::Down
};
Self {
direction,
ratio: 0.5,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SessionPlacement {
Named(onlyne_config::Placement),
Fake,
}
impl SessionPlacement {
pub fn parse(name: &str) -> Option<Self> {
let trimmed = name.trim();
if trimmed.eq_ignore_ascii_case("fake") {
return Some(Self::Fake);
}
if trimmed.eq_ignore_ascii_case("exec") {
return Some(Self::Named(onlyne_config::Placement::Headless));
}
onlyne_config::Placement::parse(trimmed).map(Self::Named)
}
pub fn as_str(self) -> &'static str {
match self {
Self::Named(placement) => placement.as_str(),
Self::Fake => "fake",
}
}
pub fn named(self) -> Option<onlyne_config::Placement> {
match self {
Self::Named(placement) => Some(placement),
Self::Fake => None,
}
}
}
impl std::fmt::Display for SessionPlacement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
pub fn unknown_placement(name: &str) -> String {
format!(
"onlyne: `{name}` is not a placement; accepted: {} \
(absent probes {}, then headless; ONLYNE_BACKEND wins over the workspace's `placement` key)",
onlyne_config::PLACEMENT_NAMES,
onlyne_config::PLACEMENT_PROBE_ORDER
.map(|placement| placement.as_str())
.join(", ")
)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownPlacement(pub String);
impl std::fmt::Display for UnknownPlacement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&unknown_placement(&self.0))
}
}
impl std::error::Error for UnknownPlacement {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SelectionSource {
Explicit,
Declared,
Probe,
Fallback,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PlacementDetection {
pub placement: SessionPlacement,
pub source: SelectionSource,
pub explicit: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SessionRef {
pub task_id: String,
pub backend: String,
pub backend_ref: Value,
pub generation: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ResourceProbe {
pub alive: bool,
pub attached: bool,
pub detail: Option<Value>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CloseReason {
Completed,
Cancelled,
Fault,
Shutdown,
Replaced,
Operator,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SessionOutcome {
pub task_id: String,
pub outcome: Option<TaskState>,
pub head: Option<String>,
pub note: Option<String>,
pub refusals: Option<String>,
}